Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc:
[POWERPC] Bolt in SLB entry for kernel stack on secondary cpus
[POWERPC] PS3: Update ps3_defconfig
[POWERPC] PS3: Remove unsupported wakeup sources
[POWERPC] PS3: Make ps3_virq_setup and ps3_virq_destroy static
[POWERPC] PS3: Add time include to lpm
[POWERPC] Fix slb.c compile warnings
[POWERPC] Xilinx: Fix compile warnings
[POWERPC] Squash build warning for print of resource_size_t in fsl_soc.c
[RAPIDIO] fix current kernel-doc notation
[POWERPC] 86xx: mpc8610_hpcd: add support for PCI Express x8 slot
Fix a potential issue in mpc52xx uart driver
[POWERPC] mpc5200: Allow for fixed speed MII configurations
[POWERPC] 86xx: Fix the wrong serial1 interrupt for 8610 board
diff --git a/.gitignore b/.gitignore
index 3016ed3..090b293 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,6 +41,7 @@
include/linux/compile.h
include/linux/version.h
include/linux/utsrelease.h
+include/linux/bounds.h
# stgit generated dirs
patches-*
diff --git a/.mailmap b/.mailmap
index ebf9bf8..7260842 100644
--- a/.mailmap
+++ b/.mailmap
@@ -88,6 +88,7 @@
Rui Saraiva <rmps@joel.ist.utl.pt>
Sachin P Sant <ssant@in.ibm.com>
Sam Ravnborg <sam@mars.ravnborg.org>
+S.Çağlar Onur <caglar@pardus.org.tr>
Simon Kelley <simon@thekelleys.org.uk>
Stéphane Witzmann <stephane.witzmann@ubpmes.univ-bpclermont.fr>
Stephen Hemminger <shemminger@osdl.org>
diff --git a/Documentation/ABI/testing/sysfs-class-bdi b/Documentation/ABI/testing/sysfs-class-bdi
new file mode 100644
index 0000000..5ac1e01
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-class-bdi
@@ -0,0 +1,46 @@
+What: /sys/class/bdi/<bdi>/
+Date: January 2008
+Contact: Peter Zijlstra <a.p.zijlstra@chello.nl>
+Description:
+
+Provide a place in sysfs for the backing_dev_info object. This allows
+setting and retrieving various BDI specific variables.
+
+The <bdi> identifier can be either of the following:
+
+MAJOR:MINOR
+
+ Device number for block devices, or value of st_dev on
+ non-block filesystems which provide their own BDI, such as NFS
+ and FUSE.
+
+default
+
+ The default backing dev, used for non-block device backed
+ filesystems which do not provide their own BDI.
+
+Files under /sys/class/bdi/<bdi>/
+---------------------------------
+
+read_ahead_kb (read-write)
+
+ Size of the read-ahead window in kilobytes
+
+min_ratio (read-write)
+
+ Under normal circumstances each device is given a part of the
+ total write-back cache that relates to its current average
+ writeout speed in relation to the other devices.
+
+ The 'min_ratio' parameter allows assigning a minimum
+ percentage of the write-back cache to a particular device.
+ For example, this is useful for providing a minimum QoS.
+
+max_ratio (read-write)
+
+ Allows limiting a particular device to use not more than the
+ given percentage of the write-back cache. This is useful in
+ situations where we want to avoid one device taking all or
+ most of the write-back cache. For example in case of an NFS
+ mount that is prone to get stuck, or a FUSE mount which cannot
+ be trusted to play fair.
diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt
index b939ebb..80d1504 100644
--- a/Documentation/DMA-API.txt
+++ b/Documentation/DMA-API.txt
@@ -145,7 +145,7 @@
int
dma_supported(struct device *dev, u64 mask)
int
-pci_dma_supported(struct device *dev, u64 mask)
+pci_dma_supported(struct pci_dev *hwdev, u64 mask)
Checks to see if the device can support DMA to the memory described by
mask.
@@ -189,7 +189,7 @@
dma_map_single(struct device *dev, void *cpu_addr, size_t size,
enum dma_data_direction direction)
dma_addr_t
-pci_map_single(struct device *dev, void *cpu_addr, size_t size,
+pci_map_single(struct pci_dev *hwdev, void *cpu_addr, size_t size,
int direction)
Maps a piece of processor virtual memory so it can be accessed by the
@@ -395,6 +395,71 @@
See also dma_map_single().
+dma_addr_t
+dma_map_single_attrs(struct device *dev, void *cpu_addr, size_t size,
+ enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+
+void
+dma_unmap_single_attrs(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+
+int
+dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+
+void
+dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl,
+ int nents, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+
+The four functions above are just like the counterpart functions
+without the _attrs suffixes, except that they pass an optional
+struct dma_attrs*.
+
+struct dma_attrs encapsulates a set of "dma attributes". For the
+definition of struct dma_attrs see linux/dma-attrs.h.
+
+The interpretation of dma attributes is architecture-specific, and
+each attribute should be documented in Documentation/DMA-attributes.txt.
+
+If struct dma_attrs* is NULL, the semantics of each of these
+functions is identical to those of the corresponding function
+without the _attrs suffix. As a result dma_map_single_attrs()
+can generally replace dma_map_single(), etc.
+
+As an example of the use of the *_attrs functions, here's how
+you could pass an attribute DMA_ATTR_FOO when mapping memory
+for DMA:
+
+#include <linux/dma-attrs.h>
+/* DMA_ATTR_FOO should be defined in linux/dma-attrs.h and
+ * documented in Documentation/DMA-attributes.txt */
+...
+
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_FOO, &attrs);
+ ....
+ n = dma_map_sg_attrs(dev, sg, nents, DMA_TO_DEVICE, &attr);
+ ....
+
+Architectures that care about DMA_ATTR_FOO would check for its
+presence in their implementations of the mapping and unmapping
+routines, e.g.:
+
+void whizco_dma_map_sg_attrs(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction dir,
+ struct dma_attrs *attrs)
+{
+ ....
+ int foo = dma_get_attr(DMA_ATTR_FOO, attrs);
+ ....
+ if (foo)
+ /* twizzle the frobnozzle */
+ ....
+
Part II - Advanced dma_ usage
-----------------------------
diff --git a/Documentation/DMA-attributes.txt b/Documentation/DMA-attributes.txt
new file mode 100644
index 0000000..6d772f8
--- /dev/null
+++ b/Documentation/DMA-attributes.txt
@@ -0,0 +1,24 @@
+ DMA attributes
+ ==============
+
+This document describes the semantics of the DMA attributes that are
+defined in linux/dma-attrs.h.
+
+DMA_ATTR_WRITE_BARRIER
+----------------------
+
+DMA_ATTR_WRITE_BARRIER is a (write) barrier attribute for DMA. DMA
+to a memory region with the DMA_ATTR_WRITE_BARRIER attribute forces
+all pending DMA writes to complete, and thus provides a mechanism to
+strictly order DMA from a device across all intervening busses and
+bridges. This barrier is not specific to a particular type of
+interconnect, it applies to the system as a whole, and so its
+implementation must account for the idiosyncracies of the system all
+the way from the DMA device to memory.
+
+As an example of a situation where DMA_ATTR_WRITE_BARRIER would be
+useful, suppose that a device does a DMA write to indicate that data is
+ready and available in memory. The DMA of the "completion indication"
+could race with data DMA. Mapping the memory used for completion
+indications with DMA_ATTR_WRITE_BARRIER would prevent the race.
+
diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
index d84f89d..b463ecd 100644
--- a/Documentation/DMA-mapping.txt
+++ b/Documentation/DMA-mapping.txt
@@ -315,11 +315,11 @@
dma_addr_t dma_handle;
- cpu_addr = pci_alloc_consistent(dev, size, &dma_handle);
+ cpu_addr = pci_alloc_consistent(pdev, size, &dma_handle);
-where dev is a struct pci_dev *. You should pass NULL for PCI like buses
-where devices don't have struct pci_dev (like ISA, EISA). This may be
-called in interrupt context.
+where pdev is a struct pci_dev *. This may be called in interrupt context.
+You should use dma_alloc_coherent (see DMA-API.txt) for buses
+where devices don't have struct pci_dev (like ISA, EISA).
This argument is needed because the DMA translations may be bus
specific (and often is private to the bus which the device is attached
@@ -332,7 +332,7 @@
driver needs regions sized smaller than a page, you may prefer using
the pci_pool interface, described below.
-The consistent DMA mapping interfaces, for non-NULL dev, will by
+The consistent DMA mapping interfaces, for non-NULL pdev, will by
default return a DMA address which is SAC (Single Address Cycle)
addressable. Even if the device indicates (via PCI dma mask) that it
may address the upper 32-bits and thus perform DAC cycles, consistent
@@ -354,9 +354,9 @@
To unmap and free such a DMA region, you call:
- pci_free_consistent(dev, size, cpu_addr, dma_handle);
+ pci_free_consistent(pdev, size, cpu_addr, dma_handle);
-where dev, size are the same as in the above call and cpu_addr and
+where pdev, size are the same as in the above call and cpu_addr and
dma_handle are the values pci_alloc_consistent returned to you.
This function may not be called in interrupt context.
@@ -371,9 +371,9 @@
struct pci_pool *pool;
- pool = pci_pool_create(name, dev, size, align, alloc);
+ pool = pci_pool_create(name, pdev, size, align, alloc);
-The "name" is for diagnostics (like a kmem_cache name); dev and size
+The "name" is for diagnostics (like a kmem_cache name); pdev and size
are as above. The device's hardware alignment requirement for this
type of data is "align" (which is expressed in bytes, and must be a
power of two). If your device has no boundary crossing restrictions,
@@ -472,11 +472,11 @@
void *addr = buffer->ptr;
size_t size = buffer->len;
- dma_handle = pci_map_single(dev, addr, size, direction);
+ dma_handle = pci_map_single(pdev, addr, size, direction);
and to unmap it:
- pci_unmap_single(dev, dma_handle, size, direction);
+ pci_unmap_single(pdev, dma_handle, size, direction);
You should call pci_unmap_single when the DMA activity is finished, e.g.
from the interrupt which told you that the DMA transfer is done.
@@ -493,17 +493,17 @@
unsigned long offset = buffer->offset;
size_t size = buffer->len;
- dma_handle = pci_map_page(dev, page, offset, size, direction);
+ dma_handle = pci_map_page(pdev, page, offset, size, direction);
...
- pci_unmap_page(dev, dma_handle, size, direction);
+ pci_unmap_page(pdev, dma_handle, size, direction);
Here, "offset" means byte offset within the given page.
With scatterlists, you map a region gathered from several regions by:
- int i, count = pci_map_sg(dev, sglist, nents, direction);
+ int i, count = pci_map_sg(pdev, sglist, nents, direction);
struct scatterlist *sg;
for_each_sg(sglist, sg, count, i) {
@@ -527,7 +527,7 @@
To unmap a scatterlist, just call:
- pci_unmap_sg(dev, sglist, nents, direction);
+ pci_unmap_sg(pdev, sglist, nents, direction);
Again, make sure DMA activity has already finished.
@@ -550,11 +550,11 @@
So, firstly, just map it with pci_map_{single,sg}, and after each DMA
transfer call either:
- pci_dma_sync_single_for_cpu(dev, dma_handle, size, direction);
+ pci_dma_sync_single_for_cpu(pdev, dma_handle, size, direction);
or:
- pci_dma_sync_sg_for_cpu(dev, sglist, nents, direction);
+ pci_dma_sync_sg_for_cpu(pdev, sglist, nents, direction);
as appropriate.
@@ -562,7 +562,7 @@
finish accessing the data with the cpu, and then before actually
giving the buffer to the hardware call either:
- pci_dma_sync_single_for_device(dev, dma_handle, size, direction);
+ pci_dma_sync_single_for_device(pdev, dma_handle, size, direction);
or:
@@ -739,7 +739,7 @@
dma_addr_t dma_handle;
- dma_handle = pci_map_single(dev, addr, size, direction);
+ dma_handle = pci_map_single(pdev, addr, size, direction);
if (pci_dma_mapping_error(dma_handle)) {
/*
* reduce current DMA mapping usage,
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 83966e9..0eb0d02 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -12,7 +12,7 @@
kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
gadget.xml libata.xml mtdnand.xml librs.xml rapidio.xml \
genericirq.xml s390-drivers.xml uio-howto.xml scsi.xml \
- mac80211.xml
+ mac80211.xml debugobjects.xml
###
# The build process is as follows (targets):
diff --git a/Documentation/DocBook/debugobjects.tmpl b/Documentation/DocBook/debugobjects.tmpl
new file mode 100644
index 0000000..7f5f218
--- /dev/null
+++ b/Documentation/DocBook/debugobjects.tmpl
@@ -0,0 +1,391 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="debug-objects-guide">
+ <bookinfo>
+ <title>Debug objects life time</title>
+
+ <authorgroup>
+ <author>
+ <firstname>Thomas</firstname>
+ <surname>Gleixner</surname>
+ <affiliation>
+ <address>
+ <email>tglx@linutronix.de</email>
+ </address>
+ </affiliation>
+ </author>
+ </authorgroup>
+
+ <copyright>
+ <year>2008</year>
+ <holder>Thomas Gleixner</holder>
+ </copyright>
+
+ <legalnotice>
+ <para>
+ This documentation 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.
+ </para>
+
+ <para>
+ 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.
+ </para>
+
+ <para>
+ 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
+ </para>
+
+ <para>
+ For more details see the file COPYING in the source
+ distribution of Linux.
+ </para>
+ </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+ <chapter id="intro">
+ <title>Introduction</title>
+ <para>
+ debugobjects is a generic infrastructure to track the life time
+ of kernel objects and validate the operations on those.
+ </para>
+ <para>
+ debugobjects is useful to check for the following error patterns:
+ <itemizedlist>
+ <listitem><para>Activation of uninitialized objects</para></listitem>
+ <listitem><para>Initialization of active objects</para></listitem>
+ <listitem><para>Usage of freed/destroyed objects</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ debugobjects is not changing the data structure of the real
+ object so it can be compiled in with a minimal runtime impact
+ and enabled on demand with a kernel command line option.
+ </para>
+ </chapter>
+
+ <chapter id="howto">
+ <title>Howto use debugobjects</title>
+ <para>
+ A kernel subsystem needs to provide a data structure which
+ describes the object type and add calls into the debug code at
+ appropriate places. The data structure to describe the object
+ type needs at minimum the name of the object type. Optional
+ functions can and should be provided to fixup detected problems
+ so the kernel can continue to work and the debug information can
+ be retrieved from a live system instead of hard core debugging
+ with serial consoles and stack trace transcripts from the
+ monitor.
+ </para>
+ <para>
+ The debug calls provided by debugobjects are:
+ <itemizedlist>
+ <listitem><para>debug_object_init</para></listitem>
+ <listitem><para>debug_object_init_on_stack</para></listitem>
+ <listitem><para>debug_object_activate</para></listitem>
+ <listitem><para>debug_object_deactivate</para></listitem>
+ <listitem><para>debug_object_destroy</para></listitem>
+ <listitem><para>debug_object_free</para></listitem>
+ </itemizedlist>
+ Each of these functions takes the address of the real object and
+ a pointer to the object type specific debug description
+ structure.
+ </para>
+ <para>
+ Each detected error is reported in the statistics and a limited
+ number of errors are printk'ed including a full stack trace.
+ </para>
+ <para>
+ The statistics are available via debugfs/debug_objects/stats.
+ They provide information about the number of warnings and the
+ number of successful fixups along with information about the
+ usage of the internal tracking objects and the state of the
+ internal tracking objects pool.
+ </para>
+ </chapter>
+ <chapter id="debugfunctions">
+ <title>Debug functions</title>
+ <sect1 id="prototypes">
+ <title>Debug object function reference</title>
+!Elib/debugobjects.c
+ </sect1>
+ <sect1 id="debug_object_init">
+ <title>debug_object_init</title>
+ <para>
+ This function is called whenever the initialization function
+ of a real object is called.
+ </para>
+ <para>
+ When the real object is already tracked by debugobjects it is
+ checked, whether the object can be initialized. Initializing
+ is not allowed for active and destroyed objects. When
+ debugobjects detects an error, then it calls the fixup_init
+ function of the object type description structure if provided
+ by the caller. The fixup function can correct the problem
+ before the real initialization of the object happens. E.g. it
+ can deactivate an active object in order to prevent damage to
+ the subsystem.
+ </para>
+ <para>
+ When the real object is not yet tracked by debugobjects,
+ debugobjects allocates a tracker object for the real object
+ and sets the tracker object state to ODEBUG_STATE_INIT. It
+ verifies that the object is not on the callers stack. If it is
+ on the callers stack then a limited number of warnings
+ including a full stack trace is printk'ed. The calling code
+ must use debug_object_init_on_stack() and remove the object
+ before leaving the function which allocated it. See next
+ section.
+ </para>
+ </sect1>
+
+ <sect1 id="debug_object_init_on_stack">
+ <title>debug_object_init_on_stack</title>
+ <para>
+ This function is called whenever the initialization function
+ of a real object which resides on the stack is called.
+ </para>
+ <para>
+ When the real object is already tracked by debugobjects it is
+ checked, whether the object can be initialized. Initializing
+ is not allowed for active and destroyed objects. When
+ debugobjects detects an error, then it calls the fixup_init
+ function of the object type description structure if provided
+ by the caller. The fixup function can correct the problem
+ before the real initialization of the object happens. E.g. it
+ can deactivate an active object in order to prevent damage to
+ the subsystem.
+ </para>
+ <para>
+ When the real object is not yet tracked by debugobjects
+ debugobjects allocates a tracker object for the real object
+ and sets the tracker object state to ODEBUG_STATE_INIT. It
+ verifies that the object is on the callers stack.
+ </para>
+ <para>
+ An object which is on the stack must be removed from the
+ tracker by calling debug_object_free() before the function
+ which allocates the object returns. Otherwise we keep track of
+ stale objects.
+ </para>
+ </sect1>
+
+ <sect1 id="debug_object_activate">
+ <title>debug_object_activate</title>
+ <para>
+ This function is called whenever the activation function of a
+ real object is called.
+ </para>
+ <para>
+ When the real object is already tracked by debugobjects it is
+ checked, whether the object can be activated. Activating is
+ not allowed for active and destroyed objects. When
+ debugobjects detects an error, then it calls the
+ fixup_activate function of the object type description
+ structure if provided by the caller. The fixup function can
+ correct the problem before the real activation of the object
+ happens. E.g. it can deactivate an active object in order to
+ prevent damage to the subsystem.
+ </para>
+ <para>
+ When the real object is not yet tracked by debugobjects then
+ the fixup_activate function is called if available. This is
+ necessary to allow the legitimate activation of statically
+ allocated and initialized objects. The fixup function checks
+ whether the object is valid and calls the debug_objects_init()
+ function to initialize the tracking of this object.
+ </para>
+ <para>
+ When the activation is legitimate, then the state of the
+ associated tracker object is set to ODEBUG_STATE_ACTIVE.
+ </para>
+ </sect1>
+
+ <sect1 id="debug_object_deactivate">
+ <title>debug_object_deactivate</title>
+ <para>
+ This function is called whenever the deactivation function of
+ a real object is called.
+ </para>
+ <para>
+ When the real object is tracked by debugobjects it is checked,
+ whether the object can be deactivated. Deactivating is not
+ allowed for untracked or destroyed objects.
+ </para>
+ <para>
+ When the deactivation is legitimate, then the state of the
+ associated tracker object is set to ODEBUG_STATE_INACTIVE.
+ </para>
+ </sect1>
+
+ <sect1 id="debug_object_destroy">
+ <title>debug_object_destroy</title>
+ <para>
+ This function is called to mark an object destroyed. This is
+ useful to prevent the usage of invalid objects, which are
+ still available in memory: either statically allocated objects
+ or objects which are freed later.
+ </para>
+ <para>
+ When the real object is tracked by debugobjects it is checked,
+ whether the object can be destroyed. Destruction is not
+ allowed for active and destroyed objects. When debugobjects
+ detects an error, then it calls the fixup_destroy function of
+ the object type description structure if provided by the
+ caller. The fixup function can correct the problem before the
+ real destruction of the object happens. E.g. it can deactivate
+ an active object in order to prevent damage to the subsystem.
+ </para>
+ <para>
+ When the destruction is legitimate, then the state of the
+ associated tracker object is set to ODEBUG_STATE_DESTROYED.
+ </para>
+ </sect1>
+
+ <sect1 id="debug_object_free">
+ <title>debug_object_free</title>
+ <para>
+ This function is called before an object is freed.
+ </para>
+ <para>
+ When the real object is tracked by debugobjects it is checked,
+ whether the object can be freed. Free is not allowed for
+ active objects. When debugobjects detects an error, then it
+ calls the fixup_free function of the object type description
+ structure if provided by the caller. The fixup function can
+ correct the problem before the real free of the object
+ happens. E.g. it can deactivate an active object in order to
+ prevent damage to the subsystem.
+ </para>
+ <para>
+ Note that debug_object_free removes the object from the
+ tracker. Later usage of the object is detected by the other
+ debug checks.
+ </para>
+ </sect1>
+ </chapter>
+ <chapter id="fixupfunctions">
+ <title>Fixup functions</title>
+ <sect1 id="debug_obj_descr">
+ <title>Debug object type description structure</title>
+!Iinclude/linux/debugobjects.h
+ </sect1>
+ <sect1 id="fixup_init">
+ <title>fixup_init</title>
+ <para>
+ This function is called from the debug code whenever a problem
+ in debug_object_init is detected. The function takes the
+ address of the object and the state which is currently
+ recorded in the tracker.
+ </para>
+ <para>
+ Called from debug_object_init when the object state is:
+ <itemizedlist>
+ <listitem><para>ODEBUG_STATE_ACTIVE</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The function returns 1 when the fixup was successful,
+ otherwise 0. The return value is used to update the
+ statistics.
+ </para>
+ <para>
+ Note, that the function needs to call the debug_object_init()
+ function again, after the damage has been repaired in order to
+ keep the state consistent.
+ </para>
+ </sect1>
+
+ <sect1 id="fixup_activate">
+ <title>fixup_activate</title>
+ <para>
+ This function is called from the debug code whenever a problem
+ in debug_object_activate is detected.
+ </para>
+ <para>
+ Called from debug_object_activate when the object state is:
+ <itemizedlist>
+ <listitem><para>ODEBUG_STATE_NOTAVAILABLE</para></listitem>
+ <listitem><para>ODEBUG_STATE_ACTIVE</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The function returns 1 when the fixup was successful,
+ otherwise 0. The return value is used to update the
+ statistics.
+ </para>
+ <para>
+ Note that the function needs to call the debug_object_activate()
+ function again after the damage has been repaired in order to
+ keep the state consistent.
+ </para>
+ <para>
+ The activation of statically initialized objects is a special
+ case. When debug_object_activate() has no tracked object for
+ this object address then fixup_activate() is called with
+ object state ODEBUG_STATE_NOTAVAILABLE. The fixup function
+ needs to check whether this is a legitimate case of a
+ statically initialized object or not. In case it is it calls
+ debug_object_init() and debug_object_activate() to make the
+ object known to the tracker and marked active. In this case
+ the function should return 0 because this is not a real fixup.
+ </para>
+ </sect1>
+
+ <sect1 id="fixup_destroy">
+ <title>fixup_destroy</title>
+ <para>
+ This function is called from the debug code whenever a problem
+ in debug_object_destroy is detected.
+ </para>
+ <para>
+ Called from debug_object_destroy when the object state is:
+ <itemizedlist>
+ <listitem><para>ODEBUG_STATE_ACTIVE</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The function returns 1 when the fixup was successful,
+ otherwise 0. The return value is used to update the
+ statistics.
+ </para>
+ </sect1>
+ <sect1 id="fixup_free">
+ <title>fixup_free</title>
+ <para>
+ This function is called from the debug code whenever a problem
+ in debug_object_free is detected. Further it can be called
+ from the debug checks in kfree/vfree, when an active object is
+ detected from the debug_check_no_obj_freed() sanity checks.
+ </para>
+ <para>
+ Called from debug_object_free() or debug_check_no_obj_freed()
+ when the object state is:
+ <itemizedlist>
+ <listitem><para>ODEBUG_STATE_ACTIVE</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The function returns 1 when the fixup was successful,
+ otherwise 0. The return value is used to update the
+ statistics.
+ </para>
+ </sect1>
+ </chapter>
+ <chapter id="bugs">
+ <title>Known Bugs And Assumptions</title>
+ <para>
+ None (knock on wood).
+ </para>
+ </chapter>
+</book>
diff --git a/Documentation/DocBook/rapidio.tmpl b/Documentation/DocBook/rapidio.tmpl
index b9e143e..54eb26b 100644
--- a/Documentation/DocBook/rapidio.tmpl
+++ b/Documentation/DocBook/rapidio.tmpl
@@ -133,7 +133,6 @@
!Idrivers/rapidio/rio-sysfs.c
</sect1>
<sect1 id="PPC32_support"><title>PPC32 support</title>
-!Iarch/powerpc/kernel/rio.c
!Earch/powerpc/sysdev/fsl_rio.c
!Iarch/powerpc/sysdev/fsl_rio.c
</sect1>
diff --git a/Documentation/braille-console.txt b/Documentation/braille-console.txt
new file mode 100644
index 0000000..000b0fb
--- /dev/null
+++ b/Documentation/braille-console.txt
@@ -0,0 +1,34 @@
+ Linux Braille Console
+
+To get early boot messages on a braille device (before userspace screen
+readers can start), you first need to compile the support for the usual serial
+console (see serial-console.txt), and for braille device (in Device Drivers -
+Accessibility).
+
+Then you need to specify a console=brl, option on the kernel command line, the
+format is:
+
+ console=brl,serial_options...
+
+where serial_options... are the same as described in serial-console.txt
+
+So for instance you can use console=brl,ttyS0 if the braille device is connected
+to the first serial port, and console=brl,ttyS0,115200 to override the baud rate
+to 115200, etc.
+
+By default, the braille device will just show the last kernel message (console
+mode). To review previous messages, press the Insert key to switch to the VT
+review mode. In review mode, the arrow keys permit to browse in the VT content,
+page up/down keys go at the top/bottom of the screen, and the home key goes back
+to the cursor, hence providing very basic screen reviewing facility.
+
+Sound feedback can be obtained by adding the braille_console.sound=1 kernel
+parameter.
+
+For simplicity, only one braille console can be enabled, other uses of
+console=brl,... will be discarded. Also note that it does not interfere with
+the console selection mecanism described in serial-console.txt
+
+For now, only the VisioBraille device is supported.
+
+Samuel Thibault <samuel.thibault@ens-lyon.org>
diff --git a/Documentation/cgroups.txt b/Documentation/cgroups.txt
index 31d12e2..c298a66 100644
--- a/Documentation/cgroups.txt
+++ b/Documentation/cgroups.txt
@@ -500,8 +500,7 @@
void fork(struct cgroup_subsy *ss, struct task_struct *task)
-Called when a task is forked into a cgroup. Also called during
-registration for all existing tasks.
+Called when a task is forked into a cgroup.
void exit(struct cgroup_subsys *ss, struct task_struct *task)
diff --git a/Documentation/controllers/devices.txt b/Documentation/controllers/devices.txt
new file mode 100644
index 0000000..4dcea42
--- /dev/null
+++ b/Documentation/controllers/devices.txt
@@ -0,0 +1,48 @@
+Device Whitelist Controller
+
+1. Description:
+
+Implement a cgroup to track and enforce open and mknod restrictions
+on device files. A device cgroup associates a device access
+whitelist with each cgroup. A whitelist entry has 4 fields.
+'type' is a (all), c (char), or b (block). 'all' means it applies
+to all types and all major and minor numbers. Major and minor are
+either an integer or * for all. Access is a composition of r
+(read), w (write), and m (mknod).
+
+The root device cgroup starts with rwm to 'all'. A child device
+cgroup gets a copy of the parent. Administrators can then remove
+devices from the whitelist or add new entries. A child cgroup can
+never receive a device access which is denied its parent. However
+when a device access is removed from a parent it will not also be
+removed from the child(ren).
+
+2. User Interface
+
+An entry is added using devices.allow, and removed using
+devices.deny. For instance
+
+ echo 'c 1:3 mr' > /cgroups/1/devices.allow
+
+allows cgroup 1 to read and mknod the device usually known as
+/dev/null. Doing
+
+ echo a > /cgroups/1/devices.deny
+
+will remove the default 'a *:* mrw' entry.
+
+3. Security
+
+Any task can move itself between cgroups. This clearly won't
+suffice, but we can decide the best way to adequately restrict
+movement as people get some experience with this. We may just want
+to require CAP_SYS_ADMIN, which at least is a separate bit from
+CAP_MKNOD. We may want to just refuse moving to a cgroup which
+isn't a descendent of the current one. Or we may want to use
+CAP_MAC_ADMIN, since we really are trying to lock down root.
+
+CAP_SYS_ADMIN is needed to modify the whitelist or move another
+task to a new cgroup. (Again we'll probably want to change that).
+
+A cgroup may not be granted more permissions than the cgroup's
+parent has.
diff --git a/Documentation/controllers/resource_counter.txt b/Documentation/controllers/resource_counter.txt
new file mode 100644
index 0000000..f196ac1
--- /dev/null
+++ b/Documentation/controllers/resource_counter.txt
@@ -0,0 +1,181 @@
+
+ The Resource Counter
+
+The resource counter, declared at include/linux/res_counter.h,
+is supposed to facilitate the resource management by controllers
+by providing common stuff for accounting.
+
+This "stuff" includes the res_counter structure and routines
+to work with it.
+
+
+
+1. Crucial parts of the res_counter structure
+
+ a. unsigned long long usage
+
+ The usage value shows the amount of a resource that is consumed
+ by a group at a given time. The units of measurement should be
+ determined by the controller that uses this counter. E.g. it can
+ be bytes, items or any other unit the controller operates on.
+
+ b. unsigned long long max_usage
+
+ The maximal value of the usage over time.
+
+ This value is useful when gathering statistical information about
+ the particular group, as it shows the actual resource requirements
+ for a particular group, not just some usage snapshot.
+
+ c. unsigned long long limit
+
+ The maximal allowed amount of resource to consume by the group. In
+ case the group requests for more resources, so that the usage value
+ would exceed the limit, the resource allocation is rejected (see
+ the next section).
+
+ d. unsigned long long failcnt
+
+ The failcnt stands for "failures counter". This is the number of
+ resource allocation attempts that failed.
+
+ c. spinlock_t lock
+
+ Protects changes of the above values.
+
+
+
+2. Basic accounting routines
+
+ a. void res_counter_init(struct res_counter *rc)
+
+ Initializes the resource counter. As usual, should be the first
+ routine called for a new counter.
+
+ b. int res_counter_charge[_locked]
+ (struct res_counter *rc, unsigned long val)
+
+ When a resource is about to be allocated it has to be accounted
+ with the appropriate resource counter (controller should determine
+ which one to use on its own). This operation is called "charging".
+
+ This is not very important which operation - resource allocation
+ or charging - is performed first, but
+ * if the allocation is performed first, this may create a
+ temporary resource over-usage by the time resource counter is
+ charged;
+ * if the charging is performed first, then it should be uncharged
+ on error path (if the one is called).
+
+ c. void res_counter_uncharge[_locked]
+ (struct res_counter *rc, unsigned long val)
+
+ When a resource is released (freed) it should be de-accounted
+ from the resource counter it was accounted to. This is called
+ "uncharging".
+
+ The _locked routines imply that the res_counter->lock is taken.
+
+
+ 2.1 Other accounting routines
+
+ There are more routines that may help you with common needs, like
+ checking whether the limit is reached or resetting the max_usage
+ value. They are all declared in include/linux/res_counter.h.
+
+
+
+3. Analyzing the resource counter registrations
+
+ a. If the failcnt value constantly grows, this means that the counter's
+ limit is too tight. Either the group is misbehaving and consumes too
+ many resources, or the configuration is not suitable for the group
+ and the limit should be increased.
+
+ b. The max_usage value can be used to quickly tune the group. One may
+ set the limits to maximal values and either load the container with
+ a common pattern or leave one for a while. After this the max_usage
+ value shows the amount of memory the container would require during
+ its common activity.
+
+ Setting the limit a bit above this value gives a pretty good
+ configuration that works in most of the cases.
+
+ c. If the max_usage is much less than the limit, but the failcnt value
+ is growing, then the group tries to allocate a big chunk of resource
+ at once.
+
+ d. If the max_usage is much less than the limit, but the failcnt value
+ is 0, then this group is given too high limit, that it does not
+ require. It is better to lower the limit a bit leaving more resource
+ for other groups.
+
+
+
+4. Communication with the control groups subsystem (cgroups)
+
+All the resource controllers that are using cgroups and resource counters
+should provide files (in the cgroup filesystem) to work with the resource
+counter fields. They are recommended to adhere to the following rules:
+
+ a. File names
+
+ Field name File name
+ ---------------------------------------------------
+ usage usage_in_<unit_of_measurement>
+ max_usage max_usage_in_<unit_of_measurement>
+ limit limit_in_<unit_of_measurement>
+ failcnt failcnt
+ lock no file :)
+
+ b. Reading from file should show the corresponding field value in the
+ appropriate format.
+
+ c. Writing to file
+
+ Field Expected behavior
+ ----------------------------------
+ usage prohibited
+ max_usage reset to usage
+ limit set the limit
+ failcnt reset to zero
+
+
+
+5. Usage example
+
+ a. Declare a task group (take a look at cgroups subsystem for this) and
+ fold a res_counter into it
+
+ struct my_group {
+ struct res_counter res;
+
+ <other fields>
+ }
+
+ b. Put hooks in resource allocation/release paths
+
+ int alloc_something(...)
+ {
+ if (res_counter_charge(res_counter_ptr, amount) < 0)
+ return -ENOMEM;
+
+ <allocate the resource and return to the caller>
+ }
+
+ void release_something(...)
+ {
+ res_counter_uncharge(res_counter_ptr, amount);
+
+ <release the resource>
+ }
+
+ In order to keep the usage value self-consistent, both the
+ "res_counter_ptr" and the "amount" in release_something() should be
+ the same as they were in the alloc_something() when the releasing
+ resource was allocated.
+
+ c. Provide the way to read res_counter values and set them (the cgroups
+ still can help with it).
+
+ c. Compile and run :)
diff --git a/Documentation/cpu-freq/user-guide.txt b/Documentation/cpu-freq/user-guide.txt
index af3b925..6c442d8 100644
--- a/Documentation/cpu-freq/user-guide.txt
+++ b/Documentation/cpu-freq/user-guide.txt
@@ -154,6 +154,11 @@
that some governors won't load - they only
work on some specific architectures or
processors.
+
+cpuinfo_cur_freq : Current speed of the CPU, in KHz.
+
+scaling_available_frequencies : List of available frequencies, in KHz.
+
scaling_min_freq and
scaling_max_freq show the current "policy limits" (in
kHz). By echoing new values into these
@@ -162,6 +167,15 @@
first set scaling_max_freq, then
scaling_min_freq.
+affected_cpus : List of CPUs that require software coordination
+ of frequency.
+
+related_cpus : List of CPUs that need some sort of frequency
+ coordination, whether software or hardware.
+
+scaling_driver : Hardware driver for cpufreq.
+
+scaling_cur_freq : Current frequency of the CPU, in KHz.
If you have selected the "userspace" governor which allows you to
set the CPU operating frequency to a specific value, you can read out
diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt
index aa854b9..fb7b361 100644
--- a/Documentation/cpusets.txt
+++ b/Documentation/cpusets.txt
@@ -171,6 +171,7 @@
- memory_migrate flag: if set, move pages to cpusets nodes
- cpu_exclusive flag: is cpu placement exclusive?
- mem_exclusive flag: is memory placement exclusive?
+ - mem_hardwall flag: is memory allocation hardwalled
- memory_pressure: measure of how much paging pressure in cpuset
In addition, the root cpuset only has the following file:
@@ -222,17 +223,18 @@
a direct ancestor or descendent, may share any of the same CPUs or
Memory Nodes.
-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.
+A cpuset that is mem_exclusive *or* mem_hardwall is "hardwalled",
+i.e. it restricts kernel allocations for page, buffer and other data
+commonly shared by the kernel across multiple users. All cpusets,
+whether hardwalled 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 job's 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.
1.5 What is memory_pressure ?
@@ -707,7 +709,7 @@
In this directory you can find several files:
# ls
-cpus cpu_exclusive mems mem_exclusive tasks
+cpus cpu_exclusive mems mem_exclusive mem_hardwall tasks
Reading them will give you information about the state of this cpuset:
the CPUs and Memory Nodes it can use, the processes that are using
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 599fe55..3c35d45 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -138,6 +138,24 @@
---------------------------
+What: find_task_by_pid
+When: 2.6.26
+Why: With pid namespaces, calling this funciton will return the
+ wrong task when called from inside a namespace.
+
+ The best way to save a task pid and find a task by this
+ pid later, is to find this task's struct pid pointer (or get
+ it directly from the task) and call pid_task() later.
+
+ If someone really needs to get a task by its pid_t, then
+ he most likely needs the find_task_by_vpid() to get the
+ task from the same namespace as the current task is in, but
+ this may be not so in general.
+
+Who: Pavel Emelyanov <xemul@openvz.org>
+
+---------------------------
+
What: ACPI procfs interface
When: July 2008
Why: ACPI sysfs conversion should be finished by January 2008.
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 2a99116..dbc3c6a 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -463,11 +463,17 @@
SwapFree: 0 kB
Dirty: 968 kB
Writeback: 0 kB
+AnonPages: 861800 kB
Mapped: 280372 kB
-Slab: 684068 kB
+Slab: 284364 kB
+SReclaimable: 159856 kB
+SUnreclaim: 124508 kB
+PageTables: 24448 kB
+NFS_Unstable: 0 kB
+Bounce: 0 kB
+WritebackTmp: 0 kB
CommitLimit: 7669796 kB
Committed_AS: 100056 kB
-PageTables: 24448 kB
VmallocTotal: 112216 kB
VmallocUsed: 428 kB
VmallocChunk: 111088 kB
@@ -503,8 +509,17 @@
on the disk
Dirty: Memory which is waiting to get written back to the disk
Writeback: Memory which is actively being written back to the disk
+ AnonPages: Non-file backed pages mapped into userspace page tables
Mapped: files which have been mmaped, such as libraries
Slab: in-kernel data structures cache
+SReclaimable: Part of Slab, that might be reclaimed, such as caches
+ SUnreclaim: Part of Slab, that cannot be reclaimed on memory pressure
+ PageTables: amount of memory dedicated to the lowest level of page
+ tables.
+NFS_Unstable: NFS pages sent to the server, but not yet committed to stable
+ storage
+ Bounce: Memory used for block device "bounce buffers"
+WritebackTmp: Memory used by FUSE for temporary writeback buffers
CommitLimit: Based on the overcommit ratio ('vm.overcommit_ratio'),
this is the total amount of memory currently available to
be allocated on the system. This limit is only adhered to
@@ -531,8 +546,6 @@
above) will not be permitted. This is useful if one needs
to guarantee that processes will not fail due to lack of
memory once that memory has been successfully allocated.
- PageTables: amount of memory dedicated to the lowest level of page
- tables.
VmallocTotal: total size of vmalloc memory area
VmallocUsed: amount of vmalloc area which is used
VmallocChunk: largest contigious block of vmalloc area which is free
diff --git a/Documentation/hwmon/w83l785ts b/Documentation/hwmon/w83l785ts
index 1841ced..bd1fa9d 100644
--- a/Documentation/hwmon/w83l785ts
+++ b/Documentation/hwmon/w83l785ts
@@ -33,7 +33,8 @@
------------
On some systems (Asus), the BIOS is known to interfere with the driver
-and cause read errors. The driver will retry a given number of times
+and cause read errors. Or maybe the W83L785TS-S chip is simply unreliable,
+we don't really know. The driver will retry a given number of times
(5 by default) and then give up, returning the old value (or 0 if
there is no old value). It seems to work well enough so that you should
not notice anything. Thanks to James Bolt for helping test this feature.
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index bfb0a55..ee75cba 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -164,7 +164,8 @@
kind of driver in Linux: they provide a probe() method to bind to
those devices, and a remove() method to unbind.
- static int foo_probe(struct i2c_client *client);
+ static int foo_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
static int foo_remove(struct i2c_client *client);
Remember that the i2c_driver does not create those client handles. The
diff --git a/Documentation/i386/boot.txt b/Documentation/i386/boot.txt
index 0fac346..95ad15c 100644
--- a/Documentation/i386/boot.txt
+++ b/Documentation/i386/boot.txt
@@ -40,9 +40,17 @@
Introduce relocatable_kernel and kernel_alignment fields.
Protocol 2.06: (Kernel 2.6.22) Added a field that contains the size of
- the boot command line
+ the boot command line.
-Protocol 2.09: (kernel 2.6.26) Added a field of 64-bit physical
+Protocol 2.07: (Kernel 2.6.24) Added paravirtualised boot protocol.
+ Introduced hardware_subarch and hardware_subarch_data
+ and KEEP_SEGMENTS flag in load_flags.
+
+Protocol 2.08: (Kernel 2.6.26) Added crc32 checksum and ELF format
+ payload. Introduced payload_offset and payload length
+ fields to aid in locating the payload.
+
+Protocol 2.09: (Kernel 2.6.26) Added a field of 64-bit physical
pointer to single linked list of struct setup_data.
**** MEMORY LAYOUT
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
index d0ac72c..b8e52c0 100644
--- a/Documentation/kdump/kdump.txt
+++ b/Documentation/kdump/kdump.txt
@@ -245,6 +245,8 @@
crashkernel=<range1>:<size1>[,<range2>:<size2>,...][@offset]
range=start-[end]
+ 'start' is inclusive and 'end' is exclusive.
+
For example:
crashkernel=512M-2G:64M,2G-:128M
@@ -253,10 +255,11 @@
1) if the RAM is smaller than 512M, then don't reserve anything
(this is the "rescue" case)
- 2) if the RAM size is between 512M and 2G, then reserve 64M
+ 2) if the RAM size is between 512M and 2G (exclusive), then reserve 64M
3) if the RAM size is larger than 2G, then reserve 128M
+
Boot into System Kernel
=======================
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index e5f3d91..a3c3544 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -496,6 +496,11 @@
switching to the matching ttyS device later. The
options are the same as for ttyS, above.
+ If the device connected to the port is not a TTY but a braille
+ device, prepend "brl," before the device type, for instance
+ console=brl,ttyS0
+ For now, only VisioBraille is supported.
+
earlycon= [KNL] Output early console device and options.
uart[8250],io,<addr>[,options]
uart[8250],mmio,<addr>[,options]
@@ -556,6 +561,8 @@
1 will print _a lot_ more information - normally
only useful to kernel developers.
+ debug_objects [KNL] Enable object debugging
+
decnet.addr= [HW,NET]
Format: <area>[,<node>]
See also Documentation/networking/decnet.txt.
@@ -627,8 +634,7 @@
eata= [HW,SCSI]
edd= [EDD]
- Format: {"of[f]" | "sk[ipmbr]"}
- See comment in arch/i386/boot/edd.S
+ Format: {"off" | "on" | "skip[mbr]"}
eisa_irq_edge= [PARISC,HW]
See header of drivers/parisc/eisa.c.
@@ -1389,6 +1395,13 @@
nr_uarts= [SERIAL] maximum number of UARTs to be registered.
+ olpc_ec_timeout= [OLPC] ms delay when issuing EC commands
+ Rather than timing out after 20 ms if an EC
+ command is not properly ACKed, override the length
+ of the timeout. We have interrupts disabled while
+ waiting for the ACK, so if this is set too high
+ interrupts *may* be lost!
+
opl3= [HW,OSS]
Format: <io>
diff --git a/Documentation/keys-request-key.txt b/Documentation/keys-request-key.txt
index 266955d..09b55e4 100644
--- a/Documentation/keys-request-key.txt
+++ b/Documentation/keys-request-key.txt
@@ -11,26 +11,29 @@
struct key *request_key(const struct key_type *type,
const char *description,
- const char *callout_string);
+ const char *callout_info);
or:
struct key *request_key_with_auxdata(const struct key_type *type,
const char *description,
- const char *callout_string,
+ const char *callout_info,
+ size_t callout_len,
void *aux);
or:
struct key *request_key_async(const struct key_type *type,
const char *description,
- const char *callout_string);
+ const char *callout_info,
+ size_t callout_len);
or:
struct key *request_key_async_with_auxdata(const struct key_type *type,
const char *description,
- const char *callout_string,
+ const char *callout_info,
+ size_t callout_len,
void *aux);
Or by userspace invoking the request_key system call:
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
index 51652d3..d5c7a57d 100644
--- a/Documentation/keys.txt
+++ b/Documentation/keys.txt
@@ -170,7 +170,8 @@
amount of description and payload space that can be consumed.
The user can view information on this and other statistics through procfs
- files.
+ files. The root user may also alter the quota limits through sysctl files
+ (see the section "New procfs files").
Process-specific and thread-specific keyrings are not counted towards a
user's quota.
@@ -329,6 +330,27 @@
<bytes>/<max> Key size quota
+Four new sysctl files have been added also for the purpose of controlling the
+quota limits on keys:
+
+ (*) /proc/sys/kernel/keys/root_maxkeys
+ /proc/sys/kernel/keys/root_maxbytes
+
+ These files hold the maximum number of keys that root may have and the
+ maximum total number of bytes of data that root may have stored in those
+ keys.
+
+ (*) /proc/sys/kernel/keys/maxkeys
+ /proc/sys/kernel/keys/maxbytes
+
+ These files hold the maximum number of keys that each non-root user may
+ have and the maximum total number of bytes of data that each of those
+ users may have stored in their keys.
+
+Root may alter these by writing each new limit as a decimal number string to
+the appropriate file.
+
+
===============================
USERSPACE SYSTEM CALL INTERFACE
===============================
@@ -711,6 +733,27 @@
The assumed authoritative key is inherited across fork and exec.
+ (*) Get the LSM security context attached to a key.
+
+ long keyctl(KEYCTL_GET_SECURITY, key_serial_t key, char *buffer,
+ size_t buflen)
+
+ This function returns a string that represents the LSM security context
+ attached to a key in the buffer provided.
+
+ Unless there's an error, it always returns the amount of data it could
+ produce, even if that's too big for the buffer, but it won't copy more
+ than requested to userspace. If the buffer pointer is NULL then no copy
+ will take place.
+
+ A NUL character is included at the end of the string if the buffer is
+ sufficiently big. This is included in the returned count. If no LSM is
+ in force then an empty string will be returned.
+
+ A process must have view permission on the key for this function to be
+ successful.
+
+
===============
KERNEL SERVICES
===============
@@ -771,7 +814,7 @@
struct key *request_key(const struct key_type *type,
const char *description,
- const char *callout_string);
+ const char *callout_info);
This is used to request a key or keyring with a description that matches
the description specified according to the key type's match function. This
@@ -793,24 +836,28 @@
struct key *request_key_with_auxdata(const struct key_type *type,
const char *description,
- const char *callout_string,
+ const void *callout_info,
+ size_t callout_len,
void *aux);
This is identical to request_key(), except that the auxiliary data is
- passed to the key_type->request_key() op if it exists.
+ passed to the key_type->request_key() op if it exists, and the callout_info
+ is a blob of length callout_len, if given (the length may be 0).
(*) A key can be requested asynchronously by calling one of:
struct key *request_key_async(const struct key_type *type,
const char *description,
- const char *callout_string);
+ const void *callout_info,
+ size_t callout_len);
or:
struct key *request_key_async_with_auxdata(const struct key_type *type,
const char *description,
- const char *callout_string,
+ const char *callout_info,
+ size_t callout_len,
void *aux);
which are asynchronous equivalents of request_key() and
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
index 76cb428..01c6c3d 100644
--- a/Documentation/laptops/thinkpad-acpi.txt
+++ b/Documentation/laptops/thinkpad-acpi.txt
@@ -1,7 +1,7 @@
ThinkPad ACPI Extras Driver
- Version 0.19
- January 06th, 2008
+ Version 0.20
+ April 09th, 2008
Borislav Deianov <borislav@users.sf.net>
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
@@ -18,6 +18,11 @@
moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
2.6.22, and release 0.14.
+The driver is named "thinkpad-acpi". In some places, like module
+names, "thinkpad_acpi" is used because of userspace issues.
+
+"tpacpi" is used as a shorthand where "thinkpad-acpi" would be too
+long due to length limitations on some Linux kernel versions.
Status
------
@@ -571,6 +576,47 @@
with hotkey_report_mode.
+Brightness hotkey notes:
+
+These are the current sane choices for brightness key mapping in
+thinkpad-acpi:
+
+For IBM and Lenovo models *without* ACPI backlight control (the ones on
+which thinkpad-acpi will autoload its backlight interface by default,
+and on which ACPI video does not export a backlight interface):
+
+1. Don't enable or map the brightness hotkeys in thinkpad-acpi, as
+ these older firmware versions unfortunately won't respect the hotkey
+ mask for brightness keys anyway, and always reacts to them. This
+ usually work fine, unless X.org drivers are doing something to block
+ the BIOS. In that case, use (3) below. This is the default mode of
+ operation.
+
+2. Enable the hotkeys, but map them to something else that is NOT
+ KEY_BRIGHTNESS_UP/DOWN or any other keycode that would cause
+ userspace to try to change the backlight level, and use that as an
+ on-screen-display hint.
+
+3. IF AND ONLY IF X.org drivers find a way to block the firmware from
+ automatically changing the brightness, enable the hotkeys and map
+ them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN, and feed that to
+ something that calls xbacklight. thinkpad-acpi will not be able to
+ change brightness in that case either, so you should disable its
+ backlight interface.
+
+For Lenovo models *with* ACPI backlight control:
+
+1. Load up ACPI video and use that. ACPI video will report ACPI
+ events for brightness change keys. Do not mess with thinkpad-acpi
+ defaults in this case. thinkpad-acpi should not have anything to do
+ with backlight events in a scenario where ACPI video is loaded:
+ brightness hotkeys must be disabled, and the backlight interface is
+ to be kept disabled as well. This is the default mode of operation.
+
+2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi,
+ and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process
+ these keys on userspace somehow (e.g. by calling xbacklight).
+
Bluetooth
---------
@@ -647,16 +693,31 @@
https://bugs.freedesktop.org/show_bug.cgi?id=2000
-ThinkLight control -- /proc/acpi/ibm/light
-------------------------------------------
+ThinkLight control
+------------------
-The current status of the ThinkLight can be found in this file. A few
-models which do not make the status available will show it as
-"unknown". The available commands are:
+procfs: /proc/acpi/ibm/light
+sysfs attributes: as per LED class, for the "tpacpi::thinklight" LED
+
+procfs notes:
+
+The ThinkLight status can be read and set through the procfs interface. A
+few models which do not make the status available will show the ThinkLight
+status as "unknown". The available commands are:
echo on > /proc/acpi/ibm/light
echo off > /proc/acpi/ibm/light
+sysfs notes:
+
+The ThinkLight sysfs interface is documented by the LED class
+documentation, in Documentation/leds-class.txt. The ThinkLight LED name
+is "tpacpi::thinklight".
+
+Due to limitations in the sysfs LED class, if the status of the thinklight
+cannot be read or if it is unknown, thinkpad-acpi will report it as "off".
+It is impossible to know if the status returned through sysfs is valid.
+
Docking / undocking -- /proc/acpi/ibm/dock
------------------------------------------
@@ -815,28 +876,63 @@
in newer ThinkPads it is just a compatibility layer. Do not use it, it is
exported just as a debug tool.
-LED control -- /proc/acpi/ibm/led
----------------------------------
+LED control
+-----------
-Some of the LED indicators can be controlled through this feature. The
-available commands are:
+procfs: /proc/acpi/ibm/led
+sysfs attributes: as per LED class, see below for names
- echo '<led number> on' >/proc/acpi/ibm/led
- echo '<led number> off' >/proc/acpi/ibm/led
- echo '<led number> blink' >/proc/acpi/ibm/led
+Some of the LED indicators can be controlled through this feature. On
+some older ThinkPad models, it is possible to query the status of the
+LED indicators as well. Newer ThinkPads cannot query the real status
+of the LED indicators.
-The <led number> range is 0 to 7. The set of LEDs that can be
-controlled varies from model to model. Here is the mapping on the X40:
+procfs notes:
+
+The available commands are:
+
+ echo '<LED number> on' >/proc/acpi/ibm/led
+ echo '<LED number> off' >/proc/acpi/ibm/led
+ echo '<LED number> blink' >/proc/acpi/ibm/led
+
+The <LED number> range is 0 to 7. The set of LEDs that can be
+controlled varies from model to model. Here is the common ThinkPad
+mapping:
0 - power
1 - battery (orange)
2 - battery (green)
- 3 - UltraBase
+ 3 - UltraBase/dock
4 - UltraBay
+ 5 - UltraBase battery slot
+ 6 - (unknown)
7 - standby
All of the above can be turned on and off and can be made to blink.
+sysfs notes:
+
+The ThinkPad LED sysfs interface is described in detail by the LED class
+documentation, in Documentation/leds-class.txt.
+
+The leds are named (in LED ID order, from 0 to 7):
+"tpacpi::power", "tpacpi:orange:batt", "tpacpi:green:batt",
+"tpacpi::dock_active", "tpacpi::bay_active", "tpacpi::dock_batt",
+"tpacpi::unknown_led", "tpacpi::standby".
+
+Due to limitations in the sysfs LED class, if the status of the LED
+indicators cannot be read due to an error, thinkpad-acpi will report it as
+a brightness of zero (same as LED off).
+
+If the thinkpad firmware doesn't support reading the current status,
+trying to read the current LED brightness will just return whatever
+brightness was last written to that attribute.
+
+These LEDs can blink using hardware acceleration. To request that a
+ThinkPad indicator LED should blink in hardware accelerated mode, use the
+"timer" trigger, and leave the delay_on and delay_off parameters set to
+zero (to request hardware acceleration autodetection).
+
ACPI sounds -- /proc/acpi/ibm/beep
----------------------------------
@@ -1090,6 +1186,15 @@
dim the display.
+WARNING:
+
+ Whatever you do, do NOT ever call thinkpad-acpi backlight-level change
+ interface and the ACPI-based backlight level change interface
+ (available on newer BIOSes, and driven by the Linux ACPI video driver)
+ at the same time. The two will interact in bad ways, do funny things,
+ and maybe reduce the life of the backlight lamps by needlessly kicking
+ its level up and down at every change.
+
Volume control -- /proc/acpi/ibm/volume
---------------------------------------
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index 4c1fc65..3be8ab2 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -131,6 +131,9 @@
/* Any queues attached to this device */
struct virtqueue *vq;
+ /* Handle status being finalized (ie. feature bits stable). */
+ void (*ready)(struct device *me);
+
/* Device-specific data. */
void *priv;
};
@@ -925,24 +928,40 @@
write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
}
-/* When the Guest asks us to reset a device, it's is fairly easy. */
-static void reset_device(struct device *dev)
+/* When the Guest tells us they updated the status field, we handle it. */
+static void update_device_status(struct device *dev)
{
struct virtqueue *vq;
- verbose("Resetting device %s\n", dev->name);
- /* Clear the status. */
- dev->desc->status = 0;
+ /* This is a reset. */
+ if (dev->desc->status == 0) {
+ verbose("Resetting device %s\n", dev->name);
- /* Clear any features they've acked. */
- memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
- dev->desc->feature_len);
+ /* Clear any features they've acked. */
+ memset(get_feature_bits(dev) + dev->desc->feature_len, 0,
+ dev->desc->feature_len);
- /* Zero out the virtqueues. */
- for (vq = dev->vq; vq; vq = vq->next) {
- memset(vq->vring.desc, 0,
- vring_size(vq->config.num, getpagesize()));
- vq->last_avail_idx = 0;
+ /* Zero out the virtqueues. */
+ for (vq = dev->vq; vq; vq = vq->next) {
+ memset(vq->vring.desc, 0,
+ vring_size(vq->config.num, getpagesize()));
+ vq->last_avail_idx = 0;
+ }
+ } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
+ warnx("Device %s configuration FAILED", dev->name);
+ } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
+ unsigned int i;
+
+ verbose("Device %s OK: offered", dev->name);
+ for (i = 0; i < dev->desc->feature_len; i++)
+ verbose(" %08x", get_feature_bits(dev)[i]);
+ verbose(", accepted");
+ for (i = 0; i < dev->desc->feature_len; i++)
+ verbose(" %08x", get_feature_bits(dev)
+ [dev->desc->feature_len+i]);
+
+ if (dev->ready)
+ dev->ready(dev);
}
}
@@ -954,9 +973,9 @@
/* Check each device and virtqueue. */
for (i = devices.dev; i; i = i->next) {
- /* Notifications to device descriptors reset the device. */
+ /* Notifications to device descriptors update device status. */
if (from_guest_phys(addr) == i->desc) {
- reset_device(i);
+ update_device_status(i);
return;
}
@@ -1170,6 +1189,7 @@
dev->handle_input = handle_input;
dev->name = name;
dev->vq = NULL;
+ dev->ready = NULL;
/* Append to device list. Prepending to a single-linked list is
* easier, but the user expects the devices to be arranged on the bus
@@ -1398,7 +1418,7 @@
struct vblk_info *vblk = dev->priv;
unsigned int head, out_num, in_num, wlen;
int ret;
- struct virtio_blk_inhdr *in;
+ u8 *in;
struct virtio_blk_outhdr *out;
struct iovec iov[dev->vq->vring.num];
off64_t off;
@@ -1416,7 +1436,7 @@
head, out_num, in_num);
out = convert(&iov[0], struct virtio_blk_outhdr);
- in = convert(&iov[out_num+in_num-1], struct virtio_blk_inhdr);
+ in = convert(&iov[out_num+in_num-1], u8);
off = out->sector * 512;
/* The block device implements "barriers", where the Guest indicates
@@ -1430,7 +1450,7 @@
* It'd be nice if we supported eject, for example, but we don't. */
if (out->type & VIRTIO_BLK_T_SCSI_CMD) {
fprintf(stderr, "Scsi commands unsupported\n");
- in->status = VIRTIO_BLK_S_UNSUPP;
+ *in = VIRTIO_BLK_S_UNSUPP;
wlen = sizeof(*in);
} else if (out->type & VIRTIO_BLK_T_OUT) {
/* Write */
@@ -1453,7 +1473,7 @@
errx(1, "Write past end %llu+%u", off, ret);
}
wlen = sizeof(*in);
- in->status = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
+ *in = (ret >= 0 ? VIRTIO_BLK_S_OK : VIRTIO_BLK_S_IOERR);
} else {
/* Read */
@@ -1466,10 +1486,10 @@
verbose("READ from sector %llu: %i\n", out->sector, ret);
if (ret >= 0) {
wlen = sizeof(*in) + ret;
- in->status = VIRTIO_BLK_S_OK;
+ *in = VIRTIO_BLK_S_OK;
} else {
wlen = sizeof(*in);
- in->status = VIRTIO_BLK_S_IOERR;
+ *in = VIRTIO_BLK_S_IOERR;
}
}
diff --git a/Documentation/oops-tracing.txt b/Documentation/oops-tracing.txt
index 7f60dfe..b152e81 100644
--- a/Documentation/oops-tracing.txt
+++ b/Documentation/oops-tracing.txt
@@ -253,6 +253,10 @@
8: 'D' if the kernel has died recently, i.e. there was an OOPS or BUG.
+ 9: 'A' if the ACPI table has been overridden.
+
+ 10: 'W' if a warning has previously been issued by the kernel.
+
The primary reason for the 'Tainted: ' string is to tell kernel
debuggers if this is a clean kernel or if anything unusual has
occurred. Tainting is permanent: even if an offending module is
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index 91c81db..716fcc1 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,3 +1,25 @@
+1 Release Date : Mon. March 10 11:02:31 PDT 2008 -
+ (emaild-id:megaraidlinux@lsi.com)
+ Sumant Patro
+ Bo Yang
+
+2 Current Version : 00.00.03.20-RC1
+3 Older Version : 00.00.03.16
+
+1. Rollback the sense info implementation
+ Sense buffer ptr data type in the ioctl path is reverted back
+ to u32 * as in previous versions of driver.
+
+2. Fixed the driver frame count.
+ When Driver sent wrong frame count to firmware. As this
+ particular command is sent to drive, FW is seeing continuous
+ chip resets and so the command will timeout.
+
+3. Add the new controller(1078DE) support to the driver
+ and Increase the max_wait to 60 from 10 in the controller
+ operational status. With this max_wait increase, driver will
+ make sure the FW will finish the pending cmd for KDUMP case.
+
1 Release Date : Thur. Nov. 07 16:30:43 PST 2007 -
(emaild-id:megaraidlinux@lsi.com)
Sumant Patro
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index fd4c32a..0bbee38 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -795,6 +795,7 @@
lg-lw LG LW20/LW25 laptop
tcl TCL S700
clevo Clevo laptops (m520G, m665n)
+ medion Medion Rim 2150
test for testing/debugging purpose, almost all controls can be
adjusted. Appearing only when compiled with
$CONFIG_SND_DEBUG=y
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index 10c8f69..5ce0952 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -85,6 +85,8 @@
'k' - Secure Access Key (SAK) Kills all programs on the current virtual
console. NOTE: See important comments below in SAK section.
+'l' - Shows a stack backtrace for all active CPUs.
+
'm' - Will dump current memory info to your console.
'n' - Used to make RT tasks nice-able
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index d9f28be..70d68ce 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -108,10 +108,12 @@
RO read only value
RW read/write value
-All thermal sysfs attributes will be represented under /sys/class/thermal
+Thermal sysfs attributes will be represented under /sys/class/thermal.
+Hwmon sysfs I/F extension is also available under /sys/class/hwmon
+if hwmon is compiled in or built as a module.
Thermal zone device sys I/F, created once it's registered:
-|thermal_zone[0-*]:
+/sys/class/thermal/thermal_zone[0-*]:
|-----type: Type of the thermal zone
|-----temp: Current temperature
|-----mode: Working mode of the thermal zone
@@ -119,7 +121,7 @@
|-----trip_point_[0-*]_type: Trip point type
Thermal cooling device sys I/F, created once it's registered:
-|cooling_device[0-*]:
+/sys/class/thermal/cooling_device[0-*]:
|-----type : Type of the cooling device(processor/fan/...)
|-----max_state: Maximum cooling state of the cooling device
|-----cur_state: Current cooling state of the cooling device
@@ -130,10 +132,19 @@
They are created/removed for each
thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful execution.
-|thermal_zone[0-*]
+/sys/class/thermal/thermal_zone[0-*]
|-----cdev[0-*]: The [0-*]th cooling device in the current thermal zone
|-----cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with
+Besides the thermal zone device sysfs I/F and cooling device sysfs I/F,
+the generic thermal driver also creates a hwmon sysfs I/F for each _type_ of
+thermal zone device. E.g. the generic thermal driver registers one hwmon class device
+and build the associated hwmon sysfs I/F for all the registered ACPI thermal zones.
+/sys/class/hwmon/hwmon[0-*]:
+ |-----name: The type of the thermal zone devices.
+ |-----temp[1-*]_input: The current temperature of thermal zone [1-*].
+ |-----temp[1-*]_critical: The critical trip point of thermal zone [1-*].
+Please read Documentation/hwmon/sysfs-interface for additional information.
***************************
* Thermal zone attributes *
@@ -141,7 +152,10 @@
type Strings which represent the thermal zone type.
This is given by thermal zone driver as part of registration.
- Eg: "ACPI thermal zone" indicates it's a ACPI thermal device
+ Eg: "acpitz" indicates it's an ACPI thermal device.
+ In order to keep it consistent with hwmon sys attribute,
+ this should be a short, lowercase string,
+ not containing spaces nor dashes.
RO
Required
@@ -218,7 +232,7 @@
/sys/class/thermal:
|thermal_zone1:
- |-----type: ACPI thermal zone
+ |-----type: acpitz
|-----temp: 37000
|-----mode: kernel
|-----trip_point_0_temp: 100000
@@ -243,3 +257,10 @@
|-----type: Fan
|-----max_state: 2
|-----cur_state: 0
+
+/sys/class/hwmon:
+
+|hwmon0:
+ |-----name: acpitz
+ |-----temp1_input: 37000
+ |-----temp1_crit: 100000
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 44d84dd..67937df 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -128,7 +128,7 @@
127 -> Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM [0000:5071,0000:507B,5ace:5070,5ace:5090]
128 -> Beholder BeholdTV Columbus TVFM [0000:5201]
129 -> Beholder BeholdTV 607 / BeholdTV 609 [5ace:6070,5ace:6071,5ace:6072,5ace:6073,5ace:6090,5ace:6091,5ace:6092,5ace:6093]
-130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193]
+130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193,5ace:6191]
131 -> Twinhan Hybrid DTV-DVB 3056 PCI [1822:0022]
132 -> Genius TVGO AM11MCE
133 -> NXP Snake DVB-S reference design
@@ -140,3 +140,4 @@
139 -> Compro VideoMate T750 [185b:c900]
140 -> Avermedia DVB-S Pro A700 [1461:a7a1]
141 -> Avermedia DVB-S Hybrid+FM A700 [1461:a7a2]
+142 -> Beholder BeholdTV H6 [5ace:6290]
diff --git a/Documentation/video4linux/cx18.txt b/Documentation/video4linux/cx18.txt
new file mode 100644
index 0000000..077d56e
--- /dev/null
+++ b/Documentation/video4linux/cx18.txt
@@ -0,0 +1,34 @@
+Some notes regarding the cx18 driver for the Conexant CX23418 MPEG
+encoder chip:
+
+1) The only hardware currently supported is the Hauppauge HVR-1600.
+
+2) Some people have problems getting the i2c bus to work. Cause unknown.
+ The symptom is that the eeprom cannot be read and the card is
+ unusable.
+
+3) The audio from the analog tuner is mono only. Probably caused by
+ incorrect audio register information in the datasheet. We are
+ waiting for updated information from Conexant.
+
+4) VBI (raw or sliced) has not yet been implemented.
+
+5) MPEG indexing is not yet implemented.
+
+6) The driver is still a bit rough around the edges, this should
+ improve over time.
+
+
+Firmware:
+
+The firmware needs to be extracted from the Windows Hauppauge HVR-1600
+driver, available here:
+
+http://hauppauge.lightpath.net/software/install_cd/hauppauge_cd_3.4d1.zip
+
+Unzip, then copy the following files to the firmware directory
+and rename them as follows:
+
+Drivers/Driver18/hcw18apu.rom -> v4l-cx23418-apu.fw
+Drivers/Driver18/hcw18enc.rom -> v4l-cx23418-cpu.fw
+Drivers/Driver18/hcw18mlC.rom -> v4l-cx23418-dig.fw
diff --git a/MAINTAINERS b/MAINTAINERS
index c1dd1ae..93547d3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -752,11 +752,13 @@
S: Maintained
AUDIT SUBSYSTEM
-P: David Woodhouse
-M: dwmw2@infradead.org
+P: Al Viro
+M: viro@zeniv.linux.org.uk
+P: Eric Paris
+M: eparis@redhat.com
L: linux-audit@redhat.com (subscribers-only)
W: http://people.redhat.com/sgrubb/audit/
-T: git kernel.org:/pub/scm/linux/kernel/git/dwmw2/audit-2.6.git
+T: git git.kernel.org/pub/scm/linux/kernel/git/viro/audit-current.git
S: Maintained
AUXILIARY DISPLAY DRIVERS
@@ -1037,7 +1039,7 @@
M: urs.thuermann@volkswagen.de
P: Oliver Hartkopp
M: oliver.hartkopp@volkswagen.de
-L: socketcan-core@lists.berlios.de
+L: socketcan-core@lists.berlios.de (subscribers-only)
W: http://developer.berlios.de/projects/socketcan/
S: Maintained
@@ -1194,9 +1196,9 @@
CPUSETS
P: Paul Jackson
-P: Simon Derr
+P: Paul Menage
M: pj@sgi.com
-M: simon.derr@bull.net
+M: menage@google.com
L: linux-kernel@vger.kernel.org
W: http://www.bullopensource.org/cpuset/
S: Supported
@@ -1531,6 +1533,13 @@
W: bluesmoke.sourceforge.net
S: Maintained
+EEEPC LAPTOP EXTRAS DRIVER
+P: Corentin Chary
+M: corentincj@iksaif.net
+L: acpi4asus-user@lists.sourceforge.net
+W: http://sourceforge.net/projects/acpi4asus
+S: Maintained
+
EEPRO100 NETWORK DRIVER
P: Andrey V. Savochkin
M: saw@saw.sw.com.sg
@@ -1548,6 +1557,14 @@
L: general@lists.openfabrics.org
S: Supported
+EMBEDDED LINUX
+P: Paul Gortmaker
+M: paul.gortmaker@windriver.com
+P David Woodhouse
+M: dwmw2@infradead.org
+L: linux-embedded@vger.kernel.org
+S: Maintained
+
EMULEX LPFC FC SCSI DRIVER
P: James Smart
M: james.smart@emulex.com
@@ -2694,7 +2711,7 @@
M: dhowells@redhat.com
P: Koichi Yasutake
M: yasutake.koichi@jp.panasonic.com
-L: linux-am33-list@redhat.com
+L: linux-am33-list@redhat.com (moderated for non-subscribers)
W: ftp://ftp.redhat.com/pub/redhat/gnupro/AM33/
S: Maintained
@@ -2757,7 +2774,7 @@
L: linux-kernel@vger.kernel.org
S: Maintained
-MOXA SMARTIO/INDUSTIO SERIAL CARD (MXSER 2.0)
+MOXA SMARTIO/INDUSTIO/INTELLIO SERIAL CARD
P: Jiri Slaby
M: jirislaby@gmail.com
L: linux-kernel@vger.kernel.org
@@ -3114,6 +3131,7 @@
M: jbarnes@virtuousgeek.org
L: linux-kernel@vger.kernel.org
L: linux-pci@atrey.karlin.mff.cuni.cz
+T: git kernel.org:/pub/scm/linux/kernel/git/jbarnes/pci-2.6.git
S: Supported
PCI HOTPLUG CORE
@@ -3574,6 +3592,13 @@
L: linux-ia64@vger.kernel.org
S: Supported
+SFC NETWORK DRIVER
+P: Steve Hodgson
+P: Ben Hutchings
+P: Robert Stonehouse
+M: linux-net-drivers@solarflare.com
+S: Supported
+
SGI VISUAL WORKSTATION 320 AND 540
P: Andrey Panin
M: pazke@donpac.ru
@@ -3740,42 +3765,6 @@
L: stable@kernel.org
S: Maintained
-TPM DEVICE DRIVER
-P: Kylene Hall
-M: tpmdd-devel@lists.sourceforge.net
-W: http://tpmdd.sourceforge.net
-P: Marcel Selhorst
-M: tpm@selhorst.net
-W: http://www.prosec.rub.de/tpm/
-L: tpmdd-devel@lists.sourceforge.net
-S: Maintained
-
-Telecom Clock Driver for MCPL0010
-P: Mark Gross
-M: mark.gross@intel.com
-S: Supported
-
-TENSILICA XTENSA PORT (xtensa):
-P: Chris Zankel
-M: chris@zankel.net
-S: Maintained
-
-THINKPAD ACPI EXTRAS DRIVER
-P: Henrique de Moraes Holschuh
-M: ibm-acpi@hmh.eng.br
-L: ibm-acpi-devel@lists.sourceforge.net
-W: http://ibm-acpi.sourceforge.net
-W: http://thinkwiki.org/wiki/Ibm-acpi
-T: git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
-S: Maintained
-
-UltraSPARC (sparc64):
-P: David S. Miller
-M: davem@davemloft.net
-L: sparclinux@vger.kernel.org
-T: git kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6.git
-S: Maintained
-
SHARP LH SUPPORT (LH7952X & LH7A40X)
P: Marc Singer
M: elf@buici.com
@@ -3872,6 +3861,12 @@
M: hch@infradead.org
S: Maintained
+TASKSTATS STATISTICS INTERFACE
+P: Shailabh Nagar
+M: nagar@watson.ibm.com
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
TC CLASSIFIER
P: Jamal Hadi Salim
M: hadi@cyberus.ca
@@ -3894,6 +3889,25 @@
L: netdev@vger.kernel.org
S: Supported
+Telecom Clock Driver for MCPL0010
+P: Mark Gross
+M: mark.gross@intel.com
+S: Supported
+
+TENSILICA XTENSA PORT (xtensa):
+P: Chris Zankel
+M: chris@zankel.net
+S: Maintained
+
+THINKPAD ACPI EXTRAS DRIVER
+P: Henrique de Moraes Holschuh
+M: ibm-acpi@hmh.eng.br
+L: ibm-acpi-devel@lists.sourceforge.net
+W: http://ibm-acpi.sourceforge.net
+W: http://thinkwiki.org/wiki/Ibm-acpi
+T: git repo.or.cz/linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git
+S: Maintained
+
TI FLASH MEDIA INTERFACE DRIVER
P: Alex Dubov
M: oakad@yahoo.com
@@ -3911,12 +3925,6 @@
M: dsaxena@plexity.net
S: Maintained
-TASKSTATS STATISTICS INTERFACE
-P: Shailabh Nagar
-M: nagar@watson.ibm.com
-L: linux-kernel@vger.kernel.org
-S: Maintained
-
TIPC NETWORK LAYER
P: Per Liden
M: per.liden@ericsson.com
@@ -3950,6 +3958,16 @@
W: http://www.buzzard.org.uk/toshiba/
S: Maintained
+TPM DEVICE DRIVER
+P: Kylene Hall
+M: tpmdd-devel@lists.sourceforge.net
+W: http://tpmdd.sourceforge.net
+P: Marcel Selhorst
+M: tpm@selhorst.net
+W: http://www.prosec.rub.de/tpm/
+L: tpmdd-devel@lists.sourceforge.net
+S: Maintained
+
TRIDENT 4DWAVE/SIS 7018 PCI AUDIO CORE
P: Muli Ben-Yehuda
M: mulix@mulix.org
@@ -3962,6 +3980,12 @@
L: linux-kernel@vger.kernel.org
S: Maintained
+TTY LAYER
+P: Alan Cox
+M: alan@lxorguk.ukuu.org.uk
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
TULIP NETWORK DRIVERS
P: Grant Grundler
M: grundler@parisc-linux.org
@@ -4027,6 +4051,12 @@
S: Maintained
W: http://www.kroah.com/linux-usb/
+USB CYPRESS C67X00 DRIVER
+P: Peter Korsgaard
+M: jacmet@sunsite.dk
+L: linux-usb@vger.kernel.org
+S: Maintained
+
USB DAVICOM DM9601 DRIVER
P: Peter Korsgaard
M: jacmet@sunsite.dk
@@ -4130,6 +4160,20 @@
W: http://www.chello.nl/~j.vreeken/se401/
S: Maintained
+USB SERIAL BELKIN F5U103 DRIVER
+P: William Greathouse
+M: wgreathouse@smva.com
+L: linux-usb@vger.kernel.org
+S: Maintained
+
+USB SERIAL CYPRESS M8 DRIVER
+P: Lonnie Mendez
+M: dignome@gmail.com
+L: linux-usb@vger.kernel.org
+S: Maintained
+W: http://geocities.com/i0xox0i
+W: http://firstlight.net/cvs
+
USB SERIAL CYBERJACK DRIVER
P: Matthias Bruestle and Harald Welte
M: support@reiner-sct.com
@@ -4149,20 +4193,6 @@
L: linux-usb@vger.kernel.org
S: Supported
-USB SERIAL BELKIN F5U103 DRIVER
-P: William Greathouse
-M: wgreathouse@smva.com
-L: linux-usb@vger.kernel.org
-S: Maintained
-
-USB SERIAL CYPRESS M8 DRIVER
-P: Lonnie Mendez
-M: dignome@gmail.com
-L: linux-usb@vger.kernel.org
-S: Maintained
-W: http://geocities.com/i0xox0i
-W: http://firstlight.net/cvs
-
USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER
P: Gary Brubaker
M: xavyer@ix.netcom.com
@@ -4265,7 +4295,7 @@
L: linux-kernel@vger.kernel.org
S: Maintained
-FAT/VFAT/MSDOS FILESYSTEM:
+VFAT/FAT/MSDOS FILESYSTEM:
P: OGAWA Hirofumi
M: hirofumi@mail.parknet.co.jp
L: linux-kernel@vger.kernel.org
@@ -4310,6 +4340,13 @@
L: linux-kernel@vger.kernel.org
S: Maintained
+UltraSPARC (sparc64):
+P: David S. Miller
+M: davem@davemloft.net
+L: sparclinux@vger.kernel.org
+T: git kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6.git
+S: Maintained
+
USB DIAMOND RIO500 DRIVER
P: Cesar Miquel
M: miquel@df.uba.ar
diff --git a/Makefile b/Makefile
index d3634cd..5cf8258 100644
--- a/Makefile
+++ b/Makefile
@@ -794,7 +794,7 @@
quiet_cmd_vmlinux-modpost = LD $@
cmd_vmlinux-modpost = $(LD) $(LDFLAGS) -r -o $@ \
$(vmlinux-init) --start-group $(vmlinux-main) --end-group \
- $(filter-out $(vmlinux-init) $(vmlinux-main) $(vmlinux-lds) FORCE ,$^)
+ $(filter-out $(vmlinux-init) $(vmlinux-main) FORCE ,$^)
define rule_vmlinux-modpost
:
+$(call cmd,vmlinux-modpost)
@@ -818,7 +818,9 @@
ifdef CONFIG_KALLSYMS
.tmp_vmlinux1: vmlinux.o
endif
-vmlinux.o: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) FORCE
+
+modpost-init := $(filter-out init/built-in.o, $(vmlinux-init))
+vmlinux.o: $(modpost-init) $(vmlinux-main) FORCE
$(call if_changed_rule,vmlinux-modpost)
# The actual objects are generated when descending,
diff --git a/arch/Kconfig b/arch/Kconfig
index 694c9af..3ea332b 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -36,3 +36,6 @@
config HAVE_KRETPROBES
def_bool n
+
+config HAVE_DMA_ATTRS
+ def_bool n
diff --git a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
index 6c56c75..4b18cd9 100644
--- a/arch/alpha/kernel/asm-offsets.c
+++ b/arch/alpha/kernel/asm-offsets.c
@@ -8,13 +8,9 @@
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/ptrace.h>
+#include <linux/kbuild.h>
#include <asm/io.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
void foo(void)
{
DEFINE(TI_TASK, offsetof(struct thread_info, task));
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 9fee37e..32ca1b9 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -981,27 +981,18 @@
osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp,
struct timeval32 __user *tvp)
{
- fd_set_bits fds;
- char *bits;
- size_t size;
- long timeout;
- int ret = -EINVAL;
- struct fdtable *fdt;
- int max_fds;
-
- timeout = MAX_SCHEDULE_TIMEOUT;
+ s64 timeout = MAX_SCHEDULE_TIMEOUT;
if (tvp) {
time_t sec, usec;
if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp))
|| __get_user(sec, &tvp->tv_sec)
|| __get_user(usec, &tvp->tv_usec)) {
- ret = -EFAULT;
- goto out_nofds;
+ return -EFAULT;
}
if (sec < 0 || usec < 0)
- goto out_nofds;
+ return -EINVAL;
if ((unsigned long) sec < MAX_SELECT_SECONDS) {
timeout = (usec + 1000000/HZ - 1) / (1000000/HZ);
@@ -1009,60 +1000,8 @@
}
}
- rcu_read_lock();
- fdt = files_fdtable(current->files);
- max_fds = fdt->max_fds;
- rcu_read_unlock();
- if (n < 0 || n > max_fds)
- goto out_nofds;
-
- /*
- * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
- * since we used fdset we need to allocate memory in units of
- * long-words.
- */
- ret = -ENOMEM;
- size = FDS_BYTES(n);
- bits = kmalloc(6 * size, GFP_KERNEL);
- if (!bits)
- goto out_nofds;
- fds.in = (unsigned long *) bits;
- fds.out = (unsigned long *) (bits + size);
- fds.ex = (unsigned long *) (bits + 2*size);
- fds.res_in = (unsigned long *) (bits + 3*size);
- fds.res_out = (unsigned long *) (bits + 4*size);
- fds.res_ex = (unsigned long *) (bits + 5*size);
-
- if ((ret = get_fd_set(n, inp->fds_bits, fds.in)) ||
- (ret = get_fd_set(n, outp->fds_bits, fds.out)) ||
- (ret = get_fd_set(n, exp->fds_bits, fds.ex)))
- goto out;
- zero_fd_set(n, fds.res_in);
- zero_fd_set(n, fds.res_out);
- zero_fd_set(n, fds.res_ex);
-
- ret = do_select(n, &fds, &timeout);
-
/* OSF does not copy back the remaining time. */
-
- if (ret < 0)
- goto out;
- if (!ret) {
- ret = -ERESTARTNOHAND;
- if (signal_pending(current))
- goto out;
- ret = 0;
- }
-
- if (set_fd_set(n, inp->fds_bits, fds.res_in) ||
- set_fd_set(n, outp->fds_bits, fds.res_out) ||
- set_fd_set(n, exp->fds_bits, fds.res_ex))
- ret = -EFAULT;
-
- out:
- kfree(bits);
- out_nofds:
- return ret;
+ return core_sys_select(n, inp, outp, exp, &timeout);
}
struct rusage32 {
diff --git a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
index baf5756..36ab22a 100644
--- a/arch/alpha/kernel/pci.c
+++ b/arch/alpha/kernel/pci.c
@@ -514,8 +514,8 @@
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
diff --git a/arch/arm/configs/am200epdkit_defconfig b/arch/arm/configs/am200epdkit_defconfig
index dc030cf..5e68420 100644
--- a/arch/arm/configs/am200epdkit_defconfig
+++ b/arch/arm/configs/am200epdkit_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.25-rc3
-# Sun Mar 9 06:33:33 2008
+# Linux kernel version: 2.6.25
+# Sun Apr 20 00:29:49 2008
#
CONFIG_ARM=y
CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -51,7 +51,8 @@
# CONFIG_RT_GROUP_SCHED is not set
CONFIG_USER_SCHED=y
# CONFIG_CGROUP_SCHED is not set
-# CONFIG_SYSFS_DEPRECATED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
# CONFIG_RELAY is not set
# CONFIG_NAMESPACES is not set
# CONFIG_BLK_DEV_INITRD is not set
@@ -85,6 +86,7 @@
CONFIG_HAVE_OPROFILE=y
# CONFIG_KPROBES is not set
CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
@@ -115,7 +117,6 @@
CONFIG_DEFAULT_NOOP=y
CONFIG_DEFAULT_IOSCHED="noop"
CONFIG_CLASSIC_RCU=y
-# CONFIG_PREEMPT_RCU is not set
#
# System Type
@@ -320,8 +321,6 @@
CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_TCP_MD5SIG is not set
# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
@@ -383,7 +382,6 @@
CONFIG_IEEE80211_CRYPT_WEP=m
# CONFIG_IEEE80211_CRYPT_CCMP is not set
# CONFIG_IEEE80211_CRYPT_TKIP is not set
-# CONFIG_IEEE80211_SOFTMAC is not set
# CONFIG_RFKILL is not set
# CONFIG_NET_9P is not set
@@ -503,7 +501,7 @@
CONFIG_BLK_DEV_IDE=m
#
-# Please see Documentation/ide.txt for help/info on IDE drives
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
#
# CONFIG_BLK_DEV_IDE_SATA is not set
CONFIG_BLK_DEV_IDEDISK=m
@@ -518,10 +516,9 @@
#
# IDE chipset support/bugfixes
#
-CONFIG_IDE_GENERIC=m
# CONFIG_BLK_DEV_PLATFORM is not set
# CONFIG_BLK_DEV_IDEDMA is not set
-CONFIG_IDE_ARCH_OBSOLETE_INIT=y
+# CONFIG_BLK_DEV_HD_ONLY is not set
# CONFIG_BLK_DEV_HD is not set
#
@@ -562,6 +559,7 @@
#
# CONFIG_WLAN_PRE80211 is not set
# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
# CONFIG_NET_PCMCIA is not set
# CONFIG_WAN is not set
# CONFIG_PPP is not set
@@ -707,6 +705,8 @@
#
# CONFIG_MFD_SM501 is not set
# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
#
# Multimedia devices
@@ -745,6 +745,7 @@
CONFIG_FB_PXA=y
CONFIG_FB_PXA_PARAMETERS=y
CONFIG_FB_MBX=m
+# CONFIG_FB_METRONOME is not set
CONFIG_FB_VIRTUAL=m
# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
@@ -891,7 +892,6 @@
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_DNOTIFY is not set
CONFIG_INOTIFY=y
diff --git a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
index 0a0d247..4a88125 100644
--- a/arch/arm/kernel/asm-offsets.c
+++ b/arch/arm/kernel/asm-offsets.c
@@ -16,6 +16,7 @@
#include <asm/thread_info.h>
#include <asm/memory.h>
#include <asm/procinfo.h>
+#include <linux/kbuild.h>
/*
* Make sure that the compiler and target are compatible.
@@ -35,13 +36,6 @@
#error Known good compilers: 3.3
#endif
-/* Use marker if you need to separate the values later */
-
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
int main(void)
{
DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
diff --git a/arch/arm/kernel/atags.c b/arch/arm/kernel/atags.c
index e2e934c..64c4208 100644
--- a/arch/arm/kernel/atags.c
+++ b/arch/arm/kernel/atags.c
@@ -35,7 +35,7 @@
{
struct proc_dir_entry* tags_entry;
- tags_entry = create_proc_read_entry("atags", 0400, &proc_root, read_buffer, &tags_buffer);
+ tags_entry = create_proc_read_entry("atags", 0400, NULL, read_buffer, &tags_buffer);
if (!tags_entry)
return -ENOMEM;
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index f56d48c..a53c0ab 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -37,6 +37,7 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/device.h>
#include <linux/init.h>
#include <linux/mutex.h>
@@ -723,17 +724,14 @@
return address;
}
-static int ecard_prints(char *buffer, ecard_t *ec)
+static int ecard_prints(struct seq_file *m, ecard_t *ec)
{
- char *start = buffer;
-
- buffer += sprintf(buffer, " %d: %s ", ec->slot_no,
- ec->easi ? "EASI" : " ");
+ seq_printf(m, " %d: %s ", ec->slot_no, ec->easi ? "EASI" : " ");
if (ec->cid.id == 0) {
struct in_chunk_dir incd;
- buffer += sprintf(buffer, "[%04X:%04X] ",
+ seq_printf(m, "[%04X:%04X] ",
ec->cid.manufacturer, ec->cid.product);
if (!ec->card_desc && ec->cid.cd &&
@@ -744,43 +742,43 @@
strcpy((char *)ec->card_desc, incd.d.string);
}
- buffer += sprintf(buffer, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
+ seq_printf(m, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*");
} else
- buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id);
+ seq_printf(m, "Simple card %d\n", ec->cid.id);
- return buffer - start;
+ return 0;
}
-static int get_ecard_dev_info(char *buf, char **start, off_t pos, int count)
+static int ecard_devices_proc_show(struct seq_file *m, void *v)
{
ecard_t *ec = cards;
- off_t at = 0;
- int len, cnt;
- cnt = 0;
- while (ec && count > cnt) {
- len = ecard_prints(buf, ec);
- at += len;
- if (at >= pos) {
- if (!*start) {
- *start = buf + (pos - (at - len));
- cnt = at - pos;
- } else
- cnt += len;
- buf += len;
- }
+ while (ec) {
+ ecard_prints(m, ec);
ec = ec->next;
}
- return (count > cnt) ? cnt : count;
+ return 0;
}
+static int ecard_devices_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ecard_devices_proc_show, NULL);
+}
+
+static const struct file_operations bus_ecard_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = ecard_devices_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static struct proc_dir_entry *proc_bus_ecard_dir = NULL;
static void ecard_proc_init(void)
{
- proc_bus_ecard_dir = proc_mkdir("ecard", proc_bus);
- create_proc_info_entry("devices", 0, proc_bus_ecard_dir,
- get_ecard_dev_info);
+ proc_bus_ecard_dir = proc_mkdir("bus/ecard", NULL);
+ proc_create("devices", 0, proc_bus_ecard_dir, &bus_ecard_proc_fops);
}
#define ec_set_resource(ec,nr,st,sz) \
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c
index d51bc8b..b4565bb 100644
--- a/arch/arm/kernel/kprobes-decode.c
+++ b/arch/arm/kernel/kprobes-decode.c
@@ -1176,7 +1176,7 @@
* *S (bit 20) updates condition codes
* ADC/SBC/RSC reads the C flag
*/
- insn &= 0xfff00ff0; /* Rn = r0, Rd = r0 */
+ insn &= 0xfff00fff; /* Rn = r0, Rd = r0 */
asi->insn[0] = insn;
asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */
emulate_alu_imm_rwflags : emulate_alu_imm_rflags;
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c
index 13e371a..5593dd2 100644
--- a/arch/arm/kernel/kprobes.c
+++ b/arch/arm/kernel/kprobes.c
@@ -66,7 +66,7 @@
return -ENOMEM;
for (is = 0; is < MAX_INSN_SIZE; ++is)
p->ainsn.insn[is] = tmp_insn[is];
- flush_insns(&p->ainsn.insn, MAX_INSN_SIZE);
+ flush_insns(p->ainsn.insn, MAX_INSN_SIZE);
break;
case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */
diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c
index f1a80d7..be52674 100644
--- a/arch/arm/mach-at91/at91cap9_devices.c
+++ b/arch/arm/mach-at91/at91cap9_devices.c
@@ -246,7 +246,7 @@
}
mmc0_data = *data;
- at91_clock_associate("mci0_clk", &at91cap9_mmc1_device.dev, "mci_clk");
+ at91_clock_associate("mci0_clk", &at91cap9_mmc0_device.dev, "mci_clk");
platform_device_register(&at91cap9_mmc0_device);
} else { /* MCI1 */
/* CLK */
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index b6454c5..719667e 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -308,7 +308,7 @@
}
mmc0_data = *data;
- at91_clock_associate("mci0_clk", &at91sam9263_mmc1_device.dev, "mci_clk");
+ at91_clock_associate("mci0_clk", &at91sam9263_mmc0_device.dev, "mci_clk");
platform_device_register(&at91sam9263_mmc0_device);
} else { /* MCI1 */
/* CLK */
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
index 26fea4d..81f1ebb 100644
--- a/arch/arm/mach-at91/board-csb337.c
+++ b/arch/arm/mach-at91/board-csb337.c
@@ -79,8 +79,7 @@
static struct i2c_board_info __initdata csb337_i2c_devices[] = {
{
- I2C_BOARD_INFO("rtc-ds1307", 0x68),
- .type = "ds1307",
+ I2C_BOARD_INFO("ds1307", 0x68),
},
};
diff --git a/arch/arm/mach-at91/board-dk.c b/arch/arm/mach-at91/board-dk.c
index 0a897ef..c1a813c 100644
--- a/arch/arm/mach-at91/board-dk.c
+++ b/arch/arm/mach-at91/board-dk.c
@@ -132,8 +132,7 @@
I2C_BOARD_INFO("x9429", 0x28),
},
{
- I2C_BOARD_INFO("at24c", 0x50),
- .type = "24c1024",
+ I2C_BOARD_INFO("24c1024", 0x50),
}
};
diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
index b7b79bb..af1a1d8 100644
--- a/arch/arm/mach-at91/board-eb9200.c
+++ b/arch/arm/mach-at91/board-eb9200.c
@@ -93,8 +93,7 @@
static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
{
- I2C_BOARD_INFO("at24c", 0x50),
- .type = "24c512",
+ I2C_BOARD_INFO("24c512", 0x50),
},
};
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 39733b6..aa863c1 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -61,6 +61,15 @@
#else
#include <asm/arch/at91sam9_sdramc.h>
+#ifdef CONFIG_ARCH_AT91SAM9263
+/*
+ * FIXME either or both the SDRAM controllers (EB0, EB1) might be in use;
+ * handle those cases both here and in the Suspend-To-RAM support.
+ */
+#define AT91_SDRAMC AT91_SDRAMC0
+#warning Assuming EB1 SDRAM controller is *NOT* used
+#endif
+
static u32 saved_lpr;
static inline void sdram_selfrefresh_enable(void)
@@ -75,11 +84,6 @@
#define sdram_selfrefresh_disable() at91_sys_write(AT91_SDRAMC_LPR, saved_lpr)
-/*
- * FIXME: The AT91SAM9263 has a second EBI controller which may have
- * additional SDRAM. pm_slowclock.S will require a similar fix.
- */
-
#endif
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 4143828..c6b94f6 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -311,11 +311,7 @@
static int __init davinci_ck_proc_init(void)
{
- struct proc_dir_entry *entry;
-
- entry = create_proc_entry("davinci_clocks", 0, NULL);
- if (entry)
- entry->proc_fops = &proc_davinci_ck_operations;
+ proc_create("davinci_clocks", 0, NULL, &proc_davinci_ck_operations);
return 0;
}
diff --git a/arch/arm/mach-iop32x/em7210.c b/arch/arm/mach-iop32x/em7210.c
index c947152..4877597 100644
--- a/arch/arm/mach-iop32x/em7210.c
+++ b/arch/arm/mach-iop32x/em7210.c
@@ -50,8 +50,7 @@
*/
static struct i2c_board_info __initdata em7210_i2c_devices[] = {
{
- I2C_BOARD_INFO("rtc-rs5c372", 0x32),
- .type = "rs5c372a",
+ I2C_BOARD_INFO("rs5c372a", 0x32),
},
};
diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c
index d2a7b04..d4fca75 100644
--- a/arch/arm/mach-iop32x/glantank.c
+++ b/arch/arm/mach-iop32x/glantank.c
@@ -176,12 +176,10 @@
static struct i2c_board_info __initdata glantank_i2c_devices[] = {
{
- I2C_BOARD_INFO("rtc-rs5c372", 0x32),
- .type = "rs5c372a",
+ I2C_BOARD_INFO("rs5c372a", 0x32),
},
{
I2C_BOARD_INFO("f75375", 0x2e),
- .type = "f75375",
.platform_data = &glantank_f75375s,
},
};
diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c
index bc91d6e..2741063 100644
--- a/arch/arm/mach-iop32x/n2100.c
+++ b/arch/arm/mach-iop32x/n2100.c
@@ -208,12 +208,10 @@
static struct i2c_board_info __initdata n2100_i2c_devices[] = {
{
- I2C_BOARD_INFO("rtc-rs5c372", 0x32),
- .type = "rs5c372b",
+ I2C_BOARD_INFO("rs5c372b", 0x32),
},
{
I2C_BOARD_INFO("f75375", 0x2e),
- .type = "f75375",
.platform_data = &n2100_f75375s,
},
};
diff --git a/arch/arm/mach-ixp4xx/dsmg600-setup.c b/arch/arm/mach-ixp4xx/dsmg600-setup.c
index 8cb0743..a51bfa6 100644
--- a/arch/arm/mach-ixp4xx/dsmg600-setup.c
+++ b/arch/arm/mach-ixp4xx/dsmg600-setup.c
@@ -65,7 +65,7 @@
static struct i2c_board_info __initdata dsmg600_i2c_board_info [] = {
{
- I2C_BOARD_INFO("rtc-pcf8563", 0x51),
+ I2C_BOARD_INFO("pcf8563", 0x51),
},
};
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_npe.c b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
index 83c137e..63a23fa 100644
--- a/arch/arm/mach-ixp4xx/ixp4xx_npe.c
+++ b/arch/arm/mach-ixp4xx/ixp4xx_npe.c
@@ -448,7 +448,9 @@
return -ETIMEDOUT;
}
+#if DEBUG_MSG > 1
debug_msg(npe, "Sending a message took %i cycles\n", cycles);
+#endif
return 0;
}
@@ -484,7 +486,9 @@
return -ETIMEDOUT;
}
+#if DEBUG_MSG > 1
debug_msg(npe, "Receiving a message took %i cycles\n", cycles);
+#endif
return 0;
}
diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
index e833013..fab94ea 100644
--- a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
+++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c
@@ -184,6 +184,8 @@
case 3: mask[0] = 0xFF; break;
}
+ mask[1] = mask[2] = mask[3] = 0;
+
while (addr--)
shift_mask(mask);
diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c
index 159e1c4..84b5e62 100644
--- a/arch/arm/mach-ixp4xx/nas100d-setup.c
+++ b/arch/arm/mach-ixp4xx/nas100d-setup.c
@@ -54,7 +54,7 @@
static struct i2c_board_info __initdata nas100d_i2c_board_info [] = {
{
- I2C_BOARD_INFO("rtc-pcf8563", 0x51),
+ I2C_BOARD_INFO("pcf8563", 0x51),
},
};
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index d9a1828..a48a665 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -57,7 +57,7 @@
static struct i2c_board_info __initdata nslu2_i2c_board_info [] = {
{
- I2C_BOARD_INFO("rtc-x1205", 0x6f),
+ I2C_BOARD_INFO("x1205", 0x6f),
},
};
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 5079877..4b444fd 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -351,11 +351,9 @@
static struct i2c_board_info __initdata h2_i2c_board_info[] = {
{
I2C_BOARD_INFO("tps65010", 0x48),
- .type = "tps65010",
.irq = OMAP_GPIO_IRQ(58),
}, {
I2C_BOARD_INFO("isp1301_omap", 0x2d),
- .type = "isp1301_omap",
.irq = OMAP_GPIO_IRQ(2),
},
};
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index c3ef1ee..7fbaa8d 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -473,8 +473,7 @@
static struct i2c_board_info __initdata h3_i2c_board_info[] = {
{
- I2C_BOARD_INFO("tps65010", 0x48),
- .type = "tps65013",
+ I2C_BOARD_INFO("tps65013", 0x48),
/* .irq = OMAP_GPIO_IRQ(??), */
},
};
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index 4f9baba..a66505f 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -254,7 +254,6 @@
static struct i2c_board_info __initdata osk_i2c_board_info[] = {
{
I2C_BOARD_INFO("tps65010", 0x48),
- .type = "tps65010",
.irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1)),
.platform_data = &tps_board,
diff --git a/arch/arm/mach-orion5x/addr-map.c b/arch/arm/mach-orion5x/addr-map.c
index 6b17937..9608503 100644
--- a/arch/arm/mach-orion5x/addr-map.c
+++ b/arch/arm/mach-orion5x/addr-map.c
@@ -19,14 +19,14 @@
/*
* The Orion has fully programable address map. There's a separate address
- * map for each of the device _master_ interfaces, e.g. CPU, PCI, PCIE, USB,
+ * map for each of the device _master_ interfaces, e.g. CPU, PCI, PCIe, USB,
* Gigabit Ethernet, DMA/XOR engines, etc. Each interface has its own
* address decode windows that allow it to access any of the Orion resources.
*
* CPU address decoding --
* Linux assumes that it is the boot loader that already setup the access to
* DDR and internal registers.
- * Setup access to PCI and PCI-E IO/MEM space is issued by this file.
+ * Setup access to PCI and PCIe IO/MEM space is issued by this file.
* Setup access to various devices located on the device bus interface (e.g.
* flashes, RTC, etc) should be issued by machine-setup.c according to
* specific board population (by using orion5x_setup_*_win()).
diff --git a/arch/arm/mach-orion5x/common.c b/arch/arm/mach-orion5x/common.c
index 439c778..968deb5 100644
--- a/arch/arm/mach-orion5x/common.c
+++ b/arch/arm/mach-orion5x/common.c
@@ -132,7 +132,7 @@
static struct resource orion5x_ehci0_resources[] = {
{
.start = ORION5X_USB0_PHYS_BASE,
- .end = ORION5X_USB0_PHYS_BASE + SZ_4K,
+ .end = ORION5X_USB0_PHYS_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -145,7 +145,7 @@
static struct resource orion5x_ehci1_resources[] = {
{
.start = ORION5X_USB1_PHYS_BASE,
- .end = ORION5X_USB1_PHYS_BASE + SZ_4K,
+ .end = ORION5X_USB1_PHYS_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -317,7 +317,7 @@
****************************************************************************/
/*
- * Identify device ID and rev from PCIE configuration header space '0'.
+ * Identify device ID and rev from PCIe configuration header space '0'.
*/
static void __init orion5x_id(u32 *dev, u32 *rev, char **dev_name)
{
diff --git a/arch/arm/mach-orion5x/common.h b/arch/arm/mach-orion5x/common.h
index f4c4c9a..14adf8d 100644
--- a/arch/arm/mach-orion5x/common.h
+++ b/arch/arm/mach-orion5x/common.h
@@ -33,10 +33,9 @@
struct pci_bus;
void orion5x_pcie_id(u32 *dev, u32 *rev);
-int orion5x_pcie_local_bus_nr(void);
-int orion5x_pci_local_bus_nr(void);
int orion5x_pci_sys_setup(int nr, struct pci_sys_data *sys);
struct pci_bus *orion5x_pci_sys_scan_bus(int nr, struct pci_sys_data *sys);
+int orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin);
/*
* Valid GPIO pins according to MPP setup, used by machine-setup.
diff --git a/arch/arm/mach-orion5x/db88f5281-setup.c b/arch/arm/mach-orion5x/db88f5281-setup.c
index 872aed3..44c6434 100644
--- a/arch/arm/mach-orion5x/db88f5281-setup.c
+++ b/arch/arm/mach-orion5x/db88f5281-setup.c
@@ -241,14 +241,17 @@
static int __init db88f5281_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
- /*
- * PCIE IRQ is connected internally (not GPIO)
- */
- if (dev->bus->number == orion5x_pcie_local_bus_nr())
- return IRQ_ORION5X_PCIE0_INT;
+ int irq;
/*
- * PCI IRQs are connected via GPIOs
+ * Check for devices with hard-wired IRQs.
+ */
+ irq = orion5x_pci_map_irq(dev, slot, pin);
+ if (irq != -1)
+ return irq;
+
+ /*
+ * PCI IRQs are connected via GPIOs.
*/
switch (slot - DB88F5281_PCI_SLOT0_OFFS) {
case 0:
@@ -292,9 +295,7 @@
* RTC DS1339 on I2C bus
****************************************************************************/
static struct i2c_board_info __initdata db88f5281_i2c_rtc = {
- .driver_name = "rtc-ds1307",
- .type = "ds1339",
- .addr = 0x68,
+ I2C_BOARD_INFO("ds1339", 0x68),
};
/*****************************************************************************
diff --git a/arch/arm/mach-orion5x/dns323-setup.c b/arch/arm/mach-orion5x/dns323-setup.c
index d67790e..f9430f5 100644
--- a/arch/arm/mach-orion5x/dns323-setup.c
+++ b/arch/arm/mach-orion5x/dns323-setup.c
@@ -43,11 +43,16 @@
static int __init dns323_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
- /* PCI-E */
- if (dev->bus->number == orion5x_pcie_local_bus_nr())
- return IRQ_ORION5X_PCIE0_INT;
+ int irq;
- pr_err("%s: requested mapping for unknown bus\n", __func__);
+ /*
+ * Check for devices with hard-wired IRQs.
+ */
+ irq = orion5x_pci_map_irq(dev, slot, pin);
+ if (irq != -1)
+ return irq;
+
+ pr_err("%s: requested mapping for unknown device\n", __func__);
return -1;
}
@@ -220,19 +225,16 @@
static struct i2c_board_info __initdata dns323_i2c_devices[] = {
{
I2C_BOARD_INFO("g760a", 0x3e),
- .type = "g760a",
},
#if 0
/* this entry requires the new-style driver model lm75 driver,
* for the meantime "insmod lm75.ko force_lm75=0,0x48" is needed */
{
- I2C_BOARD_INFO("lm75", 0x48),
- .type = "g751",
+ I2C_BOARD_INFO("g751", 0x48),
},
#endif
{
- I2C_BOARD_INFO("rtc-m41t80", 0x68),
- .type = "m41t80",
+ I2C_BOARD_INFO("m41t80", 0x68),
}
};
@@ -253,9 +255,9 @@
*/
orion5x_setup_dev_boot_win(DNS323_NOR_BOOT_BASE, DNS323_NOR_BOOT_SIZE);
- /* DNS-323 has a Marvell 88X7042 SATA controller attached via PCIE
+ /* DNS-323 has a Marvell 88X7042 SATA controller attached via PCIe
*
- * Open a special address decode windows for the PCIE WA.
+ * Open a special address decode windows for the PCIe WA.
*/
orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE,
ORION5X_PCIE_WA_SIZE);
diff --git a/arch/arm/mach-orion5x/kurobox_pro-setup.c b/arch/arm/mach-orion5x/kurobox_pro-setup.c
index 9141345..8841086 100644
--- a/arch/arm/mach-orion5x/kurobox_pro-setup.c
+++ b/arch/arm/mach-orion5x/kurobox_pro-setup.c
@@ -120,13 +120,19 @@
static int __init kurobox_pro_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
+ int irq;
+
+ /*
+ * Check for devices with hard-wired IRQs.
+ */
+ irq = orion5x_pci_map_irq(dev, slot, pin);
+ if (irq != -1)
+ return irq;
+
/*
* PCI isn't used on the Kuro
*/
- if (dev->bus->number == orion5x_pcie_local_bus_nr())
- return IRQ_ORION5X_PCIE0_INT;
- else
- printk(KERN_ERR "kurobox_pro_pci_map_irq failed, unknown bus\n");
+ printk(KERN_ERR "kurobox_pro_pci_map_irq failed, unknown bus\n");
return -1;
}
@@ -162,9 +168,7 @@
* RTC 5C372a on I2C bus
****************************************************************************/
static struct i2c_board_info __initdata kurobox_pro_i2c_rtc = {
- .driver_name = "rtc-rs5c372",
- .type = "rs5c372a",
- .addr = 0x32,
+ I2C_BOARD_INFO("rs5c372a", 0x32),
};
/*****************************************************************************
@@ -193,7 +197,7 @@
orion5x_setup_dev0_win(KUROBOX_PRO_NAND_BASE, KUROBOX_PRO_NAND_SIZE);
/*
- * Open a special address decode windows for the PCIE WA.
+ * Open a special address decode windows for the PCIe WA.
*/
orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE,
ORION5X_PCIE_WA_SIZE);
diff --git a/arch/arm/mach-orion5x/pci.c b/arch/arm/mach-orion5x/pci.c
index fdf99fc..9d5d39f 100644
--- a/arch/arm/mach-orion5x/pci.c
+++ b/arch/arm/mach-orion5x/pci.c
@@ -41,11 +41,6 @@
*rev = orion_pcie_rev(PCIE_BASE);
}
-int __init orion5x_pcie_local_bus_nr(void)
-{
- return orion_pcie_get_local_bus_nr(PCIE_BASE);
-}
-
static int pcie_valid_config(int bus, int dev)
{
/*
@@ -269,7 +264,7 @@
*/
static DEFINE_SPINLOCK(orion5x_pci_lock);
-int orion5x_pci_local_bus_nr(void)
+static int orion5x_pci_local_bus_nr(void)
{
u32 conf = orion5x_read(PCI_P2P_CONF);
return((conf & PCI_P2P_BUS_MASK) >> PCI_P2P_BUS_OFFS);
@@ -557,3 +552,16 @@
return bus;
}
+
+int __init orion5x_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int bus = dev->bus->number;
+
+ /*
+ * PCIe endpoint?
+ */
+ if (bus < orion5x_pci_local_bus_nr())
+ return IRQ_ORION5X_PCIE0_INT;
+
+ return -1;
+}
diff --git a/arch/arm/mach-orion5x/rd88f5182-setup.c b/arch/arm/mach-orion5x/rd88f5182-setup.c
index 37e8b2d..81abc10 100644
--- a/arch/arm/mach-orion5x/rd88f5182-setup.c
+++ b/arch/arm/mach-orion5x/rd88f5182-setup.c
@@ -172,11 +172,14 @@
static int __init rd88f5182_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
+ int irq;
+
/*
- * PCI-E isn't used on the RD2
+ * Check for devices with hard-wired IRQs.
*/
- if (dev->bus->number == orion5x_pcie_local_bus_nr())
- return IRQ_ORION5X_PCIE0_INT;
+ irq = orion5x_pci_map_irq(dev, slot, pin);
+ if (irq != -1)
+ return irq;
/*
* PCI IRQs are connected via GPIOs
@@ -224,9 +227,7 @@
* RTC DS1338 on I2C bus
****************************************************************************/
static struct i2c_board_info __initdata rd88f5182_i2c_rtc = {
- .driver_name = "rtc-ds1307",
- .type = "ds1338",
- .addr = 0x68,
+ I2C_BOARD_INFO("ds1338", 0x68),
};
/*****************************************************************************
@@ -259,7 +260,7 @@
orion5x_setup_dev1_win(RD88F5182_NOR_BASE, RD88F5182_NOR_SIZE);
/*
- * Open a special address decode windows for the PCIE WA.
+ * Open a special address decode windows for the PCIe WA.
*/
orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE,
ORION5X_PCIE_WA_SIZE);
diff --git a/arch/arm/mach-orion5x/ts209-setup.c b/arch/arm/mach-orion5x/ts209-setup.c
index fd43863..9afb41e 100644
--- a/arch/arm/mach-orion5x/ts209-setup.c
+++ b/arch/arm/mach-orion5x/ts209-setup.c
@@ -141,14 +141,17 @@
static int __init qnap_ts209_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
- /*
- * PCIE IRQ is connected internally (not GPIO)
- */
- if (dev->bus->number == orion5x_pcie_local_bus_nr())
- return IRQ_ORION5X_PCIE0_INT;
+ int irq;
/*
- * PCI IRQs are connected via GPIOs
+ * Check for devices with hard-wired IRQs.
+ */
+ irq = orion5x_pci_map_irq(dev, slot, pin);
+ if (irq != -1)
+ return irq;
+
+ /*
+ * PCI IRQs are connected via GPIOs.
*/
switch (slot - QNAP_TS209_PCI_SLOT0_OFFS) {
case 0:
@@ -276,8 +279,7 @@
#define TS209_RTC_GPIO 3
static struct i2c_board_info __initdata qnap_ts209_i2c_rtc = {
- .driver_name = "rtc-s35390a",
- .addr = 0x30,
+ I2C_BOARD_INFO("s35390a", 0x30),
.irq = 0,
};
@@ -373,7 +375,7 @@
QNAP_TS209_NOR_BOOT_SIZE);
/*
- * Open a special address decode windows for the PCIE WA.
+ * Open a special address decode windows for the PCIe WA.
*/
orion5x_setup_pcie_wa_win(ORION5X_PCIE_WA_PHYS_BASE,
ORION5X_PCIE_WA_SIZE);
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 7cdcb45..6a83085 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -5,9 +5,9 @@
# Common support (must be linked before board specific support)
obj-y += clock.o devices.o generic.o irq.o dma.o \
time.o gpio.o
-obj-$(CONFIG_PXA25x) += pxa25x.o mfp-pxa2xx.o
-obj-$(CONFIG_PXA27x) += pxa27x.o mfp-pxa2xx.o
-obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp-pxa3xx.o smemc.o
+obj-$(CONFIG_PXA25x) += mfp-pxa2xx.o pxa25x.o
+obj-$(CONFIG_PXA27x) += mfp-pxa2xx.o pxa27x.o
+obj-$(CONFIG_PXA3xx) += mfp-pxa3xx.o pxa3xx.o smemc.o
obj-$(CONFIG_CPU_PXA300) += pxa300.o
obj-$(CONFIG_CPU_PXA320) += pxa320.o
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 331f29b..4461793 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -90,11 +90,6 @@
.pfn = __phys_to_pfn(0x40000000),
.length = 0x02000000,
.type = MT_DEVICE
- }, { /* LCD */
- .virtual = 0xf4000000,
- .pfn = __phys_to_pfn(0x44000000),
- .length = 0x00100000,
- .type = MT_DEVICE
}, { /* Mem Ctl */
.virtual = 0xf6000000,
.pfn = __phys_to_pfn(0x48000000),
diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c
index f01d185..bdf2397 100644
--- a/arch/arm/mach-pxa/gumstix.c
+++ b/arch/arm/mach-pxa/gumstix.c
@@ -40,6 +40,7 @@
#include <asm/arch/pxa-regs.h>
#include <asm/arch/pxa2xx-regs.h>
+#include <asm/arch/pxa2xx-gpio.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index 0339606..5306544 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -301,8 +301,7 @@
static struct pxafb_mach_info littleton_lcd_info = {
.modes = tpo_tdo24mtea1_modes,
.num_modes = 2,
- .lccr0 = LCCR0_Act,
- .lccr3 = LCCR3_HSP | LCCR3_VSP,
+ .lcd_conn = LCD_COLOR_TFT_16BPP,
.pxafb_lcd_power = littleton_lcd_power,
};
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index ca209c4..0993f4d 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -395,8 +395,8 @@
.num_modes = 1,
.cmap_inverse = 0,
.cmap_static = 0,
- .lccr0 = LCCR0_SDS,
- .lccr3 = LCCR3_PCP | LCCR3_Acb(255),
+ .lcd_conn = LCD_COLOR_DSTN_16BPP | LCD_PCLK_EDGE_FALL |
+ LCD_AC_BIAS_FREQ(255);
};
#define MMC_POLL_RATE msecs_to_jiffies(1000)
diff --git a/arch/arm/mach-pxa/magician.c b/arch/arm/mach-pxa/magician.c
index d70be75..badba06 100644
--- a/arch/arm/mach-pxa/magician.c
+++ b/arch/arm/mach-pxa/magician.c
@@ -114,6 +114,14 @@
GPIO82_CIF_DD_5,
GPIO84_CIF_FV,
GPIO85_CIF_LV,
+
+ /* Magician specific input GPIOs */
+ GPIO9_GPIO, /* unknown */
+ GPIO10_GPIO, /* GSM_IRQ */
+ GPIO13_GPIO, /* CPLD_IRQ */
+ GPIO107_GPIO, /* DS1WM_IRQ */
+ GPIO108_GPIO, /* GSM_READY */
+ GPIO115_GPIO, /* nPEN_IRQ */
};
/*
@@ -438,7 +446,7 @@
static struct platform_device pasic3;
-static struct pasic3_leds_machinfo __devinit pasic3_leds_info = {
+static struct pasic3_leds_machinfo pasic3_leds_info = {
.num_leds = ARRAY_SIZE(pasic3_leds),
.power_gpio = EGPIO_MAGICIAN_LED_POWER,
.leds = pasic3_leds,
@@ -543,9 +551,28 @@
static int magician_mci_init(struct device *dev,
irq_handler_t detect_irq, void *data)
{
- return request_irq(IRQ_MAGICIAN_SD, detect_irq,
+ int err;
+
+ err = request_irq(IRQ_MAGICIAN_SD, detect_irq,
IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
"MMC card detect", data);
+ if (err)
+ goto err_request_irq;
+ err = gpio_request(EGPIO_MAGICIAN_SD_POWER, "SD_POWER");
+ if (err)
+ goto err_request_power;
+ err = gpio_request(EGPIO_MAGICIAN_nSD_READONLY, "nSD_READONLY");
+ if (err)
+ goto err_request_readonly;
+
+ return 0;
+
+err_request_readonly:
+ gpio_free(EGPIO_MAGICIAN_SD_POWER);
+err_request_power:
+ free_irq(IRQ_MAGICIAN_SD, data);
+err_request_irq:
+ return err;
}
static void magician_mci_setpower(struct device *dev, unsigned int vdd)
@@ -562,6 +589,8 @@
static void magician_mci_exit(struct device *dev, void *data)
{
+ gpio_free(EGPIO_MAGICIAN_nSD_READONLY);
+ gpio_free(EGPIO_MAGICIAN_SD_POWER);
free_irq(IRQ_MAGICIAN_SD, data);
}
@@ -643,28 +672,42 @@
{
void __iomem *cpld;
int lcd_select;
+ int err;
+
+ gpio_request(GPIO13_MAGICIAN_CPLD_IRQ, "CPLD_IRQ");
+ gpio_request(GPIO107_MAGICIAN_DS1WM_IRQ, "DS1WM_IRQ");
pxa2xx_mfp_config(ARRAY_AND_SIZE(magician_pin_config));
platform_add_devices(devices, ARRAY_SIZE(devices));
+
+ err = gpio_request(GPIO83_MAGICIAN_nIR_EN, "nIR_EN");
+ if (!err) {
+ gpio_direction_output(GPIO83_MAGICIAN_nIR_EN, 1);
+ pxa_set_ficp_info(&magician_ficp_info);
+ }
pxa_set_i2c_info(NULL);
pxa_set_mci_info(&magician_mci_info);
pxa_set_ohci_info(&magician_ohci_info);
- pxa_set_ficp_info(&magician_ficp_info);
/* Check LCD type we have */
cpld = ioremap_nocache(PXA_CS3_PHYS, 0x1000);
if (cpld) {
u8 board_id = __raw_readb(cpld+0x14);
+ iounmap(cpld);
system_rev = board_id & 0x7;
lcd_select = board_id & 0x8;
- iounmap(cpld);
pr_info("LCD type: %s\n", lcd_select ? "Samsung" : "Toppoly");
- if (lcd_select && (system_rev < 3))
- pxa_gpio_mode(GPIO75_MAGICIAN_SAMSUNG_POWER_MD);
- pxa_gpio_mode(GPIO104_MAGICIAN_LCD_POWER_1_MD);
- pxa_gpio_mode(GPIO105_MAGICIAN_LCD_POWER_2_MD);
- pxa_gpio_mode(GPIO106_MAGICIAN_LCD_POWER_3_MD);
+ if (lcd_select && (system_rev < 3)) {
+ gpio_request(GPIO75_MAGICIAN_SAMSUNG_POWER, "SAMSUNG_POWER");
+ gpio_direction_output(GPIO75_MAGICIAN_SAMSUNG_POWER, 0);
+ }
+ gpio_request(GPIO104_MAGICIAN_LCD_POWER_1, "LCD_POWER_1");
+ gpio_request(GPIO105_MAGICIAN_LCD_POWER_2, "LCD_POWER_2");
+ gpio_request(GPIO106_MAGICIAN_LCD_POWER_3, "LCD_POWER_3");
+ gpio_direction_output(GPIO104_MAGICIAN_LCD_POWER_1, 0);
+ gpio_direction_output(GPIO105_MAGICIAN_LCD_POWER_2, 0);
+ gpio_direction_output(GPIO106_MAGICIAN_LCD_POWER_3, 0);
set_pxa_fb_info(lcd_select ? &samsung_info : &toppoly_info);
} else
pr_err("LCD detection: CPLD mapping failed\n");
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 18d47cf..7399fb3 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -434,8 +434,7 @@
static struct pxafb_mach_info mainstone_pxafb_info = {
.num_modes = 1,
- .lccr0 = LCCR0_Act,
- .lccr3 = LCCR3_PCP,
+ .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
};
static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_int, void *data)
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index e6be9d0..49d951d 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -320,16 +320,13 @@
static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
{
/* Must initialize before the camera(s) */
- I2C_BOARD_INFO("pca953x", 0x41),
- .type = "pca9536",
+ I2C_BOARD_INFO("pca9536", 0x41),
.platform_data = &pca9536_data,
}, {
I2C_BOARD_INFO("mt9v022", 0x48),
- .type = "mt9v022",
.platform_data = &iclink[0], /* With extender */
}, {
I2C_BOARD_INFO("mt9m001", 0x5d),
- .type = "mt9m001",
.platform_data = &iclink[0], /* With extender */
},
};
diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
index 039194c..ec1bbf3 100644
--- a/arch/arm/mach-pxa/pm.c
+++ b/arch/arm/mach-pxa/pm.c
@@ -46,8 +46,8 @@
sleep_save_checksum += sleep_save[i];
}
- /* Clear sleep reset status */
- RCSR = RCSR_SMR;
+ /* Clear reset status */
+ RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
/* *** go zzz *** */
pxa_cpu_pm_fns->enter(state);
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index dde355e..b6a6f5f 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -486,6 +486,8 @@
case IRQ_MMC3:
mask = ADXER_MFP_GEN12;
break;
+ default:
+ return -EINVAL;
}
local_irq_save(flags);
diff --git a/arch/arm/mach-pxa/zylonite.c b/arch/arm/mach-pxa/zylonite.c
index dbb5462..4a00280 100644
--- a/arch/arm/mach-pxa/zylonite.c
+++ b/arch/arm/mach-pxa/zylonite.c
@@ -97,8 +97,7 @@
static struct pxafb_mach_info zylonite_toshiba_lcd_info = {
.num_modes = 1,
- .lccr0 = LCCR0_Act,
- .lccr3 = LCCR3_PCP,
+ .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
.pxafb_backlight_power = zylonite_backlight_power,
};
@@ -134,8 +133,7 @@
static struct pxafb_mach_info zylonite_sharp_lcd_info = {
.modes = sharp_ls037_modes,
.num_modes = 2,
- .lccr0 = LCCR0_Act,
- .lccr3 = LCCR3_PCP | LCCR3_HSP | LCCR3_VSP,
+ .lcd_conn = LCD_COLOR_TFT_16BPP | LCD_PCLK_EDGE_FALL,
.pxafb_backlight_power = zylonite_backlight_power,
};
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 1b8229d..33ed048 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -372,7 +372,7 @@
select CPU_PABRT_NOIFAR
select CPU_CACHE_VIVT
select CPU_CP15_MMU
- select CPU_COPY_V4WB if MMU
+ select CPU_COPY_FEROCEON if MMU
select CPU_TLB_V4WBI if MMU
config CPU_FEROCEON_OLD_ID
@@ -523,6 +523,9 @@
config CPU_COPY_V4WB
bool
+config CPU_COPY_FEROCEON
+ bool
+
config CPU_COPY_V6
bool
@@ -658,7 +661,7 @@
config CPU_DCACHE_WRITETHROUGH
bool "Force write through D-cache"
- depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_FEROCEON) && !CPU_DCACHE_DISABLE
+ depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020) && !CPU_DCACHE_DISABLE
default y if CPU_ARM925T
help
Say Y here to use the data cache in writethrough mode. Unless you
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 44536a0..32b2d2d 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -36,6 +36,7 @@
obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o
obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o
obj-$(CONFIG_CPU_COPY_V4WB) += copypage-v4wb.o
+obj-$(CONFIG_CPU_COPY_FEROCEON) += copypage-feroceon.o
obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o context.o
obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o
obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o
diff --git a/arch/arm/mm/copypage-feroceon.S b/arch/arm/mm/copypage-feroceon.S
new file mode 100644
index 0000000..7eb0d32
--- /dev/null
+++ b/arch/arm/mm/copypage-feroceon.S
@@ -0,0 +1,95 @@
+/*
+ * linux/arch/arm/lib/copypage-feroceon.S
+ *
+ * Copyright (C) 2008 Marvell Semiconductors
+ *
+ * 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 handles copy_user_page and clear_user_page on Feroceon
+ * more optimally than the generic implementations.
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/asm-offsets.h>
+
+ .text
+ .align 5
+
+ENTRY(feroceon_copy_user_page)
+ stmfd sp!, {r4-r9, lr}
+ mov ip, #PAGE_SZ
+1: mov lr, r1
+ ldmia r1!, {r2 - r9}
+ pld [lr, #32]
+ pld [lr, #64]
+ pld [lr, #96]
+ pld [lr, #128]
+ pld [lr, #160]
+ pld [lr, #192]
+ pld [lr, #224]
+ stmia r0, {r2 - r9}
+ ldmia r1!, {r2 - r9}
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
+ add r0, r0, #32
+ stmia r0, {r2 - r9}
+ ldmia r1!, {r2 - r9}
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
+ add r0, r0, #32
+ stmia r0, {r2 - r9}
+ ldmia r1!, {r2 - r9}
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
+ add r0, r0, #32
+ stmia r0, {r2 - r9}
+ ldmia r1!, {r2 - r9}
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
+ add r0, r0, #32
+ stmia r0, {r2 - r9}
+ ldmia r1!, {r2 - r9}
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
+ add r0, r0, #32
+ stmia r0, {r2 - r9}
+ ldmia r1!, {r2 - r9}
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
+ add r0, r0, #32
+ stmia r0, {r2 - r9}
+ ldmia r1!, {r2 - r9}
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
+ add r0, r0, #32
+ stmia r0, {r2 - r9}
+ subs ip, ip, #(32 * 8)
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
+ add r0, r0, #32
+ bne 1b
+ mcr p15, 0, ip, c7, c10, 4 @ drain WB
+ ldmfd sp!, {r4-r9, pc}
+
+ .align 5
+
+ENTRY(feroceon_clear_user_page)
+ stmfd sp!, {r4-r7, lr}
+ mov r1, #PAGE_SZ/32
+ mov r2, #0
+ mov r3, #0
+ mov r4, #0
+ mov r5, #0
+ mov r6, #0
+ mov r7, #0
+ mov ip, #0
+ mov lr, #0
+1: stmia r0, {r2-r7, ip, lr}
+ subs r1, r1, #1
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D line
+ add r0, r0, #32
+ bne 1b
+ mcr p15, 0, r1, c7, c10, 4 @ drain WB
+ ldmfd sp!, {r4-r7, pc}
+
+ __INITDATA
+
+ .type feroceon_user_fns, #object
+ENTRY(feroceon_user_fns)
+ .long feroceon_clear_user_page
+ .long feroceon_copy_user_page
+ .size feroceon_user_fns, . - feroceon_user_fns
diff --git a/arch/arm/mm/iomap.c b/arch/arm/mm/iomap.c
index 62066f3..7429f8c 100644
--- a/arch/arm/mm/iomap.c
+++ b/arch/arm/mm/iomap.c
@@ -26,8 +26,8 @@
#ifdef CONFIG_PCI
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index d41a75e..2d6d682 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -35,6 +35,7 @@
* zero-initialized data and COW.
*/
struct page *empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
/*
* The pmd table for the upper-most set of pages.
diff --git a/arch/arm/mm/proc-feroceon.S b/arch/arm/mm/proc-feroceon.S
index 90e7594..a02c171 100644
--- a/arch/arm/mm/proc-feroceon.S
+++ b/arch/arm/mm/proc-feroceon.S
@@ -93,7 +93,7 @@
*
* Called with IRQs disabled
*/
- .align 10
+ .align 5
ENTRY(cpu_feroceon_do_idle)
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ Drain write buffer
@@ -106,6 +106,7 @@
* Clean and invalidate all cache entries in a particular
* address space.
*/
+ .align 5
ENTRY(feroceon_flush_user_cache_all)
/* FALLTHROUGH */
@@ -118,12 +119,8 @@
mov r2, #VM_EXEC
mov ip, #0
__flush_whole_cache:
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
- mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
-#else
1: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate
bne 1b
-#endif
tst r2, #VM_EXEC
mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
mcrne p15, 0, ip, c7, c10, 4 @ drain WB
@@ -139,27 +136,19 @@
* - end - end address (exclusive)
* - flags - vm_flags describing address space
*/
+ .align 5
ENTRY(feroceon_flush_user_cache_range)
mov ip, #0
sub r3, r1, r0 @ calculate total size
cmp r3, #CACHE_DLIMIT
bgt __flush_whole_cache
1: tst r2, #VM_EXEC
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
- mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
- mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
- add r0, r0, #CACHE_DLINESIZE
- mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
- mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
- add r0, r0, #CACHE_DLINESIZE
-#else
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
add r0, r0, #CACHE_DLINESIZE
mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
add r0, r0, #CACHE_DLINESIZE
-#endif
cmp r0, r1
blo 1b
tst r2, #VM_EXEC
@@ -176,6 +165,7 @@
* - start - virtual start address
* - end - virtual end address
*/
+ .align 5
ENTRY(feroceon_coherent_kern_range)
/* FALLTHROUGH */
@@ -207,6 +197,7 @@
*
* - addr - page aligned address
*/
+ .align 5
ENTRY(feroceon_flush_kern_dcache_page)
add r1, r0, #PAGE_SZ
1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
@@ -231,13 +222,12 @@
*
* (same as v4wb)
*/
+ .align 5
ENTRY(feroceon_dma_inv_range)
-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
tst r0, #CACHE_DLINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
tst r1, #CACHE_DLINESIZE - 1
mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
-#endif
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
add r0, r0, #CACHE_DLINESIZE
@@ -256,14 +246,13 @@
*
* (same as v4wb)
*/
+ .align 5
ENTRY(feroceon_dma_clean_range)
-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
bic r0, r0, #CACHE_DLINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
-#endif
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
@@ -275,14 +264,10 @@
* - start - virtual start address
* - end - virtual end address
*/
+ .align 5
ENTRY(feroceon_dma_flush_range)
bic r0, r0, #CACHE_DLINESIZE - 1
-1:
-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
- mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
-#else
- mcr p15, 0, r0, c7, c10, 1 @ clean D entry
-#endif
+1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
add r0, r0, #CACHE_DLINESIZE
cmp r0, r1
blo 1b
@@ -300,13 +285,12 @@
.long feroceon_dma_clean_range
.long feroceon_dma_flush_range
+ .align 5
ENTRY(cpu_feroceon_dcache_clean_area)
-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHE_DLINESIZE
subs r1, r1, #CACHE_DLINESIZE
bhi 1b
-#endif
mcr p15, 0, r0, c7, c10, 4 @ drain WB
mov pc, lr
@@ -323,13 +307,9 @@
ENTRY(cpu_feroceon_switch_mm)
#ifdef CONFIG_MMU
mov ip, #0
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
- mcr p15, 0, ip, c7, c6, 0 @ invalidate D cache
-#else
@ && 'Clean & Invalidate whole DCache'
1: mrc p15, 0, r15, c7, c14, 3 @ test,clean,invalidate
bne 1b
-#endif
mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
mcr p15, 0, ip, c7, c10, 4 @ drain WB
mcr p15, 0, r0, c2, c0, 0 @ load page table pointer
@@ -362,16 +342,9 @@
tst r1, #L_PTE_PRESENT | L_PTE_YOUNG @ Present and Young?
movne r2, #0
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
- eor r3, r2, #0x0a @ C & small page?
- tst r3, #0x0b
- biceq r2, r2, #4
-#endif
str r2, [r0] @ hardware version
mov r0, r0
-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
mcr p15, 0, r0, c7, c10, 1 @ clean D entry
-#endif
mcr p15, 0, r0, c7, c10, 4 @ drain WB
#endif
mov pc, lr
@@ -387,20 +360,11 @@
mcr p15, 0, r0, c8, c7 @ invalidate I,D TLBs on v4
#endif
-
-#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
- mov r0, #4 @ disable write-back on caches explicitly
- mcr p15, 7, r0, c15, c0, 0
-#endif
-
adr r5, feroceon_crval
ldmia r5, {r5, r6}
mrc p15, 0, r0, c1, c0 @ get control register v4
bic r0, r0, r5
orr r0, r0, r6
-#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
- orr r0, r0, #0x4000 @ .1.. .... .... ....
-#endif
mov pc, lr
.size __feroceon_setup, . - __feroceon_setup
@@ -476,7 +440,7 @@
.long cpu_feroceon_name
.long feroceon_processor_functions
.long v4wbi_tlb_fns
- .long v4wb_user_fns
+ .long feroceon_user_fns
.long feroceon_cache_fns
.size __feroceon_old_id_proc_info, . - __feroceon_old_id_proc_info
#endif
@@ -502,6 +466,6 @@
.long cpu_feroceon_name
.long feroceon_processor_functions
.long v4wbi_tlb_fns
- .long v4wb_user_fns
+ .long feroceon_user_fns
.long feroceon_cache_fns
.size __feroceon_proc_info, . - __feroceon_proc_info
diff --git a/arch/arm/oprofile/op_model_mpcore.c b/arch/arm/oprofile/op_model_mpcore.c
index 75bae06..74fae60 100644
--- a/arch/arm/oprofile/op_model_mpcore.c
+++ b/arch/arm/oprofile/op_model_mpcore.c
@@ -51,7 +51,7 @@
/*
* MPCore SCU event monitor support
*/
-#define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_MPCORE_SCU_BASE + 0x10)
+#define SCU_EVENTMONITORS_VA_BASE __io_address(REALVIEW_EB11MP_SCU_BASE + 0x10)
/*
* Bitmask of used SCU counters
@@ -80,7 +80,7 @@
struct eventmonitor __iomem *emc = SCU_EVENTMONITORS_VA_BASE;
unsigned int cnt;
- cnt = irq - IRQ_PMU_SCU0;
+ cnt = irq - IRQ_EB11MP_PMU_SCU0;
oprofile_add_sample(get_irq_regs(), SCU_COUNTER(cnt));
scu_reset_counter(emc, cnt);
@@ -119,10 +119,10 @@
*/
for (i = 0; i < NUM_SCU_COUNTERS; i++) {
if (scu_em_used & (1 << i)) {
- ret = request_irq(IRQ_PMU_SCU0 + i, scu_em_interrupt, IRQF_DISABLED, "SCU PMU", NULL);
+ ret = request_irq(IRQ_EB11MP_PMU_SCU0 + i, scu_em_interrupt, IRQF_DISABLED, "SCU PMU", NULL);
if (ret) {
printk(KERN_ERR "oprofile: unable to request IRQ%u for SCU Event Monitor\n",
- IRQ_PMU_SCU0 + i);
+ IRQ_EB11MP_PMU_SCU0 + i);
goto err_free_scu;
}
}
@@ -153,7 +153,7 @@
err_free_scu:
while (i--)
- free_irq(IRQ_PMU_SCU0 + i, NULL);
+ free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL);
return ret;
}
@@ -175,7 +175,7 @@
for (i = 0; i < NUM_SCU_COUNTERS; i++) {
if (scu_em_used & (1 << i)) {
scu_reset_counter(emc, i);
- free_irq(IRQ_PMU_SCU0 + i, NULL);
+ free_irq(IRQ_EB11MP_PMU_SCU0 + i, NULL);
}
}
}
@@ -225,10 +225,10 @@
}
static int arm11_irqs[] = {
- [0] = IRQ_PMU_CPU0,
- [1] = IRQ_PMU_CPU1,
- [2] = IRQ_PMU_CPU2,
- [3] = IRQ_PMU_CPU3
+ [0] = IRQ_EB11MP_PMU_CPU0,
+ [1] = IRQ_EB11MP_PMU_CPU1,
+ [2] = IRQ_EB11MP_PMU_CPU2,
+ [3] = IRQ_EB11MP_PMU_CPU3
};
static int em_start(void)
@@ -273,22 +273,22 @@
/*
* Send SCU PMU interrupts to the "owner" CPU.
*/
- em_route_irq(IRQ_PMU_SCU0, 0);
- em_route_irq(IRQ_PMU_SCU1, 0);
- em_route_irq(IRQ_PMU_SCU2, 1);
- em_route_irq(IRQ_PMU_SCU3, 1);
- em_route_irq(IRQ_PMU_SCU4, 2);
- em_route_irq(IRQ_PMU_SCU5, 2);
- em_route_irq(IRQ_PMU_SCU6, 3);
- em_route_irq(IRQ_PMU_SCU7, 3);
+ em_route_irq(IRQ_EB11MP_PMU_SCU0, 0);
+ em_route_irq(IRQ_EB11MP_PMU_SCU1, 0);
+ em_route_irq(IRQ_EB11MP_PMU_SCU2, 1);
+ em_route_irq(IRQ_EB11MP_PMU_SCU3, 1);
+ em_route_irq(IRQ_EB11MP_PMU_SCU4, 2);
+ em_route_irq(IRQ_EB11MP_PMU_SCU5, 2);
+ em_route_irq(IRQ_EB11MP_PMU_SCU6, 3);
+ em_route_irq(IRQ_EB11MP_PMU_SCU7, 3);
/*
* Send CP15 PMU interrupts to the owner CPU.
*/
- em_route_irq(IRQ_PMU_CPU0, 0);
- em_route_irq(IRQ_PMU_CPU1, 1);
- em_route_irq(IRQ_PMU_CPU2, 2);
- em_route_irq(IRQ_PMU_CPU3, 3);
+ em_route_irq(IRQ_EB11MP_PMU_CPU0, 0);
+ em_route_irq(IRQ_EB11MP_PMU_CPU1, 1);
+ em_route_irq(IRQ_EB11MP_PMU_CPU2, 2);
+ em_route_irq(IRQ_EB11MP_PMU_CPU3, 3);
return 0;
}
diff --git a/arch/avr32/kernel/asm-offsets.c b/arch/avr32/kernel/asm-offsets.c
index 078cd33..e4796c6 100644
--- a/arch/avr32/kernel/asm-offsets.c
+++ b/arch/avr32/kernel/asm-offsets.c
@@ -5,14 +5,7 @@
*/
#include <linux/thread_info.h>
-
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
-#define OFFSET(sym, str, mem) \
- DEFINE(sym, offsetof(struct str, mem));
+#include <linux/kbuild.h>
void foo(void)
{
diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c
index b835257..cd12edb 100644
--- a/arch/avr32/mm/tlb.c
+++ b/arch/avr32/mm/tlb.c
@@ -369,11 +369,7 @@
static int __init proctlb_init(void)
{
- struct proc_dir_entry *entry;
-
- entry = create_proc_entry("tlb", 0, NULL);
- if (entry)
- entry->proc_fops = &proc_tlb_operations;
+ proc_create("tlb", 0, NULL, &proc_tlb_operations);
return 0;
}
late_initcall(proctlb_init);
diff --git a/arch/blackfin/kernel/asm-offsets.c b/arch/blackfin/kernel/asm-offsets.c
index b56b274..721f15f 100644
--- a/arch/blackfin/kernel/asm-offsets.c
+++ b/arch/blackfin/kernel/asm-offsets.c
@@ -34,8 +34,7 @@
#include <linux/hardirq.h>
#include <linux/irq.h>
#include <linux/thread_info.h>
-
-#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+#include <linux/kbuild.h>
int main(void)
{
diff --git a/arch/blackfin/kernel/signal.c b/arch/blackfin/kernel/signal.c
index d1fa244..cb9d883 100644
--- a/arch/blackfin/kernel/signal.c
+++ b/arch/blackfin/kernel/signal.c
@@ -212,7 +212,7 @@
/* Set up registers for signal handler */
wrusp((unsigned long)frame);
- if (get_personality & FDPIC_FUNCPTRS) {
+ if (current->personality & FDPIC_FUNCPTRS) {
struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor *) ka->sa.sa_handler;
__get_user(regs->pc, &funcptr->text);
diff --git a/arch/blackfin/mach-bf533/boards/stamp.c b/arch/blackfin/mach-bf533/boards/stamp.c
index fddce32..024f418 100644
--- a/arch/blackfin/mach-bf533/boards/stamp.c
+++ b/arch/blackfin/mach-bf533/boards/stamp.c
@@ -499,20 +499,17 @@
#if defined(CONFIG_JOYSTICK_AD7142) || defined(CONFIG_JOYSTICK_AD7142_MODULE)
{
I2C_BOARD_INFO("ad7142_joystick", 0x2C),
- .type = "ad7142_joystick",
.irq = 39,
},
#endif
#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
{
I2C_BOARD_INFO("pcf8574_lcd", 0x22),
- .type = "pcf8574_lcd",
},
#endif
#if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
{
I2C_BOARD_INFO("pcf8574_keypad", 0x27),
- .type = "pcf8574_keypad",
.irq = 39,
},
#endif
diff --git a/arch/blackfin/mach-bf537/boards/stamp.c b/arch/blackfin/mach-bf537/boards/stamp.c
index 0cec14b..d3727b7 100644
--- a/arch/blackfin/mach-bf537/boards/stamp.c
+++ b/arch/blackfin/mach-bf537/boards/stamp.c
@@ -751,20 +751,17 @@
#if defined(CONFIG_JOYSTICK_AD7142) || defined(CONFIG_JOYSTICK_AD7142_MODULE)
{
I2C_BOARD_INFO("ad7142_joystick", 0x2C),
- .type = "ad7142_joystick",
.irq = 55,
},
#endif
#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
{
I2C_BOARD_INFO("pcf8574_lcd", 0x22),
- .type = "pcf8574_lcd",
},
#endif
#if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
{
I2C_BOARD_INFO("pcf8574_keypad", 0x27),
- .type = "pcf8574_keypad",
.irq = 72,
},
#endif
diff --git a/arch/blackfin/mach-bf548/boards/ezkit.c b/arch/blackfin/mach-bf548/boards/ezkit.c
index 231dfbd3..b00f68a 100644
--- a/arch/blackfin/mach-bf548/boards/ezkit.c
+++ b/arch/blackfin/mach-bf548/boards/ezkit.c
@@ -641,13 +641,11 @@
#if defined(CONFIG_TWI_LCD) || defined(CONFIG_TWI_LCD_MODULE)
{
I2C_BOARD_INFO("pcf8574_lcd", 0x22),
- .type = "pcf8574_lcd",
},
#endif
#if defined(CONFIG_TWI_KEYPAD) || defined(CONFIG_TWI_KEYPAD_MODULE)
{
I2C_BOARD_INFO("pcf8574_keypad", 0x27),
- .type = "pcf8574_keypad",
.irq = 212,
},
#endif
diff --git a/arch/cris/kernel/profile.c b/arch/cris/kernel/profile.c
index aad0a9e..44f7b4f 100644
--- a/arch/cris/kernel/profile.c
+++ b/arch/cris/kernel/profile.c
@@ -75,9 +75,9 @@
sample_buffer_pos = sample_buffer;
- entry = create_proc_entry("system_profile", S_IWUSR | S_IRUGO, NULL);
+ entry = proc_create("system_profile", S_IWUSR | S_IRUGO, NULL,
+ &cris_proc_profile_operations);
if (entry) {
- entry->proc_fops = &cris_proc_profile_operations;
entry->size = SAMPLE_BUFFER_SIZE;
}
prof_running = 1;
diff --git a/arch/frv/kernel/asm-offsets.c b/arch/frv/kernel/asm-offsets.c
index fbb19fc..9de9684 100644
--- a/arch/frv/kernel/asm-offsets.c
+++ b/arch/frv/kernel/asm-offsets.c
@@ -7,15 +7,13 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/personality.h>
+#include <linux/kbuild.h>
#include <asm/registers.h>
#include <asm/ucontext.h>
#include <asm/processor.h>
#include <asm/thread_info.h>
#include <asm/gdb-stub.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
#define DEF_PTREG(sym, reg) \
asm volatile("\n->" #sym " %0 offsetof(struct pt_regs, " #reg ")" \
: : "i" (offsetof(struct pt_regs, reg)))
@@ -32,11 +30,6 @@
asm volatile("\n->" #sym " %0 offsetof(struct frv_frame0, " #reg ")" \
: : "i" (offsetof(struct frv_frame0, reg)))
-#define BLANK() asm volatile("\n->" : : )
-
-#define OFFSET(sym, str, mem) \
- DEFINE(sym, offsetof(struct str, mem));
-
void foo(void)
{
/* offsets into the thread_info structure */
diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c
index c57ce3f..73f3aee 100644
--- a/arch/frv/kernel/pm.c
+++ b/arch/frv/kernel/pm.c
@@ -163,14 +163,11 @@
if ((mode != 1) && (mode != 5))
return -EINVAL;
- retval = pm_send_all(PM_SUSPEND, (void *)3);
-
if (retval == 0) {
if (mode == 5)
retval = pm_do_bus_sleep();
else
retval = pm_do_suspend();
- pm_send_all(PM_RESUME, (void *)0);
}
return retval;
@@ -183,9 +180,6 @@
if (!(clock_cmodes_permitted & (1<<new_cmode)))
return -EINVAL;
- /* tell all the drivers we're suspending */
- pm_send_all(PM_SUSPEND, (void *)3);
-
/* now change cmode */
local_irq_disable();
frv_dma_pause_all();
@@ -201,8 +195,6 @@
frv_dma_resume_all();
local_irq_enable();
- /* tell all the drivers we're resuming */
- pm_send_all(PM_RESUME, (void *)0);
return 0;
}
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index d64bcaf..3bdb368 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -297,7 +297,7 @@
__frame->lr = (unsigned long) &frame->retcode;
__frame->gr8 = sig;
- if (get_personality & FDPIC_FUNCPTRS) {
+ if (current->personality & FDPIC_FUNCPTRS) {
struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor __user *) ka->sa.sa_handler;
__get_user(__frame->pc, &funcptr->text);
@@ -396,7 +396,7 @@
__frame->gr8 = sig;
__frame->gr9 = (unsigned long) &frame->info;
- if (get_personality & FDPIC_FUNCPTRS) {
+ if (current->personality & FDPIC_FUNCPTRS) {
struct fdpic_func_descriptor __user *funcptr =
(struct fdpic_func_descriptor __user *) ka->sa.sa_handler;
__get_user(__frame->pc, &funcptr->text);
diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c
index a40df80..1d2dfe6 100644
--- a/arch/frv/kernel/traps.c
+++ b/arch/frv/kernel/traps.c
@@ -362,11 +362,8 @@
#ifdef CONFIG_MMU
unsigned long fixup;
- if ((esr0 & ESRx_EC) == ESRx_EC_DATA_ACCESS)
- if (handle_misalignment(esr0, ear0, epcr0) == 0)
- return;
-
- if ((fixup = search_exception_table(__frame->pc)) != 0) {
+ fixup = search_exception_table(__frame->pc);
+ if (fixup) {
__frame->pc = fixup;
return;
}
diff --git a/arch/frv/mb93090-mb00/pci-iomap.c b/arch/frv/mb93090-mb00/pci-iomap.c
index 068fa04..35f6df2 100644
--- a/arch/frv/mb93090-mb00/pci-iomap.c
+++ b/arch/frv/mb93090-mb00/pci-iomap.c
@@ -13,8 +13,8 @@
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
diff --git a/arch/frv/mm/Makefile b/arch/frv/mm/Makefile
index fb8b1d8..1bca5ab 100644
--- a/arch/frv/mm/Makefile
+++ b/arch/frv/mm/Makefile
@@ -6,4 +6,4 @@
obj-$(CONFIG_MMU) += \
pgalloc.o highmem.o fault.o extable.o cache-page.o tlb-flush.o tlb-miss.o \
- mmu-context.o dma-alloc.o unaligned.o elf-fdpic.o
+ mmu-context.o dma-alloc.o elf-fdpic.o
diff --git a/arch/frv/mm/unaligned.c b/arch/frv/mm/unaligned.c
deleted file mode 100644
index 8f0375f..0000000
--- a/arch/frv/mm/unaligned.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/* unaligned.c: unalignment fixup handler for CPUs on which it is supported (FR451 only)
- *
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/types.h>
-#include <linux/user.h>
-#include <linux/string.h>
-#include <linux/linkage.h>
-#include <linux/init.h>
-
-#include <asm/setup.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
-#if 0
-#define kdebug(fmt, ...) printk("FDPIC "fmt"\n" ,##__VA_ARGS__ )
-#else
-#define kdebug(fmt, ...) do {} while(0)
-#endif
-
-#define _MA_SIGNED 0x01
-#define _MA_HALF 0x02
-#define _MA_WORD 0x04
-#define _MA_DWORD 0x08
-#define _MA_SZ_MASK 0x0e
-#define _MA_LOAD 0x10
-#define _MA_STORE 0x20
-#define _MA_UPDATE 0x40
-#define _MA_IMM 0x80
-
-#define _MA_LDxU _MA_LOAD | _MA_UPDATE
-#define _MA_LDxI _MA_LOAD | _MA_IMM
-#define _MA_STxU _MA_STORE | _MA_UPDATE
-#define _MA_STxI _MA_STORE | _MA_IMM
-
-static const uint8_t tbl_LDGRk_reg[0x40] = {
- [0x02] = _MA_LOAD | _MA_HALF | _MA_SIGNED, /* LDSH @(GRi,GRj),GRk */
- [0x03] = _MA_LOAD | _MA_HALF, /* LDUH @(GRi,GRj),GRk */
- [0x04] = _MA_LOAD | _MA_WORD, /* LD @(GRi,GRj),GRk */
- [0x05] = _MA_LOAD | _MA_DWORD, /* LDD @(GRi,GRj),GRk */
- [0x12] = _MA_LDxU | _MA_HALF | _MA_SIGNED, /* LDSHU @(GRi,GRj),GRk */
- [0x13] = _MA_LDxU | _MA_HALF, /* LDUHU @(GRi,GRj),GRk */
- [0x14] = _MA_LDxU | _MA_WORD, /* LDU @(GRi,GRj),GRk */
- [0x15] = _MA_LDxU | _MA_DWORD, /* LDDU @(GRi,GRj),GRk */
-};
-
-static const uint8_t tbl_STGRk_reg[0x40] = {
- [0x01] = _MA_STORE | _MA_HALF, /* STH @(GRi,GRj),GRk */
- [0x02] = _MA_STORE | _MA_WORD, /* ST @(GRi,GRj),GRk */
- [0x03] = _MA_STORE | _MA_DWORD, /* STD @(GRi,GRj),GRk */
- [0x11] = _MA_STxU | _MA_HALF, /* STHU @(GRi,GRj),GRk */
- [0x12] = _MA_STxU | _MA_WORD, /* STU @(GRi,GRj),GRk */
- [0x13] = _MA_STxU | _MA_DWORD, /* STDU @(GRi,GRj),GRk */
-};
-
-static const uint8_t tbl_LDSTGRk_imm[0x80] = {
- [0x31] = _MA_LDxI | _MA_HALF | _MA_SIGNED, /* LDSHI @(GRi,d12),GRk */
- [0x32] = _MA_LDxI | _MA_WORD, /* LDI @(GRi,d12),GRk */
- [0x33] = _MA_LDxI | _MA_DWORD, /* LDDI @(GRi,d12),GRk */
- [0x36] = _MA_LDxI | _MA_HALF, /* LDUHI @(GRi,d12),GRk */
- [0x51] = _MA_STxI | _MA_HALF, /* STHI @(GRi,d12),GRk */
- [0x52] = _MA_STxI | _MA_WORD, /* STI @(GRi,d12),GRk */
- [0x53] = _MA_STxI | _MA_DWORD, /* STDI @(GRi,d12),GRk */
-};
-
-
-/*****************************************************************************/
-/*
- * see if we can handle the exception by fixing up a misaligned memory access
- */
-int handle_misalignment(unsigned long esr0, unsigned long ear0, unsigned long epcr0)
-{
- unsigned long insn, addr, *greg;
- int GRi, GRj, GRk, D12, op;
-
- union {
- uint64_t _64;
- uint32_t _32[2];
- uint16_t _16;
- uint8_t _8[8];
- } x;
-
- if (!(esr0 & ESR0_EAV) || !(epcr0 & EPCR0_V) || !(ear0 & 7))
- return -EAGAIN;
-
- epcr0 &= EPCR0_PC;
-
- if (__frame->pc != epcr0) {
- kdebug("MISALIGN: Execution not halted on excepting instruction\n");
- BUG();
- }
-
- if (__get_user(insn, (unsigned long *) epcr0) < 0)
- return -EFAULT;
-
- /* determine the instruction type first */
- switch ((insn >> 18) & 0x7f) {
- case 0x2:
- /* LDx @(GRi,GRj),GRk */
- op = tbl_LDGRk_reg[(insn >> 6) & 0x3f];
- break;
-
- case 0x3:
- /* STx GRk,@(GRi,GRj) */
- op = tbl_STGRk_reg[(insn >> 6) & 0x3f];
- break;
-
- default:
- op = tbl_LDSTGRk_imm[(insn >> 18) & 0x7f];
- break;
- }
-
- if (!op)
- return -EAGAIN;
-
- kdebug("MISALIGN: pc=%08lx insn=%08lx ad=%08lx op=%02x\n", epcr0, insn, ear0, op);
-
- memset(&x, 0xba, 8);
-
- /* validate the instruction parameters */
- greg = (unsigned long *) &__frame->tbr;
-
- GRi = (insn >> 12) & 0x3f;
- GRk = (insn >> 25) & 0x3f;
-
- if (GRi > 31 || GRk > 31)
- return -ENOENT;
-
- if (op & _MA_DWORD && GRk & 1)
- return -EINVAL;
-
- if (op & _MA_IMM) {
- D12 = insn & 0xfff;
- asm ("slli %0,#20,%0 ! srai %0,#20,%0" : "=r"(D12) : "0"(D12)); /* sign extend */
- addr = (GRi ? greg[GRi] : 0) + D12;
- }
- else {
- GRj = (insn >> 0) & 0x3f;
- if (GRj > 31)
- return -ENOENT;
- addr = (GRi ? greg[GRi] : 0) + (GRj ? greg[GRj] : 0);
- }
-
- if (addr != ear0) {
- kdebug("MISALIGN: Calculated addr (%08lx) does not match EAR0 (%08lx)\n",
- addr, ear0);
- return -EFAULT;
- }
-
- /* check the address is okay */
- if (user_mode(__frame) && ___range_ok(ear0, 8) < 0)
- return -EFAULT;
-
- /* perform the memory op */
- if (op & _MA_STORE) {
- /* perform a store */
- x._32[0] = 0;
- if (GRk != 0) {
- if (op & _MA_HALF) {
- x._16 = greg[GRk];
- }
- else {
- x._32[0] = greg[GRk];
- }
- }
- if (op & _MA_DWORD)
- x._32[1] = greg[GRk + 1];
-
- kdebug("MISALIGN: Store GR%d { %08x:%08x } -> %08lx (%dB)\n",
- GRk, x._32[1], x._32[0], addr, op & _MA_SZ_MASK);
-
- if (__memcpy_user((void *) addr, &x, op & _MA_SZ_MASK) != 0)
- return -EFAULT;
- }
- else {
- /* perform a load */
- if (__memcpy_user(&x, (void *) addr, op & _MA_SZ_MASK) != 0)
- return -EFAULT;
-
- if (op & _MA_HALF) {
- if (op & _MA_SIGNED)
- asm ("slli %0,#16,%0 ! srai %0,#16,%0"
- : "=r"(x._32[0]) : "0"(x._16));
- else
- asm ("sethi #0,%0"
- : "=r"(x._32[0]) : "0"(x._16));
- }
-
- kdebug("MISALIGN: Load %08lx (%dB) -> GR%d, { %08x:%08x }\n",
- addr, op & _MA_SZ_MASK, GRk, x._32[1], x._32[0]);
-
- if (GRk != 0)
- greg[GRk] = x._32[0];
- if (op & _MA_DWORD)
- greg[GRk + 1] = x._32[1];
- }
-
- /* update the base pointer if required */
- if (op & _MA_UPDATE)
- greg[GRi] = addr;
-
- /* well... we've done that insn */
- __frame->pc = __frame->pc + 4;
-
- return 0;
-} /* end handle_misalignment() */
diff --git a/arch/h8300/kernel/asm-offsets.c b/arch/h8300/kernel/asm-offsets.c
index fc30b4f..2042552 100644
--- a/arch/h8300/kernel/asm-offsets.c
+++ b/arch/h8300/kernel/asm-offsets.c
@@ -13,15 +13,11 @@
#include <linux/kernel_stat.h>
#include <linux/ptrace.h>
#include <linux/hardirq.h>
+#include <linux/kbuild.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
int main(void)
{
/* offsets into the task struct */
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 3aa6c82..0df5f6f 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -19,6 +19,7 @@
select HAVE_OPROFILE
select HAVE_KPROBES
select HAVE_KRETPROBES
+ select HAVE_DMA_ATTRS
select HAVE_KVM
default y
help
@@ -47,6 +48,9 @@
config SWIOTLB
bool
+config IOMMU_HELPER
+ bool
+
config GENERIC_LOCKBREAK
bool
default y
@@ -615,7 +619,7 @@
default y
config IOMMU_HELPER
- def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC)
+ def_bool (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC || SWIOTLB)
source "arch/ia64/hp/sim/Kconfig"
diff --git a/arch/ia64/hp/common/hwsw_iommu.c b/arch/ia64/hp/common/hwsw_iommu.c
index 8f6bcfe..1c44ec2 100644
--- a/arch/ia64/hp/common/hwsw_iommu.c
+++ b/arch/ia64/hp/common/hwsw_iommu.c
@@ -20,10 +20,10 @@
extern int swiotlb_late_init_with_default_size (size_t size);
extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent;
extern ia64_mv_dma_free_coherent swiotlb_free_coherent;
-extern ia64_mv_dma_map_single swiotlb_map_single;
-extern ia64_mv_dma_unmap_single swiotlb_unmap_single;
-extern ia64_mv_dma_map_sg swiotlb_map_sg;
-extern ia64_mv_dma_unmap_sg swiotlb_unmap_sg;
+extern ia64_mv_dma_map_single_attrs swiotlb_map_single_attrs;
+extern ia64_mv_dma_unmap_single_attrs swiotlb_unmap_single_attrs;
+extern ia64_mv_dma_map_sg_attrs swiotlb_map_sg_attrs;
+extern ia64_mv_dma_unmap_sg_attrs swiotlb_unmap_sg_attrs;
extern ia64_mv_dma_supported swiotlb_dma_supported;
extern ia64_mv_dma_mapping_error swiotlb_dma_mapping_error;
@@ -31,19 +31,19 @@
extern ia64_mv_dma_alloc_coherent sba_alloc_coherent;
extern ia64_mv_dma_free_coherent sba_free_coherent;
-extern ia64_mv_dma_map_single sba_map_single;
-extern ia64_mv_dma_unmap_single sba_unmap_single;
-extern ia64_mv_dma_map_sg sba_map_sg;
-extern ia64_mv_dma_unmap_sg sba_unmap_sg;
+extern ia64_mv_dma_map_single_attrs sba_map_single_attrs;
+extern ia64_mv_dma_unmap_single_attrs sba_unmap_single_attrs;
+extern ia64_mv_dma_map_sg_attrs sba_map_sg_attrs;
+extern ia64_mv_dma_unmap_sg_attrs sba_unmap_sg_attrs;
extern ia64_mv_dma_supported sba_dma_supported;
extern ia64_mv_dma_mapping_error sba_dma_mapping_error;
#define hwiommu_alloc_coherent sba_alloc_coherent
#define hwiommu_free_coherent sba_free_coherent
-#define hwiommu_map_single sba_map_single
-#define hwiommu_unmap_single sba_unmap_single
-#define hwiommu_map_sg sba_map_sg
-#define hwiommu_unmap_sg sba_unmap_sg
+#define hwiommu_map_single_attrs sba_map_single_attrs
+#define hwiommu_unmap_single_attrs sba_unmap_single_attrs
+#define hwiommu_map_sg_attrs sba_map_sg_attrs
+#define hwiommu_unmap_sg_attrs sba_unmap_sg_attrs
#define hwiommu_dma_supported sba_dma_supported
#define hwiommu_dma_mapping_error sba_dma_mapping_error
#define hwiommu_sync_single_for_cpu machvec_dma_sync_single
@@ -98,41 +98,48 @@
}
dma_addr_t
-hwsw_map_single (struct device *dev, void *addr, size_t size, int dir)
+hwsw_map_single_attrs(struct device *dev, void *addr, size_t size, int dir,
+ struct dma_attrs *attrs)
{
if (use_swiotlb(dev))
- return swiotlb_map_single(dev, addr, size, dir);
+ return swiotlb_map_single_attrs(dev, addr, size, dir, attrs);
else
- return hwiommu_map_single(dev, addr, size, dir);
+ return hwiommu_map_single_attrs(dev, addr, size, dir, attrs);
}
+EXPORT_SYMBOL(hwsw_map_single_attrs);
void
-hwsw_unmap_single (struct device *dev, dma_addr_t iova, size_t size, int dir)
+hwsw_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
+ int dir, struct dma_attrs *attrs)
{
if (use_swiotlb(dev))
- return swiotlb_unmap_single(dev, iova, size, dir);
+ return swiotlb_unmap_single_attrs(dev, iova, size, dir, attrs);
else
- return hwiommu_unmap_single(dev, iova, size, dir);
+ return hwiommu_unmap_single_attrs(dev, iova, size, dir, attrs);
}
-
+EXPORT_SYMBOL(hwsw_unmap_single_attrs);
int
-hwsw_map_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir)
+hwsw_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents,
+ int dir, struct dma_attrs *attrs)
{
if (use_swiotlb(dev))
- return swiotlb_map_sg(dev, sglist, nents, dir);
+ return swiotlb_map_sg_attrs(dev, sglist, nents, dir, attrs);
else
- return hwiommu_map_sg(dev, sglist, nents, dir);
+ return hwiommu_map_sg_attrs(dev, sglist, nents, dir, attrs);
}
+EXPORT_SYMBOL(hwsw_map_sg_attrs);
void
-hwsw_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir)
+hwsw_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents,
+ int dir, struct dma_attrs *attrs)
{
if (use_swiotlb(dev))
- return swiotlb_unmap_sg(dev, sglist, nents, dir);
+ return swiotlb_unmap_sg_attrs(dev, sglist, nents, dir, attrs);
else
- return hwiommu_unmap_sg(dev, sglist, nents, dir);
+ return hwiommu_unmap_sg_attrs(dev, sglist, nents, dir, attrs);
}
+EXPORT_SYMBOL(hwsw_unmap_sg_attrs);
void
hwsw_sync_single_for_cpu (struct device *dev, dma_addr_t addr, size_t size, int dir)
@@ -185,10 +192,6 @@
}
EXPORT_SYMBOL(hwsw_dma_mapping_error);
-EXPORT_SYMBOL(hwsw_map_single);
-EXPORT_SYMBOL(hwsw_unmap_single);
-EXPORT_SYMBOL(hwsw_map_sg);
-EXPORT_SYMBOL(hwsw_unmap_sg);
EXPORT_SYMBOL(hwsw_dma_supported);
EXPORT_SYMBOL(hwsw_alloc_coherent);
EXPORT_SYMBOL(hwsw_free_coherent);
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index 9409de5..34421ae 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -899,16 +899,18 @@
}
/**
- * sba_map_single - map one buffer and return IOVA for DMA
+ * sba_map_single_attrs - map one buffer and return IOVA for DMA
* @dev: instance of PCI owned by the driver that's asking.
* @addr: driver buffer to map.
* @size: number of bytes to map in driver buffer.
* @dir: R/W or both.
+ * @attrs: optional dma attributes
*
* See Documentation/DMA-mapping.txt
*/
dma_addr_t
-sba_map_single(struct device *dev, void *addr, size_t size, int dir)
+sba_map_single_attrs(struct device *dev, void *addr, size_t size, int dir,
+ struct dma_attrs *attrs)
{
struct ioc *ioc;
dma_addr_t iovp;
@@ -932,7 +934,8 @@
** Device is bit capable of DMA'ing to the buffer...
** just return the PCI address of ptr
*/
- DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n",
+ DBG_BYPASS("sba_map_single_attrs() bypass mask/addr: "
+ "0x%lx/0x%lx\n",
to_pci_dev(dev)->dma_mask, pci_addr);
return pci_addr;
}
@@ -953,7 +956,7 @@
#ifdef ASSERT_PDIR_SANITY
spin_lock_irqsave(&ioc->res_lock, flags);
- if (sba_check_pdir(ioc,"Check before sba_map_single()"))
+ if (sba_check_pdir(ioc,"Check before sba_map_single_attrs()"))
panic("Sanity check failed");
spin_unlock_irqrestore(&ioc->res_lock, flags);
#endif
@@ -982,11 +985,12 @@
/* form complete address */
#ifdef ASSERT_PDIR_SANITY
spin_lock_irqsave(&ioc->res_lock, flags);
- sba_check_pdir(ioc,"Check after sba_map_single()");
+ sba_check_pdir(ioc,"Check after sba_map_single_attrs()");
spin_unlock_irqrestore(&ioc->res_lock, flags);
#endif
return SBA_IOVA(ioc, iovp, offset);
}
+EXPORT_SYMBOL(sba_map_single_attrs);
#ifdef ENABLE_MARK_CLEAN
static SBA_INLINE void
@@ -1013,15 +1017,17 @@
#endif
/**
- * sba_unmap_single - unmap one IOVA and free resources
+ * sba_unmap_single_attrs - unmap one IOVA and free resources
* @dev: instance of PCI owned by the driver that's asking.
* @iova: IOVA of driver buffer previously mapped.
* @size: number of bytes mapped in driver buffer.
* @dir: R/W or both.
+ * @attrs: optional dma attributes
*
* See Documentation/DMA-mapping.txt
*/
-void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir)
+void sba_unmap_single_attrs(struct device *dev, dma_addr_t iova, size_t size,
+ int dir, struct dma_attrs *attrs)
{
struct ioc *ioc;
#if DELAYED_RESOURCE_CNT > 0
@@ -1038,7 +1044,8 @@
/*
** Address does not fall w/in IOVA, must be bypassing
*/
- DBG_BYPASS("sba_unmap_single() bypass addr: 0x%lx\n", iova);
+ DBG_BYPASS("sba_unmap_single_atttrs() bypass addr: 0x%lx\n",
+ iova);
#ifdef ENABLE_MARK_CLEAN
if (dir == DMA_FROM_DEVICE) {
@@ -1087,7 +1094,7 @@
spin_unlock_irqrestore(&ioc->res_lock, flags);
#endif /* DELAYED_RESOURCE_CNT == 0 */
}
-
+EXPORT_SYMBOL(sba_unmap_single_attrs);
/**
* sba_alloc_coherent - allocate/map shared mem for DMA
@@ -1144,7 +1151,8 @@
* If device can't bypass or bypass is disabled, pass the 32bit fake
* device to map single to get an iova mapping.
*/
- *dma_handle = sba_map_single(&ioc->sac_only_dev->dev, addr, size, 0);
+ *dma_handle = sba_map_single_attrs(&ioc->sac_only_dev->dev, addr,
+ size, 0, NULL);
return addr;
}
@@ -1161,7 +1169,7 @@
*/
void sba_free_coherent (struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle)
{
- sba_unmap_single(dev, dma_handle, size, 0);
+ sba_unmap_single_attrs(dev, dma_handle, size, 0, NULL);
free_pages((unsigned long) vaddr, get_order(size));
}
@@ -1410,10 +1418,12 @@
* @sglist: array of buffer/length pairs
* @nents: number of entries in list
* @dir: R/W or both.
+ * @attrs: optional dma attributes
*
* See Documentation/DMA-mapping.txt
*/
-int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int dir)
+int sba_map_sg_attrs(struct device *dev, struct scatterlist *sglist, int nents,
+ int dir, struct dma_attrs *attrs)
{
struct ioc *ioc;
int coalesced, filled = 0;
@@ -1441,16 +1451,16 @@
/* Fast path single entry scatterlists. */
if (nents == 1) {
sglist->dma_length = sglist->length;
- sglist->dma_address = sba_map_single(dev, sba_sg_address(sglist), sglist->length, dir);
+ sglist->dma_address = sba_map_single_attrs(dev, sba_sg_address(sglist), sglist->length, dir, attrs);
return 1;
}
#ifdef ASSERT_PDIR_SANITY
spin_lock_irqsave(&ioc->res_lock, flags);
- if (sba_check_pdir(ioc,"Check before sba_map_sg()"))
+ if (sba_check_pdir(ioc,"Check before sba_map_sg_attrs()"))
{
sba_dump_sg(ioc, sglist, nents);
- panic("Check before sba_map_sg()");
+ panic("Check before sba_map_sg_attrs()");
}
spin_unlock_irqrestore(&ioc->res_lock, flags);
#endif
@@ -1479,10 +1489,10 @@
#ifdef ASSERT_PDIR_SANITY
spin_lock_irqsave(&ioc->res_lock, flags);
- if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
+ if (sba_check_pdir(ioc,"Check after sba_map_sg_attrs()"))
{
sba_dump_sg(ioc, sglist, nents);
- panic("Check after sba_map_sg()\n");
+ panic("Check after sba_map_sg_attrs()\n");
}
spin_unlock_irqrestore(&ioc->res_lock, flags);
#endif
@@ -1492,18 +1502,20 @@
return filled;
}
-
+EXPORT_SYMBOL(sba_map_sg_attrs);
/**
- * sba_unmap_sg - unmap Scatter/Gather list
+ * sba_unmap_sg_attrs - unmap Scatter/Gather list
* @dev: instance of PCI owned by the driver that's asking.
* @sglist: array of buffer/length pairs
* @nents: number of entries in list
* @dir: R/W or both.
+ * @attrs: optional dma attributes
*
* See Documentation/DMA-mapping.txt
*/
-void sba_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir)
+void sba_unmap_sg_attrs(struct device *dev, struct scatterlist *sglist,
+ int nents, int dir, struct dma_attrs *attrs)
{
#ifdef ASSERT_PDIR_SANITY
struct ioc *ioc;
@@ -1518,13 +1530,14 @@
ASSERT(ioc);
spin_lock_irqsave(&ioc->res_lock, flags);
- sba_check_pdir(ioc,"Check before sba_unmap_sg()");
+ sba_check_pdir(ioc,"Check before sba_unmap_sg_attrs()");
spin_unlock_irqrestore(&ioc->res_lock, flags);
#endif
while (nents && sglist->dma_length) {
- sba_unmap_single(dev, sglist->dma_address, sglist->dma_length, dir);
+ sba_unmap_single_attrs(dev, sglist->dma_address,
+ sglist->dma_length, dir, attrs);
sglist = sg_next(sglist);
nents--;
}
@@ -1533,11 +1546,12 @@
#ifdef ASSERT_PDIR_SANITY
spin_lock_irqsave(&ioc->res_lock, flags);
- sba_check_pdir(ioc,"Check after sba_unmap_sg()");
+ sba_check_pdir(ioc,"Check after sba_unmap_sg_attrs()");
spin_unlock_irqrestore(&ioc->res_lock, flags);
#endif
}
+EXPORT_SYMBOL(sba_unmap_sg_attrs);
/**************************************************************
*
@@ -1918,15 +1932,13 @@
static void __init
ioc_proc_init(void)
{
- struct proc_dir_entry *dir, *entry;
+ struct proc_dir_entry *dir;
dir = proc_mkdir("bus/mckinley", NULL);
if (!dir)
return;
- entry = create_proc_entry(ioc_list->name, 0, dir);
- if (entry)
- entry->proc_fops = &ioc_fops;
+ proc_create(ioc_list->name, 0, dir, &ioc_fops);
}
#endif
@@ -2166,10 +2178,6 @@
__setup("sbapagesize=",sba_page_override);
EXPORT_SYMBOL(sba_dma_mapping_error);
-EXPORT_SYMBOL(sba_map_single);
-EXPORT_SYMBOL(sba_unmap_single);
-EXPORT_SYMBOL(sba_map_sg);
-EXPORT_SYMBOL(sba_unmap_sg);
EXPORT_SYMBOL(sba_dma_supported);
EXPORT_SYMBOL(sba_alloc_coherent);
EXPORT_SYMBOL(sba_free_coherent);
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index eb0c32a..23cafc8 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -210,21 +210,23 @@
printk(KERN_ERR "simserial: do_softint called\n");
}
-static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+static int rs_put_char(struct tty_struct *tty, unsigned char ch)
{
struct async_struct *info = (struct async_struct *)tty->driver_data;
unsigned long flags;
- if (!tty || !info->xmit.buf) return;
+ if (!tty || !info->xmit.buf)
+ return 0;
local_irq_save(flags);
if (CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE) == 0) {
local_irq_restore(flags);
- return;
+ return 0;
}
info->xmit.buf[info->xmit.head] = ch;
info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
local_irq_restore(flags);
+ return 1;
}
static void transmit_chars(struct async_struct *info, int *intr_done)
@@ -621,7 +623,8 @@
* the line discipline to only process XON/XOFF characters.
*/
shutdown(info);
- if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty);
+ if (tty->ops->flush_buffer)
+ tty->ops->flush_buffer(tty);
if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty);
info->event = 0;
info->tty = NULL;
diff --git a/arch/ia64/ia32/ia32_signal.c b/arch/ia64/ia32/ia32_signal.c
index 256a7fa..b763ca1 100644
--- a/arch/ia64/ia32/ia32_signal.c
+++ b/arch/ia64/ia32/ia32_signal.c
@@ -463,7 +463,7 @@
current->state = TASK_INTERRUPTIBLE;
schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
return -ERESTARTNOHAND;
}
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index c7467f8..19709a0 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -966,7 +966,7 @@
fs_initcall(acpi_map_iosapics);
#endif /* CONFIG_ACPI_NUMA */
-int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
+int __ref acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
{
int err;
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c
index 230a6f9..c64a55a 100644
--- a/arch/ia64/kernel/asm-offsets.c
+++ b/arch/ia64/kernel/asm-offsets.c
@@ -9,7 +9,7 @@
#include <linux/sched.h>
#include <linux/pid.h>
#include <linux/clocksource.h>
-
+#include <linux/kbuild.h>
#include <asm-ia64/processor.h>
#include <asm-ia64/ptrace.h>
#include <asm-ia64/siginfo.h>
@@ -19,11 +19,6 @@
#include "../kernel/sigframe.h"
#include "../kernel/fsyscall_gtod_data.h"
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
void foo(void)
{
DEFINE(IA64_TASK_SIZE, sizeof (struct task_struct));
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 6dee579..7fd18f5 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -183,10 +183,10 @@
{
unsigned int irq;
extern void ia64_process_pending_intr(void);
- extern void ia64_disable_timer(void);
extern volatile int time_keeper_id;
- ia64_disable_timer();
+ /* Mask ITV to disable timer */
+ ia64_set_itv(1 << 16);
/*
* Find a new timesync master
diff --git a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
index 396004e..4547a20 100644
--- a/arch/ia64/kernel/palinfo.c
+++ b/arch/ia64/kernel/palinfo.c
@@ -1053,7 +1053,7 @@
return NOTIFY_OK;
}
-static struct notifier_block palinfo_cpu_notifier __cpuinitdata =
+static struct notifier_block __refdata palinfo_cpu_notifier =
{
.notifier_call = palinfo_cpu_callback,
.priority = 0,
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index c8e4037..c1ad27d 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -867,7 +867,7 @@
}
static pfm_context_t *
-pfm_context_alloc(void)
+pfm_context_alloc(int ctx_flags)
{
pfm_context_t *ctx;
@@ -878,6 +878,46 @@
ctx = kzalloc(sizeof(pfm_context_t), GFP_KERNEL);
if (ctx) {
DPRINT(("alloc ctx @%p\n", ctx));
+
+ /*
+ * init context protection lock
+ */
+ spin_lock_init(&ctx->ctx_lock);
+
+ /*
+ * context is unloaded
+ */
+ ctx->ctx_state = PFM_CTX_UNLOADED;
+
+ /*
+ * initialization of context's flags
+ */
+ ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
+ ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
+ ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
+ /*
+ * will move to set properties
+ * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
+ */
+
+ /*
+ * init restart semaphore to locked
+ */
+ init_completion(&ctx->ctx_restart_done);
+
+ /*
+ * activation is used in SMP only
+ */
+ ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
+ SET_LAST_CPU(ctx, -1);
+
+ /*
+ * initialize notification message queue
+ */
+ ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
+ init_waitqueue_head(&ctx->ctx_msgq_wait);
+ init_waitqueue_head(&ctx->ctx_zombieq);
+
}
return ctx;
}
@@ -2165,28 +2205,21 @@
};
-static int
-pfm_alloc_fd(struct file **cfile)
+static struct file *
+pfm_alloc_file(pfm_context_t *ctx)
{
- int fd, ret = 0;
- struct file *file = NULL;
- struct inode * inode;
+ struct file *file;
+ struct inode *inode;
+ struct dentry *dentry;
char name[32];
struct qstr this;
- fd = get_unused_fd();
- if (fd < 0) return -ENFILE;
-
- ret = -ENFILE;
-
- file = get_empty_filp();
- if (!file) goto out;
-
/*
* allocate a new inode
*/
inode = new_inode(pfmfs_mnt->mnt_sb);
- if (!inode) goto out;
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
DPRINT(("new inode ino=%ld @%p\n", inode->i_ino, inode));
@@ -2199,59 +2232,28 @@
this.len = strlen(name);
this.hash = inode->i_ino;
- ret = -ENOMEM;
-
/*
* allocate a new dcache entry
*/
- file->f_path.dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
- if (!file->f_path.dentry) goto out;
+ dentry = d_alloc(pfmfs_mnt->mnt_sb->s_root, &this);
+ if (!dentry) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
- file->f_path.dentry->d_op = &pfmfs_dentry_operations;
+ dentry->d_op = &pfmfs_dentry_operations;
+ d_add(dentry, inode);
- d_add(file->f_path.dentry, inode);
- file->f_path.mnt = mntget(pfmfs_mnt);
- file->f_mapping = inode->i_mapping;
+ file = alloc_file(pfmfs_mnt, dentry, FMODE_READ, &pfm_file_ops);
+ if (!file) {
+ dput(dentry);
+ return ERR_PTR(-ENFILE);
+ }
- file->f_op = &pfm_file_ops;
- file->f_mode = FMODE_READ;
file->f_flags = O_RDONLY;
- file->f_pos = 0;
+ file->private_data = ctx;
- /*
- * may have to delay until context is attached?
- */
- fd_install(fd, file);
-
- /*
- * the file structure we will use
- */
- *cfile = file;
-
- return fd;
-out:
- if (file) put_filp(file);
- put_unused_fd(fd);
- return ret;
-}
-
-static void
-pfm_free_fd(int fd, struct file *file)
-{
- struct files_struct *files = current->files;
- struct fdtable *fdt;
-
- /*
- * there ie no fd_uninstall(), so we do it here
- */
- spin_lock(&files->file_lock);
- fdt = files_fdtable(files);
- rcu_assign_pointer(fdt->fd[fd], NULL);
- spin_unlock(&files->file_lock);
-
- if (file)
- put_filp(file);
- put_unused_fd(fd);
+ return file;
}
static int
@@ -2475,6 +2477,7 @@
/* link buffer format and context */
ctx->ctx_buf_fmt = fmt;
+ ctx->ctx_fl_is_sampling = 1; /* assume record() is defined */
/*
* check if buffer format wants to use perfmon buffer allocation/mapping service
@@ -2669,78 +2672,45 @@
{
pfarg_context_t *req = (pfarg_context_t *)arg;
struct file *filp;
+ struct path path;
int ctx_flags;
+ int fd;
int ret;
/* let's check the arguments first */
ret = pfarg_is_sane(current, req);
- if (ret < 0) return ret;
+ if (ret < 0)
+ return ret;
ctx_flags = req->ctx_flags;
ret = -ENOMEM;
- ctx = pfm_context_alloc();
- if (!ctx) goto error;
+ fd = get_unused_fd();
+ if (fd < 0)
+ return fd;
- ret = pfm_alloc_fd(&filp);
- if (ret < 0) goto error_file;
+ ctx = pfm_context_alloc(ctx_flags);
+ if (!ctx)
+ goto error;
- req->ctx_fd = ctx->ctx_fd = ret;
+ filp = pfm_alloc_file(ctx);
+ if (IS_ERR(filp)) {
+ ret = PTR_ERR(filp);
+ goto error_file;
+ }
- /*
- * attach context to file
- */
- filp->private_data = ctx;
+ req->ctx_fd = ctx->ctx_fd = fd;
/*
* does the user want to sample?
*/
if (pfm_uuid_cmp(req->ctx_smpl_buf_id, pfm_null_uuid)) {
ret = pfm_setup_buffer_fmt(current, filp, ctx, ctx_flags, 0, req);
- if (ret) goto buffer_error;
+ if (ret)
+ goto buffer_error;
}
- /*
- * init context protection lock
- */
- spin_lock_init(&ctx->ctx_lock);
-
- /*
- * context is unloaded
- */
- ctx->ctx_state = PFM_CTX_UNLOADED;
-
- /*
- * initialization of context's flags
- */
- ctx->ctx_fl_block = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
- ctx->ctx_fl_system = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
- ctx->ctx_fl_is_sampling = ctx->ctx_buf_fmt ? 1 : 0; /* assume record() is defined */
- ctx->ctx_fl_no_msg = (ctx_flags & PFM_FL_OVFL_NO_MSG) ? 1: 0;
- /*
- * will move to set properties
- * ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
- */
-
- /*
- * init restart semaphore to locked
- */
- init_completion(&ctx->ctx_restart_done);
-
- /*
- * activation is used in SMP only
- */
- ctx->ctx_last_activation = PFM_INVALID_ACTIVATION;
- SET_LAST_CPU(ctx, -1);
-
- /*
- * initialize notification message queue
- */
- ctx->ctx_msgq_head = ctx->ctx_msgq_tail = 0;
- init_waitqueue_head(&ctx->ctx_msgq_wait);
- init_waitqueue_head(&ctx->ctx_zombieq);
-
DPRINT(("ctx=%p flags=0x%x system=%d notify_block=%d excl_idle=%d no_msg=%d ctx_fd=%d \n",
ctx,
ctx_flags,
@@ -2755,10 +2725,14 @@
*/
pfm_reset_pmu_state(ctx);
+ fd_install(fd, filp);
+
return 0;
buffer_error:
- pfm_free_fd(ctx->ctx_fd, filp);
+ path = filp->f_path;
+ put_filp(filp);
+ path_put(&path);
if (ctx->ctx_buf_fmt) {
pfm_buf_fmt_exit(ctx->ctx_buf_fmt, current, NULL, regs);
@@ -2767,6 +2741,7 @@
pfm_context_free(ctx);
error:
+ put_unused_fd(fd);
return ret;
}
@@ -6695,16 +6670,12 @@
/*
* create /proc/perfmon (mostly for debugging purposes)
*/
- perfmon_dir = create_proc_entry("perfmon", S_IRUGO, NULL);
+ perfmon_dir = proc_create("perfmon", S_IRUGO, NULL, &pfm_proc_fops);
if (perfmon_dir == NULL) {
printk(KERN_ERR "perfmon: cannot create /proc entry, perfmon disabled\n");
pmu_conf = NULL;
return -1;
}
- /*
- * install customized file operations for /proc/perfmon entry
- */
- perfmon_dir->proc_fops = &pfm_proc_fops;
/*
* create /proc/sys/kernel/perfmon (for debugging purposes)
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index a5ea817..58dcfac 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -183,7 +183,7 @@
#endif
/* deal with pending signal delivery */
- if (test_thread_flag(TIF_SIGPENDING)||test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (test_thread_flag(TIF_SIGPENDING))
ia64_do_signal(scr, in_syscall);
/* copy user rbs to kernel rbs */
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
index b11bb50..ecb9eb7 100644
--- a/arch/ia64/kernel/salinfo.c
+++ b/arch/ia64/kernel/salinfo.c
@@ -648,18 +648,16 @@
if (!dir)
continue;
- entry = create_proc_entry("event", S_IRUSR, dir);
+ entry = proc_create_data("event", S_IRUSR, dir,
+ &salinfo_event_fops, data);
if (!entry)
continue;
- entry->data = data;
- entry->proc_fops = &salinfo_event_fops;
*sdir++ = entry;
- entry = create_proc_entry("data", S_IRUSR | S_IWUSR, dir);
+ entry = proc_create_data("data", S_IRUSR | S_IWUSR, dir,
+ &salinfo_data_fops, data);
if (!entry)
continue;
- entry->data = data;
- entry->proc_fops = &salinfo_data_fops;
*sdir++ = entry;
/* we missed any events before now */
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index 5740296c..19c5a78 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -464,7 +464,7 @@
if (!user_mode(&scr->pt))
return;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = ¤t->saved_sigmask;
else
oldset = ¤t->blocked;
@@ -530,12 +530,13 @@
* continue to iterate in this loop so we can deliver the SIGSEGV...
*/
if (handle_signal(signr, &ka, &info, oldset, scr)) {
- /* a signal was successfully delivered; the saved
+ /*
+ * A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
- * clear the TIF_RESTORE_SIGMASK flag */
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ * clear the TS_RESTORE_SIGMASK flag.
+ */
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
return;
}
}
@@ -566,8 +567,8 @@
/* if there's no signal to deliver, we just put the saved sigmask
* back */
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
}
}
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index 9a9d4c4..983296f 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -98,8 +98,33 @@
spin_unlock_irq(&call_lock);
}
+static inline void
+handle_call_data(void)
+{
+ struct call_data_struct *data;
+ void (*func)(void *info);
+ void *info;
+ int wait;
+
+ /* release the 'pointer lock' */
+ data = (struct call_data_struct *)call_data;
+ func = data->func;
+ info = data->info;
+ wait = data->wait;
+
+ mb();
+ atomic_inc(&data->started);
+ /* At this point the structure may be gone unless wait is true. */
+ (*func)(info);
+
+ /* Notify the sending CPU that the task is done. */
+ mb();
+ if (wait)
+ atomic_inc(&data->finished);
+}
+
static void
-stop_this_cpu (void)
+stop_this_cpu(void)
{
/*
* Remove this CPU:
@@ -138,44 +163,21 @@
ops &= ~(1 << which);
switch (which) {
- case IPI_CALL_FUNC:
- {
- struct call_data_struct *data;
- void (*func)(void *info);
- void *info;
- int wait;
+ case IPI_CALL_FUNC:
+ handle_call_data();
+ break;
- /* release the 'pointer lock' */
- data = (struct call_data_struct *) call_data;
- func = data->func;
- info = data->info;
- wait = data->wait;
-
- mb();
- atomic_inc(&data->started);
- /*
- * At this point the structure may be gone unless
- * wait is true.
- */
- (*func)(info);
-
- /* Notify the sending CPU that the task is done. */
- mb();
- if (wait)
- atomic_inc(&data->finished);
- }
- break;
-
- case IPI_CPU_STOP:
+ case IPI_CPU_STOP:
stop_this_cpu();
break;
#ifdef CONFIG_KEXEC
- case IPI_KDUMP_CPU_STOP:
+ case IPI_KDUMP_CPU_STOP:
unw_init_running(kdump_cpu_freeze, NULL);
break;
#endif
- default:
- printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n", this_cpu, which);
+ default:
+ printk(KERN_CRIT "Unknown IPI on CPU %d: %lu\n",
+ this_cpu, which);
break;
}
} while (ops);
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 16483be..d7ad42b 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -873,7 +873,8 @@
u16 pltid;
pal_logical_to_physical_t info;
- if ((status = ia64_pal_logical_to_phys(-1, &info)) != PAL_STATUS_SUCCESS) {
+ status = ia64_pal_logical_to_phys(-1, &info);
+ if (status != PAL_STATUS_SUCCESS) {
if (status != PAL_STATUS_UNIMPLEMENTED) {
printk(KERN_ERR
"ia64_pal_logical_to_phys failed with %ld\n",
@@ -885,8 +886,13 @@
info.overview_cpp = 1;
info.overview_tpc = 1;
}
- if ((status = ia64_sal_physical_id_info(&pltid)) != PAL_STATUS_SUCCESS) {
- printk(KERN_ERR "ia64_sal_pltid failed with %ld\n", status);
+
+ status = ia64_sal_physical_id_info(&pltid);
+ if (status != PAL_STATUS_SUCCESS) {
+ if (status != PAL_STATUS_UNIMPLEMENTED)
+ printk(KERN_ERR
+ "ia64_sal_pltid failed with %ld\n",
+ status);
return;
}
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 48e15a5..8c73643 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -379,11 +379,6 @@
.name = "timer"
};
-void __devinit ia64_disable_timer(void)
-{
- ia64_set_itv(1 << 16);
-}
-
void __init
time_init (void)
{
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index a2484fc..26228e2 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -27,9 +27,20 @@
static struct ia64_cpu *sysfs_cpus;
-int arch_register_cpu(int num)
+void arch_fix_phys_package_id(int num, u32 slot)
{
-#if defined (CONFIG_ACPI) && defined (CONFIG_HOTPLUG_CPU)
+#ifdef CONFIG_SMP
+ if (cpu_data(num)->socket_id == -1)
+ cpu_data(num)->socket_id = slot;
+#endif
+}
+EXPORT_SYMBOL_GPL(arch_fix_phys_package_id);
+
+
+#ifdef CONFIG_HOTPLUG_CPU
+int __ref arch_register_cpu(int num)
+{
+#ifdef CONFIG_ACPI
/*
* If CPEI can be re-targetted or if this is not
* CPEI target, then it is hotpluggable
@@ -38,19 +49,21 @@
sysfs_cpus[num].cpu.hotpluggable = 1;
map_cpu_to_node(num, node_cpuid[num].nid);
#endif
-
return register_cpu(&sysfs_cpus[num].cpu, num);
}
-
-#ifdef CONFIG_HOTPLUG_CPU
+EXPORT_SYMBOL(arch_register_cpu);
void arch_unregister_cpu(int num)
{
unregister_cpu(&sysfs_cpus[num].cpu);
unmap_cpu_from_node(num, cpu_to_node(num));
}
-EXPORT_SYMBOL(arch_register_cpu);
EXPORT_SYMBOL(arch_unregister_cpu);
+#else
+static int __init arch_register_cpu(int num)
+{
+ return register_cpu(&sysfs_cpus[num].cpu, num);
+}
#endif /*CONFIG_HOTPLUG_CPU*/
diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c
index 2a90c32..e77995a 100644
--- a/arch/ia64/kernel/uncached.c
+++ b/arch/ia64/kernel/uncached.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001-2006 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2008 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
@@ -177,12 +177,13 @@
* uncached_alloc_page
*
* @starting_nid: node id of node to start with, or -1
+ * @n_pages: number of contiguous pages to allocate
*
- * Allocate 1 uncached page. Allocates on the requested node. If no
- * uncached pages are available on the requested node, roundrobin starting
- * with the next higher node.
+ * Allocate the specified number of contiguous uncached pages on the
+ * the requested node. If not enough contiguous uncached pages are available
+ * on the requested node, roundrobin starting with the next higher node.
*/
-unsigned long uncached_alloc_page(int starting_nid)
+unsigned long uncached_alloc_page(int starting_nid, int n_pages)
{
unsigned long uc_addr;
struct uncached_pool *uc_pool;
@@ -202,7 +203,8 @@
if (uc_pool->pool == NULL)
continue;
do {
- uc_addr = gen_pool_alloc(uc_pool->pool, PAGE_SIZE);
+ uc_addr = gen_pool_alloc(uc_pool->pool,
+ n_pages * PAGE_SIZE);
if (uc_addr != 0)
return uc_addr;
} while (uncached_add_chunk(uc_pool, nid) == 0);
@@ -217,11 +219,12 @@
/*
* uncached_free_page
*
- * @uc_addr: uncached address of page to free
+ * @uc_addr: uncached address of first page to free
+ * @n_pages: number of contiguous pages to free
*
- * Free a single uncached page.
+ * Free the specified number of uncached pages.
*/
-void uncached_free_page(unsigned long uc_addr)
+void uncached_free_page(unsigned long uc_addr, int n_pages)
{
int nid = paddr_to_nid(uc_addr - __IA64_UNCACHED_OFFSET);
struct gen_pool *pool = uncached_pools[nid].pool;
@@ -232,7 +235,7 @@
if ((uc_addr & (0XFUL << 60)) != __IA64_UNCACHED_OFFSET)
panic("uncached_free_page invalid address %lx\n", uc_addr);
- gen_pool_free(pool, uc_addr, PAGE_SIZE);
+ gen_pool_free(pool, uc_addr, n_pages * PAGE_SIZE);
}
EXPORT_SYMBOL(uncached_free_page);
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 6df0732..318b811 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1,4 +1,3 @@
-
/*
* kvm_ia64.c: Basic KVM suppport On Itanium series processors
*
@@ -431,7 +430,7 @@
if (itc_diff < 0)
itc_diff = -itc_diff;
- expires = div64_64(itc_diff, cyc_per_usec);
+ expires = div64_u64(itc_diff, cyc_per_usec);
kt = ktime_set(0, 1000 * expires);
vcpu->arch.ht_active = 1;
hrtimer_start(p_ht, kt, HRTIMER_MODE_ABS);
diff --git a/arch/ia64/mm/tlb.c b/arch/ia64/mm/tlb.c
index d52ec4e..8caf424 100644
--- a/arch/ia64/mm/tlb.c
+++ b/arch/ia64/mm/tlb.c
@@ -168,7 +168,10 @@
static int firstcpu = 1;
if (toolatetochangeptcgsem) {
- BUG_ON(max_purges < nptcg);
+ if (nptcg_from == NPTCG_FROM_PAL && max_purges == 0)
+ BUG_ON(1 < nptcg);
+ else
+ BUG_ON(max_purges < nptcg);
return;
}
diff --git a/arch/ia64/sn/kernel/sn2/sn2_smp.c b/arch/ia64/sn/kernel/sn2/sn2_smp.c
index dfc6bf1..49d3120 100644
--- a/arch/ia64/sn/kernel/sn2/sn2_smp.c
+++ b/arch/ia64/sn/kernel/sn2/sn2_smp.c
@@ -550,11 +550,12 @@
if (!ia64_platform_is("sn2"))
return 0;
- if (!(proc_sn2_ptc = create_proc_entry(PTC_BASENAME, 0444, NULL))) {
+ proc_sn2_ptc = proc_create(PTC_BASENAME, 0444,
+ NULL, &proc_sn2_ptc_operations);
+ if (!&proc_sn2_ptc_operations) {
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;
}
diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
index 62b3e9a..2526e5c 100644
--- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
+++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c
@@ -139,30 +139,21 @@
void register_sn_procfs(void)
{
static struct proc_dir_entry *sgi_proc_dir = NULL;
- struct proc_dir_entry *pde;
BUG_ON(sgi_proc_dir != NULL);
if (!(sgi_proc_dir = proc_mkdir("sgi_sn", NULL)))
return;
- pde = create_proc_entry("partition_id", 0444, sgi_proc_dir);
- if (pde)
- pde->proc_fops = &proc_partition_id_fops;
- pde = create_proc_entry("system_serial_number", 0444, sgi_proc_dir);
- if (pde)
- pde->proc_fops = &proc_system_sn_fops;
- pde = create_proc_entry("licenseID", 0444, sgi_proc_dir);
- if (pde)
- pde->proc_fops = &proc_license_id_fops;
- pde = create_proc_entry("sn_force_interrupt", 0644, sgi_proc_dir);
- if (pde)
- pde->proc_fops = &proc_sn_force_intr_fops;
- pde = create_proc_entry("coherence_id", 0444, sgi_proc_dir);
- if (pde)
- pde->proc_fops = &proc_coherence_id_fops;
- pde = create_proc_entry("sn_topology", 0444, sgi_proc_dir);
- if (pde)
- pde->proc_fops = &proc_sn_topo_fops;
+ proc_create("partition_id", 0444, sgi_proc_dir,
+ &proc_partition_id_fops);
+ proc_create("system_serial_number", 0444, sgi_proc_dir,
+ &proc_system_sn_fops);
+ proc_create("licenseID", 0444, sgi_proc_dir, &proc_license_id_fops);
+ proc_create("sn_force_interrupt", 0644, sgi_proc_dir,
+ &proc_sn_force_intr_fops);
+ proc_create("coherence_id", 0444, sgi_proc_dir,
+ &proc_coherence_id_fops);
+ proc_create("sn_topology", 0444, sgi_proc_dir, &proc_sn_topo_fops);
}
#endif /* CONFIG_PROC_FS */
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
index 18b94b79..52175af 100644
--- a/arch/ia64/sn/pci/pci_dma.c
+++ b/arch/ia64/sn/pci/pci_dma.c
@@ -10,6 +10,7 @@
*/
#include <linux/module.h>
+#include <linux/dma-attrs.h>
#include <asm/dma.h>
#include <asm/sn/intr.h>
#include <asm/sn/pcibus_provider_defs.h>
@@ -149,11 +150,12 @@
EXPORT_SYMBOL(sn_dma_free_coherent);
/**
- * sn_dma_map_single - map a single page for DMA
+ * sn_dma_map_single_attrs - map a single page for DMA
* @dev: device to map for
* @cpu_addr: kernel virtual address of the region to map
* @size: size of the region
* @direction: DMA direction
+ * @attrs: optional dma attributes
*
* Map the region pointed to by @cpu_addr for DMA and return the
* DMA address.
@@ -163,42 +165,59 @@
* no way of saving the dmamap handle from the alloc to later free
* (which is pretty much unacceptable).
*
+ * mappings with the DMA_ATTR_WRITE_BARRIER get mapped with
+ * dma_map_consistent() so that writes force a flush of pending DMA.
+ * (See "SGI Altix Architecture Considerations for Linux Device Drivers",
+ * Document Number: 007-4763-001)
+ *
* TODO: simplify our interface;
* figure out how to save dmamap handle so can use two step.
*/
-dma_addr_t sn_dma_map_single(struct device *dev, void *cpu_addr, size_t size,
- int direction)
+dma_addr_t sn_dma_map_single_attrs(struct device *dev, void *cpu_addr,
+ size_t size, int direction,
+ struct dma_attrs *attrs)
{
dma_addr_t dma_addr;
unsigned long phys_addr;
struct pci_dev *pdev = to_pci_dev(dev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+ int dmabarr;
+
+ dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs);
BUG_ON(dev->bus != &pci_bus_type);
phys_addr = __pa(cpu_addr);
- dma_addr = provider->dma_map(pdev, phys_addr, size, SN_DMA_ADDR_PHYS);
+ if (dmabarr)
+ dma_addr = provider->dma_map_consistent(pdev, phys_addr,
+ size, SN_DMA_ADDR_PHYS);
+ else
+ dma_addr = provider->dma_map(pdev, phys_addr, size,
+ SN_DMA_ADDR_PHYS);
+
if (!dma_addr) {
printk(KERN_ERR "%s: out of ATEs\n", __func__);
return 0;
}
return dma_addr;
}
-EXPORT_SYMBOL(sn_dma_map_single);
+EXPORT_SYMBOL(sn_dma_map_single_attrs);
/**
- * sn_dma_unmap_single - unamp a DMA mapped page
+ * sn_dma_unmap_single_attrs - unamp a DMA mapped page
* @dev: device to sync
* @dma_addr: DMA address to sync
* @size: size of region
* @direction: DMA direction
+ * @attrs: optional dma attributes
*
* This routine is supposed to sync the DMA region specified
* by @dma_handle into the coherence domain. On SN, we're always cache
* coherent, so we just need to free any ATEs associated with this mapping.
*/
-void sn_dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
- int direction)
+void sn_dma_unmap_single_attrs(struct device *dev, dma_addr_t dma_addr,
+ size_t size, int direction,
+ struct dma_attrs *attrs)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
@@ -207,19 +226,21 @@
provider->dma_unmap(pdev, dma_addr, direction);
}
-EXPORT_SYMBOL(sn_dma_unmap_single);
+EXPORT_SYMBOL(sn_dma_unmap_single_attrs);
/**
- * sn_dma_unmap_sg - unmap a DMA scatterlist
+ * sn_dma_unmap_sg_attrs - unmap a DMA scatterlist
* @dev: device to unmap
* @sg: scatterlist to unmap
* @nhwentries: number of scatterlist entries
* @direction: DMA direction
+ * @attrs: optional dma attributes
*
* Unmap a set of streaming mode DMA translations.
*/
-void sn_dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
- int nhwentries, int direction)
+void sn_dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sgl,
+ int nhwentries, int direction,
+ struct dma_attrs *attrs)
{
int i;
struct pci_dev *pdev = to_pci_dev(dev);
@@ -234,25 +255,34 @@
sg->dma_length = 0;
}
}
-EXPORT_SYMBOL(sn_dma_unmap_sg);
+EXPORT_SYMBOL(sn_dma_unmap_sg_attrs);
/**
- * sn_dma_map_sg - map a scatterlist for DMA
+ * sn_dma_map_sg_attrs - map a scatterlist for DMA
* @dev: device to map for
* @sg: scatterlist to map
* @nhwentries: number of entries
* @direction: direction of the DMA transaction
+ * @attrs: optional dma attributes
+ *
+ * mappings with the DMA_ATTR_WRITE_BARRIER get mapped with
+ * dma_map_consistent() so that writes force a flush of pending DMA.
+ * (See "SGI Altix Architecture Considerations for Linux Device Drivers",
+ * Document Number: 007-4763-001)
*
* Maps each entry of @sg for DMA.
*/
-int sn_dma_map_sg(struct device *dev, struct scatterlist *sgl, int nhwentries,
- int direction)
+int sn_dma_map_sg_attrs(struct device *dev, struct scatterlist *sgl,
+ int nhwentries, int direction, struct dma_attrs *attrs)
{
unsigned long phys_addr;
struct scatterlist *saved_sg = sgl, *sg;
struct pci_dev *pdev = to_pci_dev(dev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
int i;
+ int dmabarr;
+
+ dmabarr = dma_get_attr(DMA_ATTR_WRITE_BARRIER, attrs);
BUG_ON(dev->bus != &pci_bus_type);
@@ -260,11 +290,19 @@
* Setup a DMA address for each entry in the scatterlist.
*/
for_each_sg(sgl, sg, nhwentries, i) {
+ dma_addr_t dma_addr;
phys_addr = SG_ENT_PHYS_ADDRESS(sg);
- sg->dma_address = provider->dma_map(pdev,
- phys_addr, sg->length,
- SN_DMA_ADDR_PHYS);
+ if (dmabarr)
+ dma_addr = provider->dma_map_consistent(pdev,
+ phys_addr,
+ sg->length,
+ SN_DMA_ADDR_PHYS);
+ else
+ dma_addr = provider->dma_map(pdev, phys_addr,
+ sg->length,
+ SN_DMA_ADDR_PHYS);
+ sg->dma_address = dma_addr;
if (!sg->dma_address) {
printk(KERN_ERR "%s: out of ATEs\n", __func__);
@@ -272,7 +310,8 @@
* Free any successfully allocated entries.
*/
if (i > 0)
- sn_dma_unmap_sg(dev, saved_sg, i, direction);
+ sn_dma_unmap_sg_attrs(dev, saved_sg, i,
+ direction, attrs);
return 0;
}
@@ -281,7 +320,7 @@
return nhwentries;
}
-EXPORT_SYMBOL(sn_dma_map_sg);
+EXPORT_SYMBOL(sn_dma_map_sg_attrs);
void sn_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
size_t size, int direction)
diff --git a/arch/m32r/Makefile b/arch/m32r/Makefile
index 4072a07..469766b 100644
--- a/arch/m32r/Makefile
+++ b/arch/m32r/Makefile
@@ -5,6 +5,8 @@
# architecture-specific flags and dependencies.
#
+KBUILD_DEFCONFIG := m32700ut.smp_defconfig
+
LDFLAGS :=
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
LDFLAGS_vmlinux :=
diff --git a/arch/m32r/defconfig b/arch/m32r/defconfig
deleted file mode 100644
index af3b981..0000000
--- a/arch/m32r/defconfig
+++ /dev/null
@@ -1,863 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc1
-# Wed Aug 1 17:22:35 2007
-#
-CONFIG_M32R=y
-CONFIG_GENERIC_ISA_DMA=y
-CONFIG_ZONE_DMA=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_NO_IOPORT=y
-CONFIG_NO_DMA=y
-CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOCK_KERNEL=y
-CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
-# CONFIG_POSIX_MQUEUE is not set
-CONFIG_BSD_PROCESS_ACCT=y
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-# CONFIG_TASKSTATS is not set
-# CONFIG_USER_NS is not set
-# CONFIG_AUDIT is not set
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=15
-# CONFIG_CPUSETS is not set
-CONFIG_SYSFS_DEPRECATED=y
-# CONFIG_RELAY is not set
-# CONFIG_BLK_DEV_INITRD is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SYSCTL=y
-CONFIG_EMBEDDED=y
-CONFIG_SYSCTL_SYSCALL=y
-# CONFIG_KALLSYMS is not set
-CONFIG_HOTPLUG=y
-CONFIG_PRINTK=y
-CONFIG_BUG=y
-CONFIG_ELF_CORE=y
-CONFIG_BASE_FULL=y
-# CONFIG_FUTEX is not set
-CONFIG_ANON_INODES=y
-# CONFIG_EPOLL is not set
-CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
-CONFIG_EVENTFD=y
-CONFIG_SHMEM=y
-CONFIG_VM_EVENT_COUNTERS=y
-CONFIG_SLAB=y
-# CONFIG_SLUB is not set
-# CONFIG_SLOB is not set
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-CONFIG_STOP_MACHINE=y
-CONFIG_BLOCK=y
-# CONFIG_LBD is not set
-# CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
-# CONFIG_BLK_DEV_BSG is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_DEFAULT_AS is not set
-# CONFIG_DEFAULT_DEADLINE is not set
-CONFIG_DEFAULT_CFQ=y
-# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="cfq"
-
-#
-# Processor type and features
-#
-# CONFIG_PLAT_MAPPI is not set
-# CONFIG_PLAT_USRV is not set
-CONFIG_PLAT_M32700UT=y
-# CONFIG_PLAT_OPSPUT is not set
-# CONFIG_PLAT_OAKS32R is not set
-# CONFIG_PLAT_MAPPI2 is not set
-# CONFIG_PLAT_MAPPI3 is not set
-# CONFIG_PLAT_M32104UT is not set
-CONFIG_CHIP_M32700=y
-# CONFIG_CHIP_M32102 is not set
-# CONFIG_CHIP_M32104 is not set
-# CONFIG_CHIP_VDEC2 is not set
-# CONFIG_CHIP_OPSP is not set
-CONFIG_MMU=y
-CONFIG_TLB_ENTRIES=32
-CONFIG_ISA_M32R2=y
-CONFIG_ISA_DSP_LEVEL2=y
-CONFIG_ISA_DUAL_ISSUE=y
-CONFIG_BUS_CLOCK=50000000
-CONFIG_TIMER_DIVIDE=128
-# CONFIG_CPU_LITTLE_ENDIAN is not set
-CONFIG_MEMORY_START=0x08000000
-CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_NOHIGHMEM=y
-CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-CONFIG_SELECT_MEMORY_MODEL=y
-# CONFIG_FLATMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM_MANUAL=y
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_DISCONTIGMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-CONFIG_NEED_MULTIPLE_NODES=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
-CONFIG_VIRT_TO_BUS=y
-CONFIG_IRAM_START=0x00f00000
-CONFIG_IRAM_SIZE=0x00080000
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_ARCH_HAS_ILOG2_U32 is not set
-# CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_GENERIC_FIND_NEXT_BIT=y
-CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_PREEMPT=y
-CONFIG_SMP=y
-# CONFIG_CHIP_M32700_TS1 is not set
-CONFIG_NR_CPUS=2
-CONFIG_NODES_SHIFT=1
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-# CONFIG_ARCH_SUPPORTS_MSI is not set
-# CONFIG_ISA is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-
-#
-# Networking
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_UNIX=y
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_XFRM_TUNNEL is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=y
-CONFIG_INET_XFRM_MODE_TUNNEL=y
-CONFIG_INET_XFRM_MODE_BEET=y
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
-# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_CUBIC=y
-CONFIG_DEFAULT_TCP_CONG="cubic"
-# CONFIG_TCP_MD5SIG is not set
-# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
-# CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
-# CONFIG_IP_DCCP is not set
-# CONFIG_IP_SCTP is not set
-# CONFIG_TIPC is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-# CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
-# CONFIG_CFG80211 is not set
-# CONFIG_WIRELESS_EXT is not set
-# CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
-# CONFIG_RFKILL is not set
-# CONFIG_NET_9P is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=y
-# CONFIG_SYS_HYPERVISOR is not set
-# CONFIG_CONNECTOR is not set
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
-# CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED is not set
-# CONFIG_MTD_REDBOOT_PARTS_READONLY is not set
-# CONFIG_MTD_CMDLINE_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-# CONFIG_MTD_CHAR is not set
-CONFIG_MTD_BLKDEVS=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-# CONFIG_RFD_FTL is not set
-# CONFIG_SSFDC is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=m
-CONFIG_MTD_JEDECPROBE=m
-CONFIG_MTD_GEN_PROBE=m
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-# CONFIG_MTD_CFI_NOSWAP is not set
-CONFIG_MTD_CFI_BE_BYTE_SWAP=y
-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
-CONFIG_MTD_CFI_GEOMETRY=y
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_CFI_I1=y
-# CONFIG_MTD_CFI_I2 is not set
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-# CONFIG_MTD_OTP is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-CONFIG_MTD_CFI_AMDSTD=m
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=m
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_PLATRAM is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLOCK2MTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-# CONFIG_MTD_NAND is not set
-# CONFIG_MTD_ONENAND is not set
-
-#
-# UBI - Unsorted block images
-#
-# CONFIG_MTD_UBI is not set
-# CONFIG_PARPORT is not set
-CONFIG_BLK_DEV=y
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
-# CONFIG_CDROM_PKTCDVD is not set
-CONFIG_ATA_OVER_ETH=m
-CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
-CONFIG_IDE=y
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECD=m
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-CONFIG_IDE_PROC_FS=y
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDEPCI_PCIBUS_ORDER is not set
-# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=m
-# CONFIG_SCSI_DMA is not set
-# CONFIG_SCSI_TGT is not set
-# CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=m
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-CONFIG_CHR_DEV_SG=m
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-CONFIG_SCSI_MULTI_LUN=y
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_MD is not set
-CONFIG_NETDEVICES=y
-# CONFIG_NETDEVICES_MULTIQUEUE is not set
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_MACVLAN is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-# CONFIG_PHYLIB is not set
-CONFIG_NET_ETHERNET=y
-CONFIG_MII=y
-CONFIG_SMC91X=y
-# CONFIG_NE2000 is not set
-CONFIG_NETDEV_1000=y
-CONFIG_NETDEV_10000=y
-
-#
-# Wireless LAN
-#
-# CONFIG_WLAN_PRE80211 is not set
-# CONFIG_WLAN_80211 is not set
-# 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
-# CONFIG_ISDN is not set
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-# CONFIG_INPUT_FF_MEMLESS is not set
-# CONFIG_INPUT_POLLDEV is not set
-
-#
-# Userland interfaces
-#
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TABLET is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-# CONFIG_GAMEPORT is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_SERIAL_M32R_SIO=y
-CONFIG_SERIAL_M32R_SIO_CONSOLE=y
-CONFIG_SERIAL_M32R_PLDSIO=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-# CONFIG_IPMI_HANDLER is not set
-# CONFIG_WATCHDOG is not set
-CONFIG_HW_RANDOM=y
-# CONFIG_RTC is not set
-CONFIG_DS1302=y
-# CONFIG_R3964 is not set
-# CONFIG_RAW_DRIVER is not set
-# CONFIG_TCG_TPM is not set
-# CONFIG_I2C is not set
-
-#
-# SPI support
-#
-# CONFIG_SPI is not set
-# CONFIG_SPI_MASTER is not set
-# CONFIG_W1 is not set
-# CONFIG_POWER_SUPPLY is not set
-CONFIG_HWMON=y
-# CONFIG_HWMON_VID is not set
-# CONFIG_SENSORS_ABITUGURU is not set
-# CONFIG_SENSORS_ABITUGURU3 is not set
-# CONFIG_SENSORS_F71805F is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_PC87427 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_VT1211 is not set
-# CONFIG_SENSORS_W83627HF is not set
-# CONFIG_SENSORS_W83627EHF is not set
-# CONFIG_HWMON_DEBUG_CHIP is not set
-
-#
-# Multifunction device drivers
-#
-# CONFIG_MFD_SM501 is not set
-
-#
-# Multimedia devices
-#
-CONFIG_VIDEO_DEV=m
-CONFIG_VIDEO_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
-CONFIG_VIDEO_V4L2=y
-CONFIG_VIDEO_CAPTURE_DRIVERS=y
-# CONFIG_VIDEO_ADV_DEBUG is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-# CONFIG_VIDEO_CPIA is not set
-CONFIG_VIDEO_M32R_AR=m
-CONFIG_VIDEO_M32R_AR_M64278=m
-CONFIG_RADIO_ADAPTERS=y
-# CONFIG_DVB_CORE is not set
-CONFIG_DAB=y
-
-#
-# Graphics support
-#
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Display device support
-#
-# CONFIG_DISPLAY_SUPPORT is not set
-# CONFIG_VGASTATE is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=m
-CONFIG_FB=y
-CONFIG_FIRMWARE_EDID=y
-# CONFIG_FB_DDC is not set
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-# CONFIG_FB_SYS_FILLRECT is not set
-# CONFIG_FB_SYS_COPYAREA is not set
-# CONFIG_FB_SYS_IMAGEBLIT is not set
-# CONFIG_FB_SYS_FOPS is not set
-CONFIG_FB_DEFERRED_IO=y
-# CONFIG_FB_SVGALIB is not set
-# CONFIG_FB_MACMODES is not set
-# CONFIG_FB_BACKLIGHT is not set
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_TILEBLITTING is not set
-
-#
-# Frame buffer hardware drivers
-#
-CONFIG_FB_S1D13XXX=y
-# CONFIG_FB_VIRTUAL is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
-# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-# CONFIG_FONTS is not set
-CONFIG_FONT_8x8=y
-CONFIG_FONT_8x16=y
-CONFIG_LOGO=y
-CONFIG_LOGO_LINUX_MONO=y
-CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-CONFIG_LOGO_M32R_CLUT224=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=y
-# CONFIG_HID_DEBUG is not set
-CONFIG_USB_SUPPORT=y
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB_ARCH_HAS_EHCI is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-CONFIG_MMC=y
-CONFIG_MMC_DEBUG=y
-# CONFIG_MMC_UNSAFE_RESUME is not set
-
-#
-# MMC/SD Card Drivers
-#
-CONFIG_MMC_BLOCK=y
-CONFIG_MMC_BLOCK_BOUNCE=y
-
-#
-# MMC/SD Host Controller Drivers
-#
-# CONFIG_NEW_LEDS is not set
-
-#
-# Real Time Clock
-#
-# CONFIG_RTC_CLASS is not set
-
-#
-# Userspace I/O
-#
-# CONFIG_UIO 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=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-# CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=y
-CONFIG_JBD_DEBUG=y
-CONFIG_FS_MBCACHE=y
-CONFIG_REISERFS_FS=m
-# CONFIG_REISERFS_CHECK is not set
-# CONFIG_REISERFS_PROC_INFO is not set
-# CONFIG_REISERFS_FS_XATTR is not set
-# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
-# CONFIG_XFS_FS is not set
-# CONFIG_GFS2_FS is not set
-# CONFIG_OCFS2_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-# CONFIG_FUSE_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
-CONFIG_UDF_FS=m
-CONFIG_UDF_NLS=y
-
-#
-# DOS/FAT/NT Filesystems
-#
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_PROC_SYSCTL=y
-CONFIG_SYSFS=y
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_POSIX_ACL is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-# CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS2_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=y
-# CONFIG_SUNRPC_BIND34 is not set
-# 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=y
-CONFIG_NLS_DEFAULT="iso8859-1"
-# CONFIG_NLS_CODEPAGE_437 is not set
-# CONFIG_NLS_CODEPAGE_737 is not set
-# CONFIG_NLS_CODEPAGE_775 is not set
-# CONFIG_NLS_CODEPAGE_850 is not set
-# CONFIG_NLS_CODEPAGE_852 is not set
-# CONFIG_NLS_CODEPAGE_855 is not set
-# CONFIG_NLS_CODEPAGE_857 is not set
-# CONFIG_NLS_CODEPAGE_860 is not set
-# CONFIG_NLS_CODEPAGE_861 is not set
-# CONFIG_NLS_CODEPAGE_862 is not set
-# CONFIG_NLS_CODEPAGE_863 is not set
-# CONFIG_NLS_CODEPAGE_864 is not set
-# CONFIG_NLS_CODEPAGE_865 is not set
-# CONFIG_NLS_CODEPAGE_866 is not set
-# CONFIG_NLS_CODEPAGE_869 is not set
-# CONFIG_NLS_CODEPAGE_936 is not set
-# CONFIG_NLS_CODEPAGE_950 is not set
-# CONFIG_NLS_CODEPAGE_932 is not set
-# CONFIG_NLS_CODEPAGE_949 is not set
-# CONFIG_NLS_CODEPAGE_874 is not set
-# CONFIG_NLS_ISO8859_8 is not set
-# CONFIG_NLS_CODEPAGE_1250 is not set
-# CONFIG_NLS_CODEPAGE_1251 is not set
-# CONFIG_NLS_ASCII is not set
-# CONFIG_NLS_ISO8859_1 is not set
-# CONFIG_NLS_ISO8859_2 is not set
-# CONFIG_NLS_ISO8859_3 is not set
-# CONFIG_NLS_ISO8859_4 is not set
-# CONFIG_NLS_ISO8859_5 is not set
-# CONFIG_NLS_ISO8859_6 is not set
-# CONFIG_NLS_ISO8859_7 is not set
-# CONFIG_NLS_ISO8859_9 is not set
-# CONFIG_NLS_ISO8859_13 is not set
-# CONFIG_NLS_ISO8859_14 is not set
-# CONFIG_NLS_ISO8859_15 is not set
-# CONFIG_NLS_KOI8_R is not set
-# CONFIG_NLS_KOI8_U is not set
-# CONFIG_NLS_UTF8 is not set
-
-#
-# Distributed Lock Manager
-#
-# CONFIG_DLM is not set
-
-#
-# Profiling support
-#
-CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-CONFIG_ENABLE_MUST_CHECK=y
-# CONFIG_MAGIC_SYSRQ is not set
-# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_FS is not set
-# CONFIG_HEADERS_CHECK is not set
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_DEBUG_BUGVERBOSE is not set
-# CONFIG_FRAME_POINTER is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-# CONFIG_CRYPTO is not set
-
-#
-# Library routines
-#
-CONFIG_BITREVERSE=y
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC16 is not set
-# CONFIG_CRC_ITU_T is not set
-CONFIG_CRC32=y
-# CONFIG_CRC7 is not set
-# CONFIG_LIBCRC32C is not set
-CONFIG_HAS_IOMEM=y
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index 41b0785..15a6f36 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -60,9 +60,6 @@
. = ALIGN(4096);
__nosave_end = .;
- . = ALIGN(4096);
- .data.page_aligned : { *(.data.idt) }
-
. = ALIGN(32);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
diff --git a/arch/m68k/kernel/asm-offsets.c b/arch/m68k/kernel/asm-offsets.c
index 246a882..b1f012f 100644
--- a/arch/m68k/kernel/asm-offsets.c
+++ b/arch/m68k/kernel/asm-offsets.c
@@ -11,14 +11,12 @@
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
+#include <linux/kbuild.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/amigahw.h>
#include <linux/font.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
int main(void)
{
/* offsets into the task struct */
diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
index 5b2799e..326fb99 100644
--- a/arch/m68k/mac/iop.c
+++ b/arch/m68k/mac/iop.c
@@ -109,7 +109,6 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/proc_fs.h>
#include <linux/interrupt.h>
#include <asm/bootinfo.h>
@@ -124,10 +123,6 @@
int iop_scc_present,iop_ism_present;
-#ifdef CONFIG_PROC_FS
-static int iop_get_proc_info(char *, char **, off_t, int);
-#endif /* CONFIG_PROC_FS */
-
/* structure for tracking channel listeners */
struct listener {
@@ -299,12 +294,6 @@
iop_listeners[IOP_NUM_ISM][i].devname = NULL;
iop_listeners[IOP_NUM_ISM][i].handler = NULL;
}
-
-#if 0 /* Crashing in 2.4 now, not yet sure why. --jmt */
-#ifdef CONFIG_PROC_FS
- create_proc_info_entry("mac_iop", 0, &proc_root, iop_get_proc_info);
-#endif
-#endif
}
/*
@@ -637,77 +626,3 @@
}
return IRQ_HANDLED;
}
-
-#ifdef CONFIG_PROC_FS
-
-char *iop_chan_state(int state)
-{
- switch(state) {
- case IOP_MSG_IDLE : return "idle ";
- case IOP_MSG_NEW : return "new ";
- case IOP_MSG_RCVD : return "received ";
- case IOP_MSG_COMPLETE : return "completed ";
- default : return "unknown ";
- }
-}
-
-int iop_dump_one_iop(char *buf, int iop_num, char *iop_name)
-{
- int i,len = 0;
- volatile struct mac_iop *iop = iop_base[iop_num];
-
- len += sprintf(buf+len, "%s IOP channel states:\n\n", iop_name);
- len += sprintf(buf+len, "## send_state recv_state device\n");
- len += sprintf(buf+len, "------------------------------------------------\n");
- for (i = 0 ; i < NUM_IOP_CHAN ; i++) {
- len += sprintf(buf+len, "%2d %10s %10s %s\n", i,
- iop_chan_state(iop_readb(iop, IOP_ADDR_SEND_STATE+i)),
- iop_chan_state(iop_readb(iop, IOP_ADDR_RECV_STATE+i)),
- iop_listeners[iop_num][i].handler?
- iop_listeners[iop_num][i].devname : "");
-
- }
- len += sprintf(buf+len, "\n");
- return len;
-}
-
-static int iop_get_proc_info(char *buf, char **start, off_t pos, int count)
-{
- int len, cnt;
-
- cnt = 0;
- len = sprintf(buf, "IOPs detected:\n\n");
-
- if (iop_scc_present) {
- len += sprintf(buf+len, "SCC IOP (%p): status %02X\n",
- iop_base[IOP_NUM_SCC],
- (uint) iop_base[IOP_NUM_SCC]->status_ctrl);
- }
- if (iop_ism_present) {
- len += sprintf(buf+len, "ISM IOP (%p): status %02X\n\n",
- iop_base[IOP_NUM_ISM],
- (uint) iop_base[IOP_NUM_ISM]->status_ctrl);
- }
-
- if (iop_scc_present) {
- len += iop_dump_one_iop(buf+len, IOP_NUM_SCC, "SCC");
-
- }
-
- if (iop_ism_present) {
- len += iop_dump_one_iop(buf+len, IOP_NUM_ISM, "ISM");
-
- }
-
- if (len >= pos) {
- if (!*start) {
- *start = buf + pos;
- cnt = len - pos;
- } else {
- cnt += len;
- }
- }
- return (count > cnt) ? cnt : count;
-}
-
-#endif /* CONFIG_PROC_FS */
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index a2bb01f..d8fb9c5 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -69,6 +69,7 @@
*/
void *empty_zero_page;
+EXPORT_SYMBOL(empty_zero_page);
void show_mem(void)
{
diff --git a/arch/m68knommu/kernel/asm-offsets.c b/arch/m68knommu/kernel/asm-offsets.c
index d97b89b..c785d07 100644
--- a/arch/m68knommu/kernel/asm-offsets.c
+++ b/arch/m68knommu/kernel/asm-offsets.c
@@ -13,15 +13,11 @@
#include <linux/kernel_stat.h>
#include <linux/ptrace.h>
#include <linux/hardirq.h>
+#include <linux/kbuild.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/thread_info.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
int main(void)
{
/* offsets into the task struct */
@@ -91,6 +87,7 @@
DEFINE(TI_TASK, offsetof(struct thread_info, task));
DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+ DEFINE(TI_PREEMPTCOUNT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
return 0;
diff --git a/arch/m68knommu/kernel/entry.S b/arch/m68knommu/kernel/entry.S
index 1e7ea6a..f4782d2 100644
--- a/arch/m68knommu/kernel/entry.S
+++ b/arch/m68knommu/kernel/entry.S
@@ -32,6 +32,7 @@
#include <asm/segment.h>
#include <asm/asm-offsets.h>
#include <asm/entry.h>
+#include <asm/unistd.h>
.text
@@ -140,3 +141,11 @@
RESTORE_SWITCH_STACK
rts
+ENTRY(ret_from_user_signal)
+ moveq #__NR_sigreturn,%d0
+ trap #0
+
+ENTRY(ret_from_user_rt_signal)
+ move #__NR_rt_sigreturn,%d0
+ trap #0
+
diff --git a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c
index d6f0200..03f4fe6 100644
--- a/arch/m68knommu/kernel/setup.c
+++ b/arch/m68knommu/kernel/setup.c
@@ -162,7 +162,7 @@
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)");
+ printk(KERN_INFO "Motorola M5235EVB support (C)2005 Syn-tech Systems, Inc. (Jate Sujjavanich)\n");
#endif
#ifdef DEBUG
diff --git a/arch/m68knommu/kernel/signal.c b/arch/m68knommu/kernel/signal.c
index 7037137..bbfcae9 100644
--- a/arch/m68knommu/kernel/signal.c
+++ b/arch/m68knommu/kernel/signal.c
@@ -51,6 +51,8 @@
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+void ret_from_user_signal(void);
+void ret_from_user_rt_signal(void);
asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs);
/*
@@ -539,10 +541,6 @@
return err;
}
-static inline void push_cache (unsigned long vaddr)
-{
-}
-
static inline void *
get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
{
@@ -586,16 +584,11 @@
err |= copy_to_user (&frame->sc, &context, sizeof(context));
/* Set up to return from userspace. */
- err |= __put_user(frame->retcode, &frame->pretcode);
- /* moveq #,d0; trap #0 */
- err |= __put_user(0x70004e40 + (__NR_sigreturn << 16),
- (long *)(frame->retcode));
+ err |= __put_user((void *) ret_from_user_signal, &frame->pretcode);
if (err)
goto give_sigsegv;
- push_cache ((unsigned long) &frame->retcode);
-
/* Set up registers for signal handler */
wrusp ((unsigned long) frame);
regs->pc = (unsigned long) ka->sa.sa_handler;
@@ -655,17 +648,11 @@
err |= copy_to_user (&frame->uc.uc_sigmask, set, sizeof(*set));
/* Set up to return from userspace. */
- err |= __put_user(frame->retcode, &frame->pretcode);
- /* moveq #,d0; notb d0; trap #0 */
- err |= __put_user(0x70004600 + ((__NR_rt_sigreturn ^ 0xff) << 16),
- (long *)(frame->retcode + 0));
- err |= __put_user(0x4e40, (short *)(frame->retcode + 4));
+ err |= __put_user((void *) ret_from_user_rt_signal, &frame->pretcode);
if (err)
goto give_sigsegv;
- push_cache ((unsigned long) &frame->retcode);
-
/* Set up registers for signal handler */
wrusp ((unsigned long) frame);
regs->pc = (unsigned long) ka->sa.sa_handler;
diff --git a/arch/m68knommu/kernel/traps.c b/arch/m68knommu/kernel/traps.c
index 437a061..ec9aea6 100644
--- a/arch/m68knommu/kernel/traps.c
+++ b/arch/m68knommu/kernel/traps.c
@@ -28,6 +28,7 @@
#include <linux/linkage.h>
#include <linux/init.h>
#include <linux/ptrace.h>
+#include <linux/kallsyms.h>
#include <asm/setup.h>
#include <asm/fpu.h>
@@ -102,56 +103,47 @@
force_sig(SIGSEGV, current);
}
-
int kstack_depth_to_print = 48;
-void show_stack(struct task_struct *task, unsigned long *stack)
+static void __show_stack(struct task_struct *task, unsigned long *stack)
{
unsigned long *endstack, addr;
- extern char _start, _etext;
+ unsigned long *last_stack;
int i;
- if (!stack) {
- if (task)
- stack = (unsigned long *)task->thread.ksp;
- else
- stack = (unsigned long *)&stack;
- }
+ if (!stack)
+ stack = (unsigned long *)task->thread.ksp;
addr = (unsigned long) stack;
endstack = (unsigned long *) PAGE_ALIGN(addr);
printk(KERN_EMERG "Stack from %08lx:", (unsigned long)stack);
for (i = 0; i < kstack_depth_to_print; i++) {
- if (stack + 1 > endstack)
+ if (stack + 1 + i > endstack)
break;
if (i % 8 == 0)
printk("\n" KERN_EMERG " ");
- printk(" %08lx", *stack++);
+ printk(" %08lx", *(stack + i));
}
printk("\n");
- printk(KERN_EMERG "Call Trace:");
- i = 0;
- while (stack + 1 <= endstack) {
- addr = *stack++;
- /*
- * If the address is either in the text segment of the
- * kernel, or in the region which contains vmalloc'ed
- * memory, it *may* be the address of a calling
- * routine; if so, print it so that someone tracing
- * down the cause of the crash will be able to figure
- * out the call path that was taken.
- */
- if (((addr >= (unsigned long) &_start) &&
- (addr <= (unsigned long) &_etext))) {
- if (i % 4 == 0)
- printk("\n" KERN_EMERG " ");
- printk(" [<%08lx>]", addr);
- i++;
- }
+#ifdef CONFIG_FRAME_POINTER
+ printk(KERN_EMERG "Call Trace:\n");
+
+ last_stack = stack - 1;
+ while (stack <= endstack && stack > last_stack) {
+
+ addr = *(stack + 1);
+ printk(KERN_EMERG " [%08lx] ", addr);
+ print_symbol(KERN_CONT "%s\n", addr);
+
+ last_stack = stack;
+ stack = (unsigned long *)*stack;
}
printk("\n");
+#else
+ printk(KERN_EMERG "CONFIG_FRAME_POINTER disabled, no symbolic call trace\n");
+#endif
}
void bad_super_trap(struct frame *fp)
@@ -298,19 +290,47 @@
current->thread.esp0 = ssp;
}
-
/*
* The architecture-independent backtrace generator
*/
void dump_stack(void)
{
- unsigned long stack;
+ /*
+ * We need frame pointers for this little trick, which works as follows:
+ *
+ * +------------+ 0x00
+ * | Next SP | -> 0x0c
+ * +------------+ 0x04
+ * | Caller |
+ * +------------+ 0x08
+ * | Local vars | -> our stack var
+ * +------------+ 0x0c
+ * | Next SP | -> 0x18, that is what we pass to show_stack()
+ * +------------+ 0x10
+ * | Caller |
+ * +------------+ 0x14
+ * | Local vars |
+ * +------------+ 0x18
+ * | ... |
+ * +------------+
+ */
- show_stack(current, &stack);
+ unsigned long *stack;
+
+ stack = (unsigned long *)&stack;
+ stack++;
+ __show_stack(current, stack);
}
-
EXPORT_SYMBOL(dump_stack);
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+ if (!stack && !task)
+ dump_stack();
+ else
+ __show_stack(task, 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 b44edb0..5592e0b 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -64,6 +64,7 @@
_stext = . ;
TEXT_TEXT
SCHED_TEXT
+ LOCK_TEXT
*(.text.lock)
. = ALIGN(16); /* Exception table */
@@ -73,6 +74,7 @@
*(.rodata) *(.rodata.*)
*(__vermagic) /* Kernel version magic */
+ *(__markers_strings)
*(.rodata1)
*(.rodata.str1.1)
@@ -182,6 +184,7 @@
*(COMMON)
. = ALIGN(4) ;
_ebss = . ;
+ _end = . ;
} > BSS
}
diff --git a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c
index a6692e9..d01a5d2 100644
--- a/arch/m68knommu/platform/5206e/config.c
+++ b/arch/m68knommu/platform/5206e/config.c
@@ -48,7 +48,7 @@
/***************************************************************************/
-static void __init m5206_uart_init_line(int line, int irq)
+static void __init m5206e_uart_init_line(int line, int irq)
{
if (line == 0) {
writel(MCFSIM_ICR_LEVEL6 | MCFSIM_ICR_PRI1, MCF_MBAR + MCFSIM_UART1ICR);
diff --git a/arch/m68knommu/platform/5272/config.c b/arch/m68knommu/platform/5272/config.c
index 2aca599..230bae6 100644
--- a/arch/m68knommu/platform/5272/config.c
+++ b/arch/m68knommu/platform/5272/config.c
@@ -139,10 +139,6 @@
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0xf0004000, size);
commandp[size-1] = 0;
-#elif defined(CONFIG_MTD_KeyTechnology)
- /* Copy command line from FLASH to local buffer... */
- memcpy(commandp, (char *) 0xffe06000, size);
- commandp[size-1] = 0;
#elif defined(CONFIG_CANCam)
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0xf0010000, size);
diff --git a/arch/m68knommu/platform/528x/config.c b/arch/m68knommu/platform/528x/config.c
index 036e1b7..dfdb5c2e 100644
--- a/arch/m68knommu/platform/528x/config.c
+++ b/arch/m68knommu/platform/528x/config.c
@@ -26,9 +26,240 @@
#include <asm/mcfuart.h>
#include <asm/mcfqspi.h>
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
/***************************************************************************/
void coldfire_reset(void);
+static void coldfire_qspi_cs_control(u8 cs, u8 command);
+
+/***************************************************************************/
+
+#if defined(CONFIG_SPI)
+
+#if defined(CONFIG_WILDFIRE)
+#define SPI_NUM_CHIPSELECTS 0x02
+#define SPI_PAR_VAL 0x07 /* Enable DIN, DOUT, CLK */
+#define SPI_CS_MASK 0x18
+
+#define FLASH_BLOCKSIZE (1024*64)
+#define FLASH_NUMBLOCKS 16
+#define FLASH_TYPE "m25p80"
+
+#define M25P80_CS 0
+#define MMC_CS 1
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition stm25p_partitions[] = {
+ /* sflash */
+ [0] = {
+ .name = "stm25p80",
+ .offset = 0x00000000,
+ .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS,
+ .mask_flags = 0
+ }
+};
+
+#endif
+
+#elif defined(CONFIG_WILDFIREMOD)
+
+#define SPI_NUM_CHIPSELECTS 0x08
+#define SPI_PAR_VAL 0x07 /* Enable DIN, DOUT, CLK */
+#define SPI_CS_MASK 0x78
+
+#define FLASH_BLOCKSIZE (1024*64)
+#define FLASH_NUMBLOCKS 64
+#define FLASH_TYPE "m25p32"
+/* Reserve 1M for the kernel parition */
+#define FLASH_KERNEL_SIZE (1024 * 1024)
+
+#define M25P80_CS 5
+#define MMC_CS 6
+
+#ifdef CONFIG_MTD_PARTITIONS
+static struct mtd_partition stm25p_partitions[] = {
+ /* sflash */
+ [0] = {
+ .name = "kernel",
+ .offset = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS - FLASH_KERNEL_SIZE,
+ .size = FLASH_KERNEL_SIZE,
+ .mask_flags = 0
+ },
+ [1] = {
+ .name = "image",
+ .offset = 0x00000000,
+ .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS - FLASH_KERNEL_SIZE,
+ .mask_flags = 0
+ },
+ [2] = {
+ .name = "all",
+ .offset = 0x00000000,
+ .size = FLASH_BLOCKSIZE * FLASH_NUMBLOCKS,
+ .mask_flags = 0
+ }
+};
+#endif
+
+#else
+#define SPI_NUM_CHIPSELECTS 0x04
+#define SPI_PAR_VAL 0x7F /* Enable DIN, DOUT, CLK, CS0 - CS4 */
+#endif
+
+#ifdef MMC_CS
+static struct coldfire_spi_chip flash_chip_info = {
+ .mode = SPI_MODE_0,
+ .bits_per_word = 16,
+ .del_cs_to_clk = 17,
+ .del_after_trans = 1,
+ .void_write_data = 0
+};
+
+static struct coldfire_spi_chip mmc_chip_info = {
+ .mode = SPI_MODE_0,
+ .bits_per_word = 16,
+ .del_cs_to_clk = 17,
+ .del_after_trans = 1,
+ .void_write_data = 0xFFFF
+};
+#endif
+
+#ifdef M25P80_CS
+static struct flash_platform_data stm25p80_platform_data = {
+ .name = "ST M25P80 SPI Flash chip",
+#ifdef CONFIG_MTD_PARTITIONS
+ .parts = stm25p_partitions,
+ .nr_parts = sizeof(stm25p_partitions) / sizeof(*stm25p_partitions),
+#endif
+ .type = FLASH_TYPE
+};
+#endif
+
+static struct spi_board_info spi_board_info[] __initdata = {
+#ifdef M25P80_CS
+ {
+ .modalias = "m25p80",
+ .max_speed_hz = 16000000,
+ .bus_num = 1,
+ .chip_select = M25P80_CS,
+ .platform_data = &stm25p80_platform_data,
+ .controller_data = &flash_chip_info
+ },
+#endif
+#ifdef MMC_CS
+ {
+ .modalias = "mmc_spi",
+ .max_speed_hz = 16000000,
+ .bus_num = 1,
+ .chip_select = MMC_CS,
+ .controller_data = &mmc_chip_info
+ }
+#endif
+};
+
+static struct coldfire_spi_master coldfire_master_info = {
+ .bus_num = 1,
+ .num_chipselect = SPI_NUM_CHIPSELECTS,
+ .irq_source = MCF5282_QSPI_IRQ_SOURCE,
+ .irq_vector = MCF5282_QSPI_IRQ_VECTOR,
+ .irq_mask = ((0x01 << MCF5282_QSPI_IRQ_SOURCE) | 0x01),
+ .irq_lp = 0x2B, /* Level 5 and Priority 3 */
+ .par_val = SPI_PAR_VAL,
+ .cs_control = coldfire_qspi_cs_control,
+};
+
+static struct resource coldfire_spi_resources[] = {
+ [0] = {
+ .name = "qspi-par",
+ .start = MCF5282_QSPI_PAR,
+ .end = MCF5282_QSPI_PAR,
+ .flags = IORESOURCE_MEM
+ },
+
+ [1] = {
+ .name = "qspi-module",
+ .start = MCF5282_QSPI_QMR,
+ .end = MCF5282_QSPI_QMR + 0x18,
+ .flags = IORESOURCE_MEM
+ },
+
+ [2] = {
+ .name = "qspi-int-level",
+ .start = MCF5282_INTC0 + MCFINTC_ICR0 + MCF5282_QSPI_IRQ_SOURCE,
+ .end = MCF5282_INTC0 + MCFINTC_ICR0 + MCF5282_QSPI_IRQ_SOURCE,
+ .flags = IORESOURCE_MEM
+ },
+
+ [3] = {
+ .name = "qspi-int-mask",
+ .start = MCF5282_INTC0 + MCFINTC_IMRL,
+ .end = MCF5282_INTC0 + MCFINTC_IMRL,
+ .flags = IORESOURCE_MEM
+ }
+};
+
+static struct platform_device coldfire_spi = {
+ .name = "spi_coldfire",
+ .id = -1,
+ .resource = coldfire_spi_resources,
+ .num_resources = ARRAY_SIZE(coldfire_spi_resources),
+ .dev = {
+ .platform_data = &coldfire_master_info,
+ }
+};
+
+static void coldfire_qspi_cs_control(u8 cs, u8 command)
+{
+ u8 cs_bit = ((0x01 << cs) << 3) & SPI_CS_MASK;
+
+#if defined(CONFIG_WILDFIRE)
+ u8 cs_mask = ~(((0x01 << cs) << 3) & SPI_CS_MASK);
+#endif
+#if defined(CONFIG_WILDFIREMOD)
+ u8 cs_mask = (cs << 3) & SPI_CS_MASK;
+#endif
+
+ /*
+ * Don't do anything if the chip select is not
+ * one of the port qs pins.
+ */
+ if (command & QSPI_CS_INIT) {
+#if defined(CONFIG_WILDFIRE)
+ MCF5282_GPIO_DDRQS |= cs_bit;
+ MCF5282_GPIO_PQSPAR &= ~cs_bit;
+#endif
+
+#if defined(CONFIG_WILDFIREMOD)
+ MCF5282_GPIO_DDRQS |= SPI_CS_MASK;
+ MCF5282_GPIO_PQSPAR &= ~SPI_CS_MASK;
+#endif
+ }
+
+ if (command & QSPI_CS_ASSERT) {
+ MCF5282_GPIO_PORTQS &= ~SPI_CS_MASK;
+ MCF5282_GPIO_PORTQS |= cs_mask;
+ } else if (command & QSPI_CS_DROP) {
+ MCF5282_GPIO_PORTQS |= SPI_CS_MASK;
+ }
+}
+
+static int __init spi_dev_init(void)
+{
+ int retval;
+
+ retval = platform_device_register(&coldfire_spi);
+ if (retval < 0)
+ return retval;
+
+ if (ARRAY_SIZE(spi_board_info))
+ retval = spi_register_board_info(spi_board_info, ARRAY_SIZE(spi_board_info));
+
+ return retval;
+}
+
+#endif /* CONFIG_SPI */
/***************************************************************************/
@@ -111,10 +342,43 @@
/***************************************************************************/
+#ifdef CONFIG_WILDFIRE
+void wildfire_halt(void)
+{
+ writeb(0, 0x30000007);
+ writeb(0x2, 0x30000007);
+}
+#endif
+
+#ifdef CONFIG_WILDFIREMOD
+void wildfiremod_halt(void)
+{
+ printk(KERN_INFO "WildFireMod hibernating...\n");
+
+ /* Set portE.5 to Digital IO */
+ MCF5282_GPIO_PEPAR &= ~(1 << (5 * 2));
+
+ /* Make portE.5 an output */
+ MCF5282_GPIO_DDRE |= (1 << 5);
+
+ /* Now toggle portE.5 from low to high */
+ MCF5282_GPIO_PORTE &= ~(1 << 5);
+ MCF5282_GPIO_PORTE |= (1 << 5);
+
+ printk(KERN_EMERG "Failed to hibernate. Halting!\n");
+}
+#endif
+
void __init config_BSP(char *commandp, int size)
{
mcf_disableall();
- mach_reset = coldfire_reset;
+
+#ifdef CONFIG_WILDFIRE
+ mach_halt = wildfire_halt;
+#endif
+#ifdef CONFIG_WILDFIREMOD
+ mach_halt = wildfiremod_halt;
+#endif
}
/***************************************************************************/
diff --git a/arch/m68knommu/platform/5307/config.c b/arch/m68knommu/platform/5307/config.c
index 92dc862..11cff66 100644
--- a/arch/m68knommu/platform/5307/config.c
+++ b/arch/m68knommu/platform/5307/config.c
@@ -124,8 +124,7 @@
mcf_setimr(MCFSIM_IMR_MASKALL);
#if defined(CONFIG_NETtel) || defined(CONFIG_eLIA) || \
- defined(CONFIG_DISKtel) || defined(CONFIG_SECUREEDGEMP3) || \
- defined(CONFIG_CLEOPATRA)
+ defined(CONFIG_SECUREEDGEMP3) || defined(CONFIG_CLEOPATRA)
/* Copy command line from FLASH to local buffer... */
memcpy(commandp, (char *) 0xf0004000, size);
commandp[size-1] = 0;
diff --git a/arch/m68knommu/platform/coldfire/entry.S b/arch/m68knommu/platform/coldfire/entry.S
index 111b66d..1e3c0dc 100644
--- a/arch/m68knommu/platform/coldfire/entry.S
+++ b/arch/m68knommu/platform/coldfire/entry.S
@@ -103,9 +103,26 @@
addql #4,%sp
ret_from_exception:
+ move #0x2700,%sr /* disable intrs */
btst #5,%sp@(PT_SR) /* check if returning to kernel */
jeq Luser_return /* if so, skip resched, signals */
+#ifdef CONFIG_PREEMPT
+ movel %sp,%d1 /* get thread_info pointer */
+ andl #-THREAD_SIZE,%d1 /* at base of kernel stack */
+ movel %d1,%a0
+ movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */
+ andl #_TIF_NEED_RESCHED,%d1
+ jeq Lkernel_return
+
+ movel %a0@(TI_PREEMPTCOUNT),%d1
+ cmpl #0,%d1
+ jne Lkernel_return
+
+ pea Lkernel_return
+ jmp preempt_schedule_irq /* preempt the kernel */
+#endif
+
Lkernel_return:
moveml %sp@,%d1-%d5/%a0-%a2
lea %sp@(32),%sp /* space for 8 regs */
@@ -140,6 +157,7 @@
Lwork_to_do:
movel %a0@(TI_FLAGS),%d1 /* get thread_info->flags */
+ move #0x2000,%sr /* enable intrs again */
btst #TIF_NEED_RESCHED,%d1
jne reschedule
diff --git a/arch/mips/au1000/common/power.c b/arch/mips/au1000/common/power.c
index 812a5f8..a8cd2c1 100644
--- a/arch/mips/au1000/common/power.c
+++ b/arch/mips/au1000/common/power.c
@@ -251,7 +251,6 @@
static int pm_do_sleep(ctl_table * ctl, int write, struct file *file,
void __user *buffer, size_t * len, loff_t *ppos)
{
- int retval = 0;
#ifdef SLEEP_TEST_TIMEOUT
#define TMPBUFLEN2 16
char buf[TMPBUFLEN2], *p;
@@ -271,36 +270,12 @@
p = buf;
sleep_ticks = simple_strtoul(p, &p, 0);
#endif
- retval = pm_send_all(PM_SUSPEND, (void *) 2);
-
- if (retval)
- return retval;
au_sleep();
- retval = pm_send_all(PM_RESUME, (void *) 0);
}
- return retval;
+ return 0;
}
-static int pm_do_suspend(ctl_table * ctl, int write, struct file *file,
- void __user *buffer, size_t * len, loff_t *ppos)
-{
- int retval = 0;
-
- if (!write) {
- *len = 0;
- } else {
- retval = pm_send_all(PM_SUSPEND, (void *) 2);
- if (retval)
- return retval;
- suspend_mode = 1;
-
- retval = pm_send_all(PM_RESUME, (void *) 0);
- }
- return retval;
-}
-
-
static int pm_do_freq(ctl_table * ctl, int write, struct file *file,
void __user *buffer, size_t * len, loff_t *ppos)
{
@@ -414,14 +389,6 @@
static struct ctl_table pm_table[] = {
{
- .ctl_name = CTL_UNNUMBERED,
- .procname = "suspend",
- .data = NULL,
- .maxlen = 0,
- .mode = 0600,
- .proc_handler = &pm_do_suspend
- },
- {
.ctl_name = CTL_UNNUMBERED,
.procname = "sleep",
.data = NULL,
diff --git a/arch/mips/basler/excite/excite_procfs.c b/arch/mips/basler/excite/excite_procfs.c
index 9ee67a9..08923e6 100644
--- a/arch/mips/basler/excite/excite_procfs.c
+++ b/arch/mips/basler/excite/excite_procfs.c
@@ -18,8 +18,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-
+#include <linux/module.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/stat.h>
#include <asm/page.h>
#include <asm/io.h>
@@ -28,14 +29,25 @@
#include <excite.h>
-static int excite_get_unit_id(char *buf, char **addr, off_t offs, int size)
+static int excite_unit_id_proc_show(struct seq_file *m, void *v)
{
- const int len = snprintf(buf, PAGE_SIZE, "%06x", unit_id);
- const int w = len - offs;
- *addr = buf + offs;
- return w < size ? w : size;
+ seq_printf(m, "%06x", unit_id);
+ return 0;
}
+static int excite_unit_id_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, excite_unit_id_proc_show, NULL);
+}
+
+static const struct file_operations excite_unit_id_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = excite_unit_id_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static int
excite_bootrom_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
@@ -65,12 +77,12 @@
void excite_procfs_init(void)
{
/* Create & populate /proc/excite */
- struct proc_dir_entry * const pdir = proc_mkdir("excite", &proc_root);
+ struct proc_dir_entry * const pdir = proc_mkdir("excite", NULL);
if (pdir) {
struct proc_dir_entry * e;
- e = create_proc_info_entry("unit_id", S_IRUGO, pdir,
- excite_get_unit_id);
+ e = proc_create("unit_id", S_IRUGO, pdir,
+ &excite_unit_id_proc_fops);
if (e) e->size = 6;
e = create_proc_read_entry("bootrom", S_IRUGO, pdir,
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index 5bf03b3..7294222 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -13,327 +13,285 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
-
+#include <linux/kbuild.h>
#include <asm/ptrace.h>
#include <asm/processor.h>
-#define text(t) __asm__("\n->#" t)
-#define _offset(type, member) (&(((type *)NULL)->member))
-#define offset(string, ptr, member) \
- __asm__("\n->" string " %0" : : "i" (_offset(ptr, member)))
-#define constant(string, member) \
- __asm__("\n->" string " %0" : : "ri" (member))
-#define size(string, size) \
- __asm__("\n->" string " %0" : : "i" (sizeof(size)))
-#define linefeed text("")
-
void output_ptreg_defines(void)
{
- text("MIPS pt_regs offsets.");
- offset("PT_R0", struct pt_regs, regs[0]);
- offset("PT_R1", struct pt_regs, regs[1]);
- offset("PT_R2", struct pt_regs, regs[2]);
- offset("PT_R3", struct pt_regs, regs[3]);
- offset("PT_R4", struct pt_regs, regs[4]);
- offset("PT_R5", struct pt_regs, regs[5]);
- offset("PT_R6", struct pt_regs, regs[6]);
- offset("PT_R7", struct pt_regs, regs[7]);
- offset("PT_R8", struct pt_regs, regs[8]);
- offset("PT_R9", struct pt_regs, regs[9]);
- offset("PT_R10", struct pt_regs, regs[10]);
- offset("PT_R11", struct pt_regs, regs[11]);
- offset("PT_R12", struct pt_regs, regs[12]);
- offset("PT_R13", struct pt_regs, regs[13]);
- offset("PT_R14", struct pt_regs, regs[14]);
- offset("PT_R15", struct pt_regs, regs[15]);
- offset("PT_R16", struct pt_regs, regs[16]);
- offset("PT_R17", struct pt_regs, regs[17]);
- offset("PT_R18", struct pt_regs, regs[18]);
- offset("PT_R19", struct pt_regs, regs[19]);
- offset("PT_R20", struct pt_regs, regs[20]);
- offset("PT_R21", struct pt_regs, regs[21]);
- offset("PT_R22", struct pt_regs, regs[22]);
- offset("PT_R23", struct pt_regs, regs[23]);
- offset("PT_R24", struct pt_regs, regs[24]);
- offset("PT_R25", struct pt_regs, regs[25]);
- offset("PT_R26", struct pt_regs, regs[26]);
- offset("PT_R27", struct pt_regs, regs[27]);
- offset("PT_R28", struct pt_regs, regs[28]);
- offset("PT_R29", struct pt_regs, regs[29]);
- offset("PT_R30", struct pt_regs, regs[30]);
- offset("PT_R31", struct pt_regs, regs[31]);
- offset("PT_LO", struct pt_regs, lo);
- offset("PT_HI", struct pt_regs, hi);
+ COMMENT("MIPS pt_regs offsets.");
+ OFFSET(PT_R0, pt_regs, regs[0]);
+ OFFSET(PT_R1, pt_regs, regs[1]);
+ OFFSET(PT_R2, pt_regs, regs[2]);
+ OFFSET(PT_R3, pt_regs, regs[3]);
+ OFFSET(PT_R4, pt_regs, regs[4]);
+ OFFSET(PT_R5, pt_regs, regs[5]);
+ OFFSET(PT_R6, pt_regs, regs[6]);
+ OFFSET(PT_R7, pt_regs, regs[7]);
+ OFFSET(PT_R8, pt_regs, regs[8]);
+ OFFSET(PT_R9, pt_regs, regs[9]);
+ OFFSET(PT_R10, pt_regs, regs[10]);
+ OFFSET(PT_R11, pt_regs, regs[11]);
+ OFFSET(PT_R12, pt_regs, regs[12]);
+ OFFSET(PT_R13, pt_regs, regs[13]);
+ OFFSET(PT_R14, pt_regs, regs[14]);
+ OFFSET(PT_R15, pt_regs, regs[15]);
+ OFFSET(PT_R16, pt_regs, regs[16]);
+ OFFSET(PT_R17, pt_regs, regs[17]);
+ OFFSET(PT_R18, pt_regs, regs[18]);
+ OFFSET(PT_R19, pt_regs, regs[19]);
+ OFFSET(PT_R20, pt_regs, regs[20]);
+ OFFSET(PT_R21, pt_regs, regs[21]);
+ OFFSET(PT_R22, pt_regs, regs[22]);
+ OFFSET(PT_R23, pt_regs, regs[23]);
+ OFFSET(PT_R24, pt_regs, regs[24]);
+ OFFSET(PT_R25, pt_regs, regs[25]);
+ OFFSET(PT_R26, pt_regs, regs[26]);
+ OFFSET(PT_R27, pt_regs, regs[27]);
+ OFFSET(PT_R28, pt_regs, regs[28]);
+ OFFSET(PT_R29, pt_regs, regs[29]);
+ OFFSET(PT_R30, pt_regs, regs[30]);
+ OFFSET(PT_R31, pt_regs, regs[31]);
+ OFFSET(PT_LO, pt_regs, lo);
+ OFFSET(PT_HI, pt_regs, hi);
#ifdef CONFIG_CPU_HAS_SMARTMIPS
- offset("PT_ACX", struct pt_regs, acx);
+ OFFSET(PT_ACX, pt_regs, acx);
#endif
- offset("PT_EPC", struct pt_regs, cp0_epc);
- offset("PT_BVADDR", struct pt_regs, cp0_badvaddr);
- offset("PT_STATUS", struct pt_regs, cp0_status);
- offset("PT_CAUSE", struct pt_regs, cp0_cause);
+ OFFSET(PT_EPC, pt_regs, cp0_epc);
+ OFFSET(PT_BVADDR, pt_regs, cp0_badvaddr);
+ OFFSET(PT_STATUS, pt_regs, cp0_status);
+ OFFSET(PT_CAUSE, pt_regs, cp0_cause);
#ifdef CONFIG_MIPS_MT_SMTC
- offset("PT_TCSTATUS", struct pt_regs, cp0_tcstatus);
+ OFFSET(PT_TCSTATUS, pt_regs, cp0_tcstatus);
#endif /* CONFIG_MIPS_MT_SMTC */
- size("PT_SIZE", struct pt_regs);
- linefeed;
+ DEFINE(PT_SIZE, sizeof(struct pt_regs));
+ BLANK();
}
void output_task_defines(void)
{
- text("MIPS task_struct offsets.");
- offset("TASK_STATE", struct task_struct, state);
- offset("TASK_THREAD_INFO", struct task_struct, stack);
- offset("TASK_FLAGS", struct task_struct, flags);
- offset("TASK_MM", struct task_struct, mm);
- offset("TASK_PID", struct task_struct, pid);
- size( "TASK_STRUCT_SIZE", struct task_struct);
- linefeed;
+ COMMENT("MIPS task_struct offsets.");
+ OFFSET(TASK_STATE, task_struct, state);
+ OFFSET(TASK_THREAD_INFO, task_struct, stack);
+ OFFSET(TASK_FLAGS, task_struct, flags);
+ OFFSET(TASK_MM, task_struct, mm);
+ OFFSET(TASK_PID, task_struct, pid);
+ DEFINE(TASK_STRUCT_SIZE, sizeof(struct task_struct));
+ BLANK();
}
void output_thread_info_defines(void)
{
- text("MIPS thread_info offsets.");
- offset("TI_TASK", struct thread_info, task);
- offset("TI_EXEC_DOMAIN", struct thread_info, exec_domain);
- offset("TI_FLAGS", struct thread_info, flags);
- offset("TI_TP_VALUE", struct thread_info, tp_value);
- offset("TI_CPU", struct thread_info, cpu);
- offset("TI_PRE_COUNT", struct thread_info, preempt_count);
- offset("TI_ADDR_LIMIT", struct thread_info, addr_limit);
- offset("TI_RESTART_BLOCK", struct thread_info, restart_block);
- offset("TI_REGS", struct thread_info, regs);
- constant("_THREAD_SIZE", THREAD_SIZE);
- constant("_THREAD_MASK", THREAD_MASK);
- linefeed;
+ COMMENT("MIPS thread_info offsets.");
+ OFFSET(TI_TASK, thread_info, task);
+ OFFSET(TI_EXEC_DOMAIN, thread_info, exec_domain);
+ OFFSET(TI_FLAGS, thread_info, flags);
+ OFFSET(TI_TP_VALUE, thread_info, tp_value);
+ OFFSET(TI_CPU, thread_info, cpu);
+ OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
+ OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit);
+ OFFSET(TI_RESTART_BLOCK, thread_info, restart_block);
+ OFFSET(TI_REGS, thread_info, regs);
+ DEFINE(_THREAD_SIZE, THREAD_SIZE);
+ DEFINE(_THREAD_MASK, THREAD_MASK);
+ BLANK();
}
void output_thread_defines(void)
{
- text("MIPS specific thread_struct offsets.");
- offset("THREAD_REG16", struct task_struct, thread.reg16);
- offset("THREAD_REG17", struct task_struct, thread.reg17);
- offset("THREAD_REG18", struct task_struct, thread.reg18);
- offset("THREAD_REG19", struct task_struct, thread.reg19);
- offset("THREAD_REG20", struct task_struct, thread.reg20);
- offset("THREAD_REG21", struct task_struct, thread.reg21);
- offset("THREAD_REG22", struct task_struct, thread.reg22);
- offset("THREAD_REG23", struct task_struct, thread.reg23);
- offset("THREAD_REG29", struct task_struct, thread.reg29);
- offset("THREAD_REG30", struct task_struct, thread.reg30);
- offset("THREAD_REG31", struct task_struct, thread.reg31);
- offset("THREAD_STATUS", struct task_struct,
+ COMMENT("MIPS specific thread_struct offsets.");
+ OFFSET(THREAD_REG16, task_struct, thread.reg16);
+ OFFSET(THREAD_REG17, task_struct, thread.reg17);
+ OFFSET(THREAD_REG18, task_struct, thread.reg18);
+ OFFSET(THREAD_REG19, task_struct, thread.reg19);
+ OFFSET(THREAD_REG20, task_struct, thread.reg20);
+ OFFSET(THREAD_REG21, task_struct, thread.reg21);
+ OFFSET(THREAD_REG22, task_struct, thread.reg22);
+ OFFSET(THREAD_REG23, task_struct, thread.reg23);
+ OFFSET(THREAD_REG29, task_struct, thread.reg29);
+ OFFSET(THREAD_REG30, task_struct, thread.reg30);
+ OFFSET(THREAD_REG31, task_struct, thread.reg31);
+ OFFSET(THREAD_STATUS, task_struct,
thread.cp0_status);
- offset("THREAD_FPU", struct task_struct, thread.fpu);
+ OFFSET(THREAD_FPU, task_struct, thread.fpu);
- offset("THREAD_BVADDR", struct task_struct, \
+ OFFSET(THREAD_BVADDR, task_struct, \
thread.cp0_badvaddr);
- offset("THREAD_BUADDR", struct task_struct, \
+ OFFSET(THREAD_BUADDR, task_struct, \
thread.cp0_baduaddr);
- offset("THREAD_ECODE", struct task_struct, \
+ OFFSET(THREAD_ECODE, task_struct, \
thread.error_code);
- offset("THREAD_TRAPNO", struct task_struct, thread.trap_no);
- offset("THREAD_TRAMP", struct task_struct, \
+ OFFSET(THREAD_TRAPNO, task_struct, thread.trap_no);
+ OFFSET(THREAD_TRAMP, task_struct, \
thread.irix_trampoline);
- offset("THREAD_OLDCTX", struct task_struct, \
+ OFFSET(THREAD_OLDCTX, task_struct, \
thread.irix_oldctx);
- linefeed;
+ BLANK();
}
void output_thread_fpu_defines(void)
{
- offset("THREAD_FPR0",
- struct task_struct, thread.fpu.fpr[0]);
- offset("THREAD_FPR1",
- struct task_struct, thread.fpu.fpr[1]);
- offset("THREAD_FPR2",
- struct task_struct, thread.fpu.fpr[2]);
- offset("THREAD_FPR3",
- struct task_struct, thread.fpu.fpr[3]);
- offset("THREAD_FPR4",
- struct task_struct, thread.fpu.fpr[4]);
- offset("THREAD_FPR5",
- struct task_struct, thread.fpu.fpr[5]);
- offset("THREAD_FPR6",
- struct task_struct, thread.fpu.fpr[6]);
- offset("THREAD_FPR7",
- struct task_struct, thread.fpu.fpr[7]);
- offset("THREAD_FPR8",
- struct task_struct, thread.fpu.fpr[8]);
- offset("THREAD_FPR9",
- struct task_struct, thread.fpu.fpr[9]);
- offset("THREAD_FPR10",
- struct task_struct, thread.fpu.fpr[10]);
- offset("THREAD_FPR11",
- struct task_struct, thread.fpu.fpr[11]);
- offset("THREAD_FPR12",
- struct task_struct, thread.fpu.fpr[12]);
- offset("THREAD_FPR13",
- struct task_struct, thread.fpu.fpr[13]);
- offset("THREAD_FPR14",
- struct task_struct, thread.fpu.fpr[14]);
- offset("THREAD_FPR15",
- struct task_struct, thread.fpu.fpr[15]);
- offset("THREAD_FPR16",
- struct task_struct, thread.fpu.fpr[16]);
- offset("THREAD_FPR17",
- struct task_struct, thread.fpu.fpr[17]);
- offset("THREAD_FPR18",
- struct task_struct, thread.fpu.fpr[18]);
- offset("THREAD_FPR19",
- struct task_struct, thread.fpu.fpr[19]);
- offset("THREAD_FPR20",
- struct task_struct, thread.fpu.fpr[20]);
- offset("THREAD_FPR21",
- struct task_struct, thread.fpu.fpr[21]);
- offset("THREAD_FPR22",
- struct task_struct, thread.fpu.fpr[22]);
- offset("THREAD_FPR23",
- struct task_struct, thread.fpu.fpr[23]);
- offset("THREAD_FPR24",
- struct task_struct, thread.fpu.fpr[24]);
- offset("THREAD_FPR25",
- struct task_struct, thread.fpu.fpr[25]);
- offset("THREAD_FPR26",
- struct task_struct, thread.fpu.fpr[26]);
- offset("THREAD_FPR27",
- struct task_struct, thread.fpu.fpr[27]);
- offset("THREAD_FPR28",
- struct task_struct, thread.fpu.fpr[28]);
- offset("THREAD_FPR29",
- struct task_struct, thread.fpu.fpr[29]);
- offset("THREAD_FPR30",
- struct task_struct, thread.fpu.fpr[30]);
- offset("THREAD_FPR31",
- struct task_struct, thread.fpu.fpr[31]);
+ OFFSET(THREAD_FPR0, task_struct, thread.fpu.fpr[0]);
+ OFFSET(THREAD_FPR1, task_struct, thread.fpu.fpr[1]);
+ OFFSET(THREAD_FPR2, task_struct, thread.fpu.fpr[2]);
+ OFFSET(THREAD_FPR3, task_struct, thread.fpu.fpr[3]);
+ OFFSET(THREAD_FPR4, task_struct, thread.fpu.fpr[4]);
+ OFFSET(THREAD_FPR5, task_struct, thread.fpu.fpr[5]);
+ OFFSET(THREAD_FPR6, task_struct, thread.fpu.fpr[6]);
+ OFFSET(THREAD_FPR7, task_struct, thread.fpu.fpr[7]);
+ OFFSET(THREAD_FPR8, task_struct, thread.fpu.fpr[8]);
+ OFFSET(THREAD_FPR9, task_struct, thread.fpu.fpr[9]);
+ OFFSET(THREAD_FPR10, task_struct, thread.fpu.fpr[10]);
+ OFFSET(THREAD_FPR11, task_struct, thread.fpu.fpr[11]);
+ OFFSET(THREAD_FPR12, task_struct, thread.fpu.fpr[12]);
+ OFFSET(THREAD_FPR13, task_struct, thread.fpu.fpr[13]);
+ OFFSET(THREAD_FPR14, task_struct, thread.fpu.fpr[14]);
+ OFFSET(THREAD_FPR15, task_struct, thread.fpu.fpr[15]);
+ OFFSET(THREAD_FPR16, task_struct, thread.fpu.fpr[16]);
+ OFFSET(THREAD_FPR17, task_struct, thread.fpu.fpr[17]);
+ OFFSET(THREAD_FPR18, task_struct, thread.fpu.fpr[18]);
+ OFFSET(THREAD_FPR19, task_struct, thread.fpu.fpr[19]);
+ OFFSET(THREAD_FPR20, task_struct, thread.fpu.fpr[20]);
+ OFFSET(THREAD_FPR21, task_struct, thread.fpu.fpr[21]);
+ OFFSET(THREAD_FPR22, task_struct, thread.fpu.fpr[22]);
+ OFFSET(THREAD_FPR23, task_struct, thread.fpu.fpr[23]);
+ OFFSET(THREAD_FPR24, task_struct, thread.fpu.fpr[24]);
+ OFFSET(THREAD_FPR25, task_struct, thread.fpu.fpr[25]);
+ OFFSET(THREAD_FPR26, task_struct, thread.fpu.fpr[26]);
+ OFFSET(THREAD_FPR27, task_struct, thread.fpu.fpr[27]);
+ OFFSET(THREAD_FPR28, task_struct, thread.fpu.fpr[28]);
+ OFFSET(THREAD_FPR29, task_struct, thread.fpu.fpr[29]);
+ OFFSET(THREAD_FPR30, task_struct, thread.fpu.fpr[30]);
+ OFFSET(THREAD_FPR31, task_struct, thread.fpu.fpr[31]);
- offset("THREAD_FCR31",
- struct task_struct, thread.fpu.fcr31);
- linefeed;
+ OFFSET(THREAD_FCR31, task_struct, thread.fpu.fcr31);
+ BLANK();
}
void output_mm_defines(void)
{
- text("Size of struct page");
- size("STRUCT_PAGE_SIZE", struct page);
- linefeed;
- text("Linux mm_struct offsets.");
- offset("MM_USERS", struct mm_struct, mm_users);
- offset("MM_PGD", struct mm_struct, pgd);
- offset("MM_CONTEXT", struct mm_struct, context);
- linefeed;
- constant("_PAGE_SIZE", PAGE_SIZE);
- constant("_PAGE_SHIFT", PAGE_SHIFT);
- linefeed;
- constant("_PGD_T_SIZE", sizeof(pgd_t));
- constant("_PMD_T_SIZE", sizeof(pmd_t));
- constant("_PTE_T_SIZE", sizeof(pte_t));
- linefeed;
- constant("_PGD_T_LOG2", PGD_T_LOG2);
- constant("_PMD_T_LOG2", PMD_T_LOG2);
- constant("_PTE_T_LOG2", PTE_T_LOG2);
- linefeed;
- constant("_PGD_ORDER", PGD_ORDER);
- constant("_PMD_ORDER", PMD_ORDER);
- constant("_PTE_ORDER", PTE_ORDER);
- linefeed;
- constant("_PMD_SHIFT", PMD_SHIFT);
- constant("_PGDIR_SHIFT", PGDIR_SHIFT);
- linefeed;
- constant("_PTRS_PER_PGD", PTRS_PER_PGD);
- constant("_PTRS_PER_PMD", PTRS_PER_PMD);
- constant("_PTRS_PER_PTE", PTRS_PER_PTE);
- linefeed;
+ COMMENT("Size of struct page");
+ DEFINE(STRUCT_PAGE_SIZE, sizeof(struct page));
+ BLANK();
+ COMMENT("Linux mm_struct offsets.");
+ OFFSET(MM_USERS, mm_struct, mm_users);
+ OFFSET(MM_PGD, mm_struct, pgd);
+ OFFSET(MM_CONTEXT, mm_struct, context);
+ BLANK();
+ DEFINE(_PAGE_SIZE, PAGE_SIZE);
+ DEFINE(_PAGE_SHIFT, PAGE_SHIFT);
+ BLANK();
+ DEFINE(_PGD_T_SIZE, sizeof(pgd_t));
+ DEFINE(_PMD_T_SIZE, sizeof(pmd_t));
+ DEFINE(_PTE_T_SIZE, sizeof(pte_t));
+ BLANK();
+ DEFINE(_PGD_T_LOG2, PGD_T_LOG2);
+ DEFINE(_PMD_T_LOG2, PMD_T_LOG2);
+ DEFINE(_PTE_T_LOG2, PTE_T_LOG2);
+ BLANK();
+ DEFINE(_PGD_ORDER, PGD_ORDER);
+ DEFINE(_PMD_ORDER, PMD_ORDER);
+ DEFINE(_PTE_ORDER, PTE_ORDER);
+ BLANK();
+ DEFINE(_PMD_SHIFT, PMD_SHIFT);
+ DEFINE(_PGDIR_SHIFT, PGDIR_SHIFT);
+ BLANK();
+ DEFINE(_PTRS_PER_PGD, PTRS_PER_PGD);
+ DEFINE(_PTRS_PER_PMD, PTRS_PER_PMD);
+ DEFINE(_PTRS_PER_PTE, PTRS_PER_PTE);
+ BLANK();
}
#ifdef CONFIG_32BIT
void output_sc_defines(void)
{
- text("Linux sigcontext offsets.");
- offset("SC_REGS", struct sigcontext, sc_regs);
- offset("SC_FPREGS", struct sigcontext, sc_fpregs);
- offset("SC_ACX", struct sigcontext, sc_acx);
- offset("SC_MDHI", struct sigcontext, sc_mdhi);
- offset("SC_MDLO", struct sigcontext, sc_mdlo);
- offset("SC_PC", struct sigcontext, sc_pc);
- offset("SC_FPC_CSR", struct sigcontext, sc_fpc_csr);
- offset("SC_FPC_EIR", struct sigcontext, sc_fpc_eir);
- offset("SC_HI1", struct sigcontext, sc_hi1);
- offset("SC_LO1", struct sigcontext, sc_lo1);
- offset("SC_HI2", struct sigcontext, sc_hi2);
- offset("SC_LO2", struct sigcontext, sc_lo2);
- offset("SC_HI3", struct sigcontext, sc_hi3);
- offset("SC_LO3", struct sigcontext, sc_lo3);
- linefeed;
+ COMMENT("Linux sigcontext offsets.");
+ OFFSET(SC_REGS, sigcontext, sc_regs);
+ OFFSET(SC_FPREGS, sigcontext, sc_fpregs);
+ OFFSET(SC_ACX, sigcontext, sc_acx);
+ OFFSET(SC_MDHI, sigcontext, sc_mdhi);
+ OFFSET(SC_MDLO, sigcontext, sc_mdlo);
+ OFFSET(SC_PC, sigcontext, sc_pc);
+ OFFSET(SC_FPC_CSR, sigcontext, sc_fpc_csr);
+ OFFSET(SC_FPC_EIR, sigcontext, sc_fpc_eir);
+ OFFSET(SC_HI1, sigcontext, sc_hi1);
+ OFFSET(SC_LO1, sigcontext, sc_lo1);
+ OFFSET(SC_HI2, sigcontext, sc_hi2);
+ OFFSET(SC_LO2, sigcontext, sc_lo2);
+ OFFSET(SC_HI3, sigcontext, sc_hi3);
+ OFFSET(SC_LO3, sigcontext, sc_lo3);
+ BLANK();
}
#endif
#ifdef CONFIG_64BIT
void output_sc_defines(void)
{
- text("Linux sigcontext offsets.");
- offset("SC_REGS", struct sigcontext, sc_regs);
- offset("SC_FPREGS", struct sigcontext, sc_fpregs);
- offset("SC_MDHI", struct sigcontext, sc_mdhi);
- offset("SC_MDLO", struct sigcontext, sc_mdlo);
- offset("SC_PC", struct sigcontext, sc_pc);
- offset("SC_FPC_CSR", struct sigcontext, sc_fpc_csr);
- linefeed;
+ COMMENT("Linux sigcontext offsets.");
+ OFFSET(SC_REGS, sigcontext, sc_regs);
+ OFFSET(SC_FPREGS, sigcontext, sc_fpregs);
+ OFFSET(SC_MDHI, sigcontext, sc_mdhi);
+ OFFSET(SC_MDLO, sigcontext, sc_mdlo);
+ OFFSET(SC_PC, sigcontext, sc_pc);
+ OFFSET(SC_FPC_CSR, sigcontext, sc_fpc_csr);
+ BLANK();
}
#endif
#ifdef CONFIG_MIPS32_COMPAT
void output_sc32_defines(void)
{
- text("Linux 32-bit sigcontext offsets.");
- offset("SC32_FPREGS", struct sigcontext32, sc_fpregs);
- offset("SC32_FPC_CSR", struct sigcontext32, sc_fpc_csr);
- offset("SC32_FPC_EIR", struct sigcontext32, sc_fpc_eir);
- linefeed;
+ COMMENT("Linux 32-bit sigcontext offsets.");
+ OFFSET(SC32_FPREGS, sigcontext32, sc_fpregs);
+ OFFSET(SC32_FPC_CSR, sigcontext32, sc_fpc_csr);
+ OFFSET(SC32_FPC_EIR, sigcontext32, sc_fpc_eir);
+ BLANK();
}
#endif
void output_signal_defined(void)
{
- text("Linux signal numbers.");
- constant("_SIGHUP", SIGHUP);
- constant("_SIGINT", SIGINT);
- constant("_SIGQUIT", SIGQUIT);
- constant("_SIGILL", SIGILL);
- constant("_SIGTRAP", SIGTRAP);
- constant("_SIGIOT", SIGIOT);
- constant("_SIGABRT", SIGABRT);
- constant("_SIGEMT", SIGEMT);
- constant("_SIGFPE", SIGFPE);
- constant("_SIGKILL", SIGKILL);
- constant("_SIGBUS", SIGBUS);
- constant("_SIGSEGV", SIGSEGV);
- constant("_SIGSYS", SIGSYS);
- constant("_SIGPIPE", SIGPIPE);
- constant("_SIGALRM", SIGALRM);
- constant("_SIGTERM", SIGTERM);
- constant("_SIGUSR1", SIGUSR1);
- constant("_SIGUSR2", SIGUSR2);
- constant("_SIGCHLD", SIGCHLD);
- constant("_SIGPWR", SIGPWR);
- constant("_SIGWINCH", SIGWINCH);
- constant("_SIGURG", SIGURG);
- constant("_SIGIO", SIGIO);
- constant("_SIGSTOP", SIGSTOP);
- constant("_SIGTSTP", SIGTSTP);
- constant("_SIGCONT", SIGCONT);
- constant("_SIGTTIN", SIGTTIN);
- constant("_SIGTTOU", SIGTTOU);
- constant("_SIGVTALRM", SIGVTALRM);
- constant("_SIGPROF", SIGPROF);
- constant("_SIGXCPU", SIGXCPU);
- constant("_SIGXFSZ", SIGXFSZ);
- linefeed;
+ COMMENT("Linux signal numbers.");
+ DEFINE(_SIGHUP, SIGHUP);
+ DEFINE(_SIGINT, SIGINT);
+ DEFINE(_SIGQUIT, SIGQUIT);
+ DEFINE(_SIGILL, SIGILL);
+ DEFINE(_SIGTRAP, SIGTRAP);
+ DEFINE(_SIGIOT, SIGIOT);
+ DEFINE(_SIGABRT, SIGABRT);
+ DEFINE(_SIGEMT, SIGEMT);
+ DEFINE(_SIGFPE, SIGFPE);
+ DEFINE(_SIGKILL, SIGKILL);
+ DEFINE(_SIGBUS, SIGBUS);
+ DEFINE(_SIGSEGV, SIGSEGV);
+ DEFINE(_SIGSYS, SIGSYS);
+ DEFINE(_SIGPIPE, SIGPIPE);
+ DEFINE(_SIGALRM, SIGALRM);
+ DEFINE(_SIGTERM, SIGTERM);
+ DEFINE(_SIGUSR1, SIGUSR1);
+ DEFINE(_SIGUSR2, SIGUSR2);
+ DEFINE(_SIGCHLD, SIGCHLD);
+ DEFINE(_SIGPWR, SIGPWR);
+ DEFINE(_SIGWINCH, SIGWINCH);
+ DEFINE(_SIGURG, SIGURG);
+ DEFINE(_SIGIO, SIGIO);
+ DEFINE(_SIGSTOP, SIGSTOP);
+ DEFINE(_SIGTSTP, SIGTSTP);
+ DEFINE(_SIGCONT, SIGCONT);
+ DEFINE(_SIGTTIN, SIGTTIN);
+ DEFINE(_SIGTTOU, SIGTTOU);
+ DEFINE(_SIGVTALRM, SIGVTALRM);
+ DEFINE(_SIGPROF, SIGPROF);
+ DEFINE(_SIGXCPU, SIGXCPU);
+ DEFINE(_SIGXFSZ, SIGXFSZ);
+ BLANK();
}
void output_irq_cpustat_t_defines(void)
{
- text("Linux irq_cpustat_t offsets.");
- offset("IC_SOFTIRQ_PENDING", irq_cpustat_t, __softirq_pending);
- size("IC_IRQ_CPUSTAT_T", irq_cpustat_t);
- linefeed;
+ COMMENT("Linux irq_cpustat_t offsets.");
+ DEFINE(IC_SOFTIRQ_PENDING,
+ offsetof(irq_cpustat_t, __softirq_pending));
+ DEFINE(IC_IRQ_CPUSTAT_T, sizeof(irq_cpustat_t));
+ BLANK();
}
diff --git a/arch/mips/kernel/binfmt_elfn32.c b/arch/mips/kernel/binfmt_elfn32.c
index 77db347..9fdd8bc 100644
--- a/arch/mips/kernel/binfmt_elfn32.c
+++ b/arch/mips/kernel/binfmt_elfn32.c
@@ -54,6 +54,7 @@
#include <linux/module.h>
#include <linux/elfcore.h>
#include <linux/compat.h>
+#include <linux/math64.h>
#define elf_prstatus elf_prstatus32
struct elf_prstatus32
@@ -102,8 +103,8 @@
* one divide.
*/
u64 nsec = (u64)jiffies * TICK_NSEC;
- long rem;
- value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+ u32 rem;
+ value->tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
value->tv_usec = rem / NSEC_PER_USEC;
}
diff --git a/arch/mips/kernel/binfmt_elfo32.c b/arch/mips/kernel/binfmt_elfo32.c
index 08f4cd7..e1333d7 100644
--- a/arch/mips/kernel/binfmt_elfo32.c
+++ b/arch/mips/kernel/binfmt_elfo32.c
@@ -56,6 +56,7 @@
#include <linux/module.h>
#include <linux/elfcore.h>
#include <linux/compat.h>
+#include <linux/math64.h>
#define elf_prstatus elf_prstatus32
struct elf_prstatus32
@@ -104,8 +105,8 @@
* one divide.
*/
u64 nsec = (u64)jiffies * TICK_NSEC;
- long rem;
- value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+ u32 rem;
+ value->tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem);
value->tv_usec = rem / NSEC_PER_USEC;
}
diff --git a/arch/mips/kernel/irixioctl.c b/arch/mips/kernel/irixioctl.c
index 2bde200d..b39bdba 100644
--- a/arch/mips/kernel/irixioctl.c
+++ b/arch/mips/kernel/irixioctl.c
@@ -27,33 +27,6 @@
cc_t c_cc[NCCS];
};
-extern void start_tty(struct tty_struct *tty);
-static struct tty_struct *get_tty(int fd)
-{
- struct file *filp;
- struct tty_struct *ttyp = NULL;
-
- rcu_read_lock();
- filp = fcheck(fd);
- if(filp && filp->private_data) {
- ttyp = (struct tty_struct *) filp->private_data;
-
- if(ttyp->magic != TTY_MAGIC)
- ttyp =NULL;
- }
- rcu_read_unlock();
- return ttyp;
-}
-
-static struct tty_struct *get_real_tty(struct tty_struct *tp)
-{
- if (tp->driver->type == TTY_DRIVER_TYPE_PTY &&
- tp->driver->subtype == PTY_TYPE_MASTER)
- return tp->link;
- else
- return tp;
-}
-
asmlinkage int irix_ioctl(int fd, unsigned long cmd, unsigned long arg)
{
struct tty_struct *tp, *rtp;
@@ -146,34 +119,24 @@
error = sys_ioctl(fd, TIOCNOTTY, arg);
break;
- case 0x00007416:
+ case 0x00007416: {
+ pid_t pid;
#ifdef DEBUG_IOCTLS
printk("TIOCGSID, %08lx) ", arg);
#endif
- tp = get_tty(fd);
- if(!tp) {
- error = -EINVAL;
- break;
- }
- rtp = get_real_tty(tp);
-#ifdef DEBUG_IOCTLS
- printk("rtp->session=%d ", rtp->session);
-#endif
- error = put_user(rtp->session, (unsigned long __user *) arg);
+ old_fs = get_fs(); set_fs(get_ds());
+ error = sys_ioctl(fd, TIOCGSID, (unsigned long)&pid);
+ set_fs(old_fs);
+ if (!error)
+ error = put_user(pid, (unsigned long __user *) arg);
break;
-
+ }
case 0x746e:
/* TIOCSTART, same effect as hitting ^Q */
#ifdef DEBUG_IOCTLS
printk("TIOCSTART, %08lx) ", arg);
#endif
- tp = get_tty(fd);
- if(!tp) {
- error = -EINVAL;
- break;
- }
- rtp = get_real_tty(tp);
- start_tty(rtp);
+ error = sys_ioctl(fd, TCXONC, TCOON);
break;
case 0x20006968:
diff --git a/arch/mips/kernel/kspd.c b/arch/mips/kernel/kspd.c
index 998c4ef..ceb62dc 100644
--- a/arch/mips/kernel/kspd.c
+++ b/arch/mips/kernel/kspd.c
@@ -20,6 +20,7 @@
#include <linux/sched.h>
#include <linux/unistd.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/syscalls.h>
#include <linux/workqueue.h>
diff --git a/arch/mips/lib/iomap-pci.c b/arch/mips/lib/iomap-pci.c
index c11b249..2ab899c 100644
--- a/arch/mips/lib/iomap-pci.c
+++ b/arch/mips/lib/iomap-pci.c
@@ -45,8 +45,8 @@
*/
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
index 855977c..6537d90 100644
--- a/arch/mips/pmc-sierra/yosemite/setup.c
+++ b/arch/mips/pmc-sierra/yosemite/setup.c
@@ -143,9 +143,6 @@
mips_hpt_frequency = 33000000 * 3 * 5;
}
-/* No other usable initialization hook than this ... */
-extern void (*late_time_init)(void);
-
unsigned long ocd_base;
EXPORT_SYMBOL(ocd_base);
diff --git a/arch/mn10300/kernel/asm-offsets.c b/arch/mn10300/kernel/asm-offsets.c
index ee2d9f8..2646fcb 100644
--- a/arch/mn10300/kernel/asm-offsets.c
+++ b/arch/mn10300/kernel/asm-offsets.c
@@ -7,6 +7,7 @@
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/personality.h>
+#include <linux/kbuild.h>
#include <asm/ucontext.h>
#include <asm/processor.h>
#include <asm/thread_info.h>
@@ -14,14 +15,6 @@
#include "sigframe.h"
#include "mn10300-serial.h"
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->")
-
-#define OFFSET(sym, str, mem) \
- DEFINE(sym, offsetof(struct str, mem));
-
void foo(void)
{
OFFSET(SIGCONTEXT_d0, sigcontext, d0);
diff --git a/arch/mn10300/unit-asb2305/pci-iomap.c b/arch/mn10300/unit-asb2305/pci-iomap.c
index dbceae4..c1a8d8f 100644
--- a/arch/mn10300/unit-asb2305/pci-iomap.c
+++ b/arch/mn10300/unit-asb2305/pci-iomap.c
@@ -16,8 +16,8 @@
*/
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
index eaa79bc..3efc0b7 100644
--- a/arch/parisc/kernel/asm-offsets.c
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -32,6 +32,7 @@
#include <linux/thread_info.h>
#include <linux/ptrace.h>
#include <linux/hardirq.h>
+#include <linux/kbuild.h>
#include <asm/pgtable.h>
#include <asm/ptrace.h>
@@ -39,11 +40,6 @@
#include <asm/pdc.h>
#include <asm/uaccess.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
#ifdef CONFIG_64BIT
#define FRAME_SIZE 128
#else
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
index 9448d4e..ccd61b9 100644
--- a/arch/parisc/kernel/pci-dma.c
+++ b/arch/parisc/kernel/pci-dma.c
@@ -397,10 +397,9 @@
"pcxl_dma_init: Unable to create gsc /proc dir entry\n");
else {
struct proc_dir_entry* ent;
- ent = create_proc_entry("pcxl_dma", 0, proc_gsc_root);
- if (ent)
- ent->proc_fops = &proc_pcxl_dma_ops;
- else
+ ent = proc_create("pcxl_dma", 0, proc_gsc_root,
+ &proc_pcxl_dma_ops);
+ if (!ent)
printk(KERN_WARNING
"pci-dma.c: Unable to create pcxl_dma /proc entry.\n");
}
diff --git a/arch/parisc/lib/iomap.c b/arch/parisc/lib/iomap.c
index f4a81169..9abed07 100644
--- a/arch/parisc/lib/iomap.c
+++ b/arch/parisc/lib/iomap.c
@@ -438,8 +438,8 @@
/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index af1d2c8..ec9228d 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -30,6 +30,7 @@
#include <linux/time.h>
#include <linux/hardirq.h>
#endif
+#include <linux/kbuild.h>
#include <asm/io.h>
#include <asm/page.h>
@@ -51,11 +52,6 @@
#include <asm/iseries/alpaca.h>
#endif
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
int main(void)
{
DEFINE(THREAD, offsetof(struct task_struct, thread));
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c
index 1ffacc6..1e656b4 100644
--- a/arch/powerpc/kernel/lparcfg.c
+++ b/arch/powerpc/kernel/lparcfg.c
@@ -591,10 +591,8 @@
!firmware_has_feature(FW_FEATURE_ISERIES))
mode |= S_IWUSR;
- ent = create_proc_entry("ppc64/lparcfg", mode, NULL);
- if (ent) {
- ent->proc_fops = &lparcfg_fops;
- } else {
+ ent = proc_create("ppc64/lparcfg", mode, NULL, &lparcfg_fops);
+ if (!ent) {
printk(KERN_ERR "Failed to create ppc64/lparcfg\n");
return -EIO;
}
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c
index 09fcb50..cf6b5a7 100644
--- a/arch/powerpc/kernel/ppc_ksyms.c
+++ b/arch/powerpc/kernel/ppc_ksyms.c
@@ -133,9 +133,6 @@
EXPORT_SYMBOL(cuda_request);
EXPORT_SYMBOL(cuda_poll);
#endif /* CONFIG_ADB_CUDA */
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(kd_mksound);
-#endif
EXPORT_SYMBOL(to_tm);
#ifdef CONFIG_PPC32
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
index f78dfce..c647dde 100644
--- a/arch/powerpc/kernel/proc_ppc64.c
+++ b/arch/powerpc/kernel/proc_ppc64.c
@@ -68,12 +68,11 @@
{
struct proc_dir_entry *pde;
- pde = create_proc_entry("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL);
+ pde = proc_create_data("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL,
+ &page_map_fops, vdso_data);
if (!pde)
return 1;
- pde->data = vdso_data;
pde->size = PAGE_SIZE;
- pde->proc_fops = &page_map_fops;
return 0;
}
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
index f2e3bc7..f9c6abc 100644
--- a/arch/powerpc/kernel/rtas-proc.c
+++ b/arch/powerpc/kernel/rtas-proc.c
@@ -255,8 +255,6 @@
static int __init proc_rtas_init(void)
{
- struct proc_dir_entry *entry;
-
if (!machine_is(pseries))
return -ENODEV;
@@ -264,35 +262,20 @@
if (rtas_node == NULL)
return -ENODEV;
- entry = create_proc_entry("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL);
- if (entry)
- entry->proc_fops = &ppc_rtas_progress_operations;
-
- entry = create_proc_entry("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL);
- if (entry)
- entry->proc_fops = &ppc_rtas_clock_operations;
-
- entry = create_proc_entry("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL);
- if (entry)
- entry->proc_fops = &ppc_rtas_poweron_operations;
-
- entry = create_proc_entry("ppc64/rtas/sensors", S_IRUGO, NULL);
- if (entry)
- entry->proc_fops = &ppc_rtas_sensors_operations;
-
- entry = create_proc_entry("ppc64/rtas/frequency", S_IWUSR|S_IRUGO,
- NULL);
- if (entry)
- entry->proc_fops = &ppc_rtas_tone_freq_operations;
-
- entry = create_proc_entry("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL);
- if (entry)
- entry->proc_fops = &ppc_rtas_tone_volume_operations;
-
- entry = create_proc_entry("ppc64/rtas/rmo_buffer", S_IRUSR, NULL);
- if (entry)
- entry->proc_fops = &ppc_rtas_rmo_buf_ops;
-
+ proc_create("ppc64/rtas/progress", S_IRUGO|S_IWUSR, NULL,
+ &ppc_rtas_progress_operations);
+ proc_create("ppc64/rtas/clock", S_IRUGO|S_IWUSR, NULL,
+ &ppc_rtas_clock_operations);
+ proc_create("ppc64/rtas/poweron", S_IWUSR|S_IRUGO, NULL,
+ &ppc_rtas_poweron_operations);
+ proc_create("ppc64/rtas/sensors", S_IRUGO, NULL,
+ &ppc_rtas_sensors_operations);
+ proc_create("ppc64/rtas/frequency", S_IWUSR|S_IRUGO, NULL,
+ &ppc_rtas_tone_freq_operations);
+ proc_create("ppc64/rtas/volume", S_IWUSR|S_IRUGO, NULL,
+ &ppc_rtas_tone_volume_operations);
+ proc_create("ppc64/rtas/rmo_buffer", S_IRUSR, NULL,
+ &ppc_rtas_rmo_buf_ops);
return 0;
}
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c
index 627f126..0a5e22b 100644
--- a/arch/powerpc/kernel/rtas_flash.c
+++ b/arch/powerpc/kernel/rtas_flash.c
@@ -704,18 +704,11 @@
static struct proc_dir_entry *create_flash_pde(const char *filename,
const struct file_operations *fops)
{
- struct proc_dir_entry *ent = NULL;
-
- ent = create_proc_entry(filename, S_IRUSR | S_IWUSR, NULL);
- if (ent != NULL) {
- ent->proc_fops = fops;
- ent->owner = THIS_MODULE;
- }
-
- return ent;
+ return proc_create(filename, S_IRUSR | S_IWUSR, NULL, fops);
}
static const struct file_operations rtas_flash_operations = {
+ .owner = THIS_MODULE,
.read = rtas_flash_read,
.write = rtas_flash_write,
.open = rtas_excl_open,
@@ -723,6 +716,7 @@
};
static const struct file_operations manage_flash_operations = {
+ .owner = THIS_MODULE,
.read = manage_flash_read,
.write = manage_flash_write,
.open = rtas_excl_open,
@@ -730,6 +724,7 @@
};
static const struct file_operations validate_flash_operations = {
+ .owner = THIS_MODULE,
.read = validate_flash_read,
.write = validate_flash_write,
.open = rtas_excl_open,
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 3b26fbd6..73401e8 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -149,7 +149,7 @@
u64 tb_to_xs;
unsigned tb_to_us;
-#define TICKLEN_SCALE TICK_LENGTH_SHIFT
+#define TICKLEN_SCALE NTP_SCALE_SHIFT
u64 last_tick_len; /* units are ns / 2^TICKLEN_SCALE */
u64 ticklen_to_xs; /* 0.64 fraction */
@@ -1007,8 +1007,6 @@
vdso_data->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;
vdso_data->tb_to_xs = tb_to_xs;
- time_freq = 0;
-
write_sequnlock_irqrestore(&xtime_lock, flags);
/* Register the clocksource, if we're not running on iSeries */
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c
index b962c3a..af116aa 100644
--- a/arch/powerpc/platforms/cell/spufs/coredump.c
+++ b/arch/powerpc/platforms/cell/spufs/coredump.c
@@ -22,6 +22,7 @@
#include <linux/elf.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/module.h>
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 62280c2..7298e7d 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -1065,10 +1065,9 @@
mod_timer(&spuloadavg_timer, 0);
- entry = create_proc_entry("spu_loadavg", 0, NULL);
+ entry = proc_create("spu_loadavg", 0, NULL, &spu_loadavg_fops);
if (!entry)
goto out_stop_kthread;
- entry->proc_fops = &spu_loadavg_fops;
pr_debug("spusched: tick: %d, min ticks: %d, default ticks: %d\n",
SPUSCHED_TICK, MIN_SPU_TIMESLICE, DEF_SPU_TIMESLICE);
diff --git a/arch/powerpc/platforms/cell/spufs/sputrace.c b/arch/powerpc/platforms/cell/spufs/sputrace.c
index b9c79ed..5320242 100644
--- a/arch/powerpc/platforms/cell/spufs/sputrace.c
+++ b/arch/powerpc/platforms/cell/spufs/sputrace.c
@@ -201,10 +201,9 @@
if (!sputrace_log)
goto out;
- entry = create_proc_entry("sputrace", S_IRUSR, NULL);
+ entry = proc_create("sputrace", S_IRUSR, NULL, &sputrace_fops);
if (!entry)
goto out_free_log;
- entry->proc_fops = &sputrace_fops;
for (i = 0; i < ARRAY_SIZE(spu_probes); i++) {
struct spu_probe *p = &spu_probes[i];
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c
index e5b40e3..b0f8a85 100644
--- a/arch/powerpc/platforms/iseries/lpevents.c
+++ b/arch/powerpc/platforms/iseries/lpevents.c
@@ -330,15 +330,11 @@
static int __init proc_lpevents_init(void)
{
- struct proc_dir_entry *e;
-
if (!firmware_has_feature(FW_FEATURE_ISERIES))
return 0;
- e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL);
- if (e)
- e->proc_fops = &proc_lpevents_operations;
-
+ proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL,
+ &proc_lpevents_operations);
return 0;
}
__initcall(proc_lpevents_init);
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
index c0f2433..1dc7295 100644
--- a/arch/powerpc/platforms/iseries/mf.c
+++ b/arch/powerpc/platforms/iseries/mf.c
@@ -1255,11 +1255,11 @@
if (i == 3) /* no vmlinux entry for 'D' */
continue;
- ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf);
+ ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf,
+ &proc_vmlinux_operations,
+ (void *)(long)i);
if (!ent)
return 1;
- ent->data = (void *)(long)i;
- ent->proc_fops = &proc_vmlinux_operations;
}
ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root);
diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c
index f2cde41..91f4c6c 100644
--- a/arch/powerpc/platforms/iseries/proc.c
+++ b/arch/powerpc/platforms/iseries/proc.c
@@ -110,15 +110,11 @@
static int __init iseries_proc_init(void)
{
- struct proc_dir_entry *e;
-
if (!firmware_has_feature(FW_FEATURE_ISERIES))
return 0;
- e = create_proc_entry("iSeries/titanTod", S_IFREG|S_IRUGO, NULL);
- if (e)
- e->proc_fops = &proc_titantod_operations;
-
+ proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL,
+ &proc_titantod_operations);
return 0;
}
__initcall(iseries_proc_init);
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
index df23331..49ff4dc 100644
--- a/arch/powerpc/platforms/iseries/viopath.c
+++ b/arch/powerpc/platforms/iseries/viopath.c
@@ -180,15 +180,10 @@
static int __init vio_proc_init(void)
{
- struct proc_dir_entry *e;
-
if (!firmware_has_feature(FW_FEATURE_ISERIES))
return 0;
- e = create_proc_entry("iSeries/config", 0, NULL);
- if (e)
- e->proc_fops = &proc_viopath_operations;
-
+ proc_create("iSeries/config", 0, NULL, &proc_viopath_operations);
return 0;
}
__initcall(vio_proc_init);
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index a3fd56b..6f544ba 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1259,14 +1259,8 @@
static int __init eeh_init_proc(void)
{
- struct proc_dir_entry *e;
-
- if (machine_is(pseries)) {
- e = create_proc_entry("ppc64/eeh", 0, NULL);
- if (e)
- e->proc_fops = &proc_eeh_operations;
- }
-
+ if (machine_is(pseries))
+ proc_create("ppc64/eeh", 0, NULL, &proc_eeh_operations);
return 0;
}
__initcall(eeh_init_proc);
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index ac75c10..75769aa 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -512,12 +512,9 @@
if (!machine_is(pseries))
return 0;
- ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
- if (ent) {
- ent->data = NULL;
+ ent = proc_create("ppc64/ofdt", S_IWUSR, NULL, &ofdt_fops);
+ if (ent)
ent->size = 0;
- ent->proc_fops = &ofdt_fops;
- }
return 0;
}
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index befadd4..7d3e2b0 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -468,10 +468,9 @@
return -ENOMEM;
}
- entry = create_proc_entry("ppc64/rtas/error_log", S_IRUSR, NULL);
- if (entry)
- entry->proc_fops = &proc_rtas_log_operations;
- else
+ entry = proc_create("ppc64/rtas/error_log", S_IRUSR, NULL,
+ &proc_rtas_log_operations);
+ if (!entry)
printk(KERN_ERR "Failed to create error_log proc entry\n");
if (kernel_thread(rtasd, NULL, CLONE_FS) < 0)
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index b594087..3a7054e 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -418,22 +418,21 @@
#include <linux/i2c.h>
struct i2c_driver_device {
char *of_device;
- char *i2c_driver;
char *i2c_type;
};
static struct i2c_driver_device i2c_devices[] __initdata = {
- {"ricoh,rs5c372a", "rtc-rs5c372", "rs5c372a",},
- {"ricoh,rs5c372b", "rtc-rs5c372", "rs5c372b",},
- {"ricoh,rv5c386", "rtc-rs5c372", "rv5c386",},
- {"ricoh,rv5c387a", "rtc-rs5c372", "rv5c387a",},
- {"dallas,ds1307", "rtc-ds1307", "ds1307",},
- {"dallas,ds1337", "rtc-ds1307", "ds1337",},
- {"dallas,ds1338", "rtc-ds1307", "ds1338",},
- {"dallas,ds1339", "rtc-ds1307", "ds1339",},
- {"dallas,ds1340", "rtc-ds1307", "ds1340",},
- {"stm,m41t00", "rtc-ds1307", "m41t00"},
- {"dallas,ds1374", "rtc-ds1374", "rtc-ds1374",},
+ {"ricoh,rs5c372a", "rs5c372a"},
+ {"ricoh,rs5c372b", "rs5c372b"},
+ {"ricoh,rv5c386", "rv5c386"},
+ {"ricoh,rv5c387a", "rv5c387a"},
+ {"dallas,ds1307", "ds1307"},
+ {"dallas,ds1337", "ds1337"},
+ {"dallas,ds1338", "ds1338"},
+ {"dallas,ds1339", "ds1339"},
+ {"dallas,ds1340", "ds1340"},
+ {"stm,m41t00", "m41t00"},
+ {"dallas,ds1374", "rtc-ds1374"},
};
static int __init of_find_i2c_driver(struct device_node *node,
@@ -444,9 +443,7 @@
for (i = 0; i < ARRAY_SIZE(i2c_devices); i++) {
if (!of_device_is_compatible(node, i2c_devices[i].of_device))
continue;
- if (strlcpy(info->driver_name, i2c_devices[i].i2c_driver,
- KOBJ_NAME_LEN) >= KOBJ_NAME_LEN ||
- strlcpy(info->type, i2c_devices[i].i2c_type,
+ if (strlcpy(info->type, i2c_devices[i].i2c_type,
I2C_NAME_SIZE) >= I2C_NAME_SIZE)
return -ENOMEM;
return 0;
diff --git a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
index a51a177..8dcbdd6 100644
--- a/arch/ppc/kernel/asm-offsets.c
+++ b/arch/ppc/kernel/asm-offsets.c
@@ -18,6 +18,8 @@
#include <linux/suspend.h>
#include <linux/mman.h>
#include <linux/mm.h>
+#include <linux/kbuild.h>
+
#include <asm/io.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -26,11 +28,6 @@
#include <asm/thread_info.h>
#include <asm/vdso_datapage.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
int
main(void)
{
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 50ce83f..df3ef6d 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1121,8 +1121,8 @@
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len)
diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
index d9036ef..16ac11c 100644
--- a/arch/ppc/kernel/ppc_ksyms.c
+++ b/arch/ppc/kernel/ppc_ksyms.c
@@ -183,9 +183,6 @@
#if defined(CONFIG_BOOTX_TEXT)
EXPORT_SYMBOL(btext_update_display);
#endif
-#ifdef CONFIG_VT
-EXPORT_SYMBOL(kd_mksound);
-#endif
EXPORT_SYMBOL(to_tm);
EXPORT_SYMBOL(pm_power_off);
diff --git a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c
index 0df6aac..24f6e06 100644
--- a/arch/ppc/platforms/sbc82xx.c
+++ b/arch/ppc/platforms/sbc82xx.c
@@ -30,8 +30,6 @@
extern unsigned char __res[sizeof(bd_t)];
-extern void (*late_time_init)(void);
-
#ifdef CONFIG_GEN_RTC
TODC_ALLOC();
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 8f5f021..29a7940 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -300,6 +300,14 @@
source "kernel/Kconfig.preempt"
+config ARCH_SPARSEMEM_ENABLE
+ def_bool y
+ select SPARSEMEM_VMEMMAP_ENABLE
+ select SPARSEMEM_VMEMMAP
+
+config ARCH_SPARSEMEM_DEFAULT
+ def_bool y
+
source "mm/Kconfig"
comment "I/O subsystem configuration"
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index a72f208..aa341d0e 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.25-rc4
-# Wed Mar 5 11:22:59 2008
+# Linux kernel version: 2.6.25
+# Wed Apr 30 11:07:45 2008
#
CONFIG_SCHED_MC=y
CONFIG_MMU=y
@@ -14,10 +14,12 @@
# CONFIG_ARCH_HAS_ILOG2_U64 is not set
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
CONFIG_GENERIC_BUG=y
CONFIG_NO_IOMEM=y
CONFIG_NO_DMA=y
CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_PGSTE=y
CONFIG_S390=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -43,6 +45,7 @@
CONFIG_CGROUPS=y
# CONFIG_CGROUP_DEBUG is not set
CONFIG_CGROUP_NS=y
+# CONFIG_CGROUP_DEVICE is not set
# CONFIG_CPUSETS is not set
CONFIG_GROUP_SCHED=y
CONFIG_FAIR_GROUP_SCHED=y
@@ -65,6 +68,7 @@
CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
CONFIG_SYSCTL_SYSCALL=y
+CONFIG_SYSCTL_SYSCALL_CHECK=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -92,6 +96,7 @@
CONFIG_KRETPROBES=y
CONFIG_HAVE_KPROBES=y
CONFIG_HAVE_KRETPROBES=y
+# CONFIG_HAVE_DMA_ATTRS is not set
CONFIG_PROC_PAGE_MONITOR=y
CONFIG_SLABINFO=y
CONFIG_RT_MUTEXES=y
@@ -121,8 +126,8 @@
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="deadline"
+CONFIG_PREEMPT_NOTIFIERS=y
CONFIG_CLASSIC_RCU=y
-# CONFIG_PREEMPT_RCU is not set
#
# Base setup
@@ -131,6 +136,10 @@
#
# Processor type and features
#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
CONFIG_64BIT=y
CONFIG_SMP=y
CONFIG_NR_CPUS=32
@@ -161,15 +170,20 @@
# CONFIG_PREEMPT_NONE is not set
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
-# CONFIG_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
+# CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
# CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_RESOURCES_64BIT=y
CONFIG_ZONE_DMA_FLAG=1
@@ -205,11 +219,10 @@
# CONFIG_HZ_1000 is not set
CONFIG_HZ=100
# CONFIG_SCHED_HRTICK is not set
-CONFIG_NO_IDLE_HZ=y
-CONFIG_NO_IDLE_HZ_INIT=y
CONFIG_S390_HYPFS_FS=y
CONFIG_KEXEC=y
# CONFIG_ZFCPDUMP is not set
+CONFIG_S390_GUEST=y
#
# Networking
@@ -272,8 +285,10 @@
CONFIG_INET6_XFRM_MODE_BEET=y
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
# CONFIG_IPV6_TUNNEL is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
# CONFIG_NETWORK_SECMARK is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
@@ -289,6 +304,7 @@
# CONFIG_NF_CT_ACCT is not set
# CONFIG_NF_CONNTRACK_MARK is not set
# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
# CONFIG_NF_CT_PROTO_SCTP is not set
# CONFIG_NF_CT_PROTO_UDPLITE is not set
# CONFIG_NF_CONNTRACK_AMANDA is not set
@@ -439,6 +455,7 @@
CONFIG_DASD_FBA=y
CONFIG_DASD_DIAG=y
CONFIG_DASD_EER=y
+CONFIG_VIRTIO_BLK=m
CONFIG_MISC_DEVICES=y
# CONFIG_EEPROM_93CX6 is not set
# CONFIG_ENCLOSURE_SERVICES is not set
@@ -533,7 +550,7 @@
# S/390 network device drivers
#
CONFIG_LCS=m
-CONFIG_CTC=m
+CONFIG_CTCM=m
# CONFIG_NETIUCV is not set
# CONFIG_SMSGIUCV is not set
# CONFIG_CLAW is not set
@@ -547,10 +564,12 @@
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
# CONFIG_NET_POLL_CONTROLLER is not set
+CONFIG_VIRTIO_NET=m
#
# Character devices
#
+CONFIG_DEVKMEM=y
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -600,6 +619,7 @@
# Sonics Silicon Backplane
#
# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
#
# File systems
@@ -652,6 +672,7 @@
CONFIG_SYSFS=y
CONFIG_TMPFS=y
CONFIG_TMPFS_POSIX_ACL=y
+# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_CONFIGFS_FS=m
@@ -678,12 +699,10 @@
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=y
CONFIG_NFSD_V3=y
# CONFIG_NFSD_V3_ACL is not set
# CONFIG_NFSD_V4 is not set
-CONFIG_NFSD_TCP=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
@@ -731,6 +750,7 @@
# CONFIG_PRINTK_TIME is not set
CONFIG_ENABLE_WARN_DEPRECATED=y
CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_FS=y
@@ -754,6 +774,7 @@
CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
# CONFIG_FRAME_POINTER is not set
@@ -775,58 +796,88 @@
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_AEAD=m
CONFIG_CRYPTO_BLKCIPHER=y
-CONFIG_CRYPTO_SEQIV=m
CONFIG_CRYPTO_HASH=m
CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_GF128MUL=m
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+CONFIG_CRYPTO_CCM=m
+CONFIG_CRYPTO_GCM=m
+CONFIG_CRYPTO_SEQIV=m
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_CTR=m
+CONFIG_CRYPTO_CTS=m
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
CONFIG_CRYPTO_HMAC=m
# CONFIG_CRYPTO_XCBC is not set
-# CONFIG_CRYPTO_NULL is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_MD4 is not set
CONFIG_CRYPTO_MD5=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
CONFIG_CRYPTO_SHA1=m
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
-# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
-CONFIG_CRYPTO_GF128MUL=m
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_XTS is not set
-CONFIG_CRYPTO_CTR=m
-CONFIG_CRYPTO_GCM=m
-CONFIG_CRYPTO_CCM=m
-# CONFIG_CRYPTO_CRYPTD is not set
-# CONFIG_CRYPTO_DES is not set
-CONFIG_CRYPTO_FCRYPT=m
-# CONFIG_CRYPTO_BLOWFISH is not set
-# CONFIG_CRYPTO_TWOFISH is not set
-# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+CONFIG_CRYPTO_CAMELLIA=m
# CONFIG_CRYPTO_CAST5 is not set
# CONFIG_CRYPTO_CAST6 is not set
-# CONFIG_CRYPTO_TEA is not set
-# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_DES is not set
+CONFIG_CRYPTO_FCRYPT=m
# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-CONFIG_CRYPTO_SEED=m
CONFIG_CRYPTO_SALSA20=m
+CONFIG_CRYPTO_SEED=m
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
# CONFIG_CRYPTO_DEFLATE is not set
-# CONFIG_CRYPTO_MICHAEL_MIC is not set
-# CONFIG_CRYPTO_CRC32C is not set
-CONFIG_CRYPTO_CAMELLIA=m
-# CONFIG_CRYPTO_TEST is not set
-CONFIG_CRYPTO_AUTHENC=m
CONFIG_CRYPTO_LZO=m
CONFIG_CRYPTO_HW=y
CONFIG_ZCRYPT=m
# CONFIG_ZCRYPT_MONOLITHIC is not set
# CONFIG_CRYPTO_SHA1_S390 is not set
# CONFIG_CRYPTO_SHA256_S390 is not set
+CONFIG_CRYPTO_SHA512_S390=m
# CONFIG_CRYPTO_DES_S390 is not set
# CONFIG_CRYPTO_AES_S390 is not set
CONFIG_S390_PRNG=m
@@ -835,6 +886,8 @@
# Library routines
#
CONFIG_BITREVERSE=m
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
+# CONFIG_GENERIC_FIND_NEXT_BIT is not set
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
@@ -844,3 +897,9 @@
CONFIG_LZO_COMPRESS=m
CONFIG_LZO_DECOMPRESS=m
CONFIG_PLIST=y
+CONFIG_HAVE_KVM=y
+CONFIG_VIRTUALIZATION=y
+CONFIG_KVM=m
+CONFIG_VIRTIO=y
+CONFIG_VIRTIO_RING=y
+CONFIG_VIRTIO_BALLOON=m
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 77051cd..6302f50 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -2,8 +2,6 @@
# Makefile for the linux kernel.
#
-EXTRA_AFLAGS := -traditional
-
#
# Passing null pointers is ok for smp code, since we access the lowcore here.
#
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c
index 1375f8a..fa28eca 100644
--- a/arch/s390/kernel/asm-offsets.c
+++ b/arch/s390/kernel/asm-offsets.c
@@ -5,44 +5,38 @@
*/
#include <linux/sched.h>
-
-/* Use marker if you need to separate the values later */
-
-#define DEFINE(sym, val, marker) \
- asm volatile("\n->" #sym " %0 " #val " " #marker : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
+#include <linux/kbuild.h>
int main(void)
{
- DEFINE(__THREAD_info, offsetof(struct task_struct, stack),);
- DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp),);
- DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info),);
+ DEFINE(__THREAD_info, offsetof(struct task_struct, stack));
+ DEFINE(__THREAD_ksp, offsetof(struct task_struct, thread.ksp));
+ DEFINE(__THREAD_per, offsetof(struct task_struct, thread.per_info));
DEFINE(__THREAD_mm_segment,
- offsetof(struct task_struct, thread.mm_segment),);
+ offsetof(struct task_struct, thread.mm_segment));
BLANK();
- DEFINE(__TASK_pid, offsetof(struct task_struct, pid),);
+ DEFINE(__TASK_pid, offsetof(struct task_struct, pid));
BLANK();
- DEFINE(__PER_atmid, offsetof(per_struct, lowcore.words.perc_atmid),);
- DEFINE(__PER_address, offsetof(per_struct, lowcore.words.address),);
- DEFINE(__PER_access_id, offsetof(per_struct, lowcore.words.access_id),);
+ DEFINE(__PER_atmid, offsetof(per_struct, lowcore.words.perc_atmid));
+ DEFINE(__PER_address, offsetof(per_struct, lowcore.words.address));
+ DEFINE(__PER_access_id, offsetof(per_struct, lowcore.words.access_id));
BLANK();
- DEFINE(__TI_task, offsetof(struct thread_info, task),);
- DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain),);
- DEFINE(__TI_flags, offsetof(struct thread_info, flags),);
- DEFINE(__TI_cpu, offsetof(struct thread_info, cpu),);
- DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count),);
+ DEFINE(__TI_task, offsetof(struct thread_info, task));
+ DEFINE(__TI_domain, offsetof(struct thread_info, exec_domain));
+ DEFINE(__TI_flags, offsetof(struct thread_info, flags));
+ DEFINE(__TI_cpu, offsetof(struct thread_info, cpu));
+ DEFINE(__TI_precount, offsetof(struct thread_info, preempt_count));
BLANK();
- DEFINE(__PT_ARGS, offsetof(struct pt_regs, args),);
- DEFINE(__PT_PSW, offsetof(struct pt_regs, psw),);
- DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs),);
- DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2),);
- DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc),);
- DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap),);
- DEFINE(__PT_SIZE, sizeof(struct pt_regs),);
+ DEFINE(__PT_ARGS, offsetof(struct pt_regs, args));
+ DEFINE(__PT_PSW, offsetof(struct pt_regs, psw));
+ DEFINE(__PT_GPRS, offsetof(struct pt_regs, gprs));
+ DEFINE(__PT_ORIG_GPR2, offsetof(struct pt_regs, orig_gpr2));
+ DEFINE(__PT_ILC, offsetof(struct pt_regs, ilc));
+ DEFINE(__PT_TRAP, offsetof(struct pt_regs, trap));
+ DEFINE(__PT_SIZE, sizeof(struct pt_regs));
BLANK();
- DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain),);
- DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs),);
- DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1),);
+ DEFINE(__SF_BACKCHAIN, offsetof(struct stack_frame, back_chain));
+ DEFINE(__SF_GPRS, offsetof(struct stack_frame, gprs));
+ DEFINE(__SF_EMPTY, offsetof(struct stack_frame, empty1));
return 0;
}
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 68ec408..d0e0968 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -139,15 +139,15 @@
/* Running under z/VM ? */
if (cpuinfo->cpu_id.version == 0xff)
- machine_flags |= 1;
+ machine_flags |= MACHINE_FLAG_VM;
/* Running on a P/390 ? */
if (cpuinfo->cpu_id.machine == 0x7490)
- machine_flags |= 4;
+ machine_flags |= MACHINE_FLAG_P390;
/* Running under KVM ? */
if (cpuinfo->cpu_id.version == 0xfe)
- machine_flags |= 64;
+ machine_flags |= MACHINE_FLAG_KVM;
}
#ifdef CONFIG_64BIT
@@ -268,6 +268,118 @@
s390_base_pgm_handler_fn = early_pgm_check_handler;
}
+static noinline __init void setup_hpage(void)
+{
+#ifndef CONFIG_DEBUG_PAGEALLOC
+ unsigned int facilities;
+
+ facilities = stfl();
+ if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
+ return;
+ machine_flags |= MACHINE_FLAG_HPAGE;
+ __ctl_set_bit(0, 23);
+#endif
+}
+
+static __init void detect_mvpg(void)
+{
+#ifndef CONFIG_64BIT
+ int rc;
+
+ asm volatile(
+ " la 0,0\n"
+ " mvpg %2,%2\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (rc) : "0" (-EOPNOTSUPP), "a" (0) : "memory", "cc", "0");
+ if (!rc)
+ machine_flags |= MACHINE_FLAG_MVPG;
+#endif
+}
+
+static __init void detect_ieee(void)
+{
+#ifndef CONFIG_64BIT
+ int rc, tmp;
+
+ asm volatile(
+ " efpc %1,0\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (rc), "=d" (tmp): "0" (-EOPNOTSUPP) : "cc");
+ if (!rc)
+ machine_flags |= MACHINE_FLAG_IEEE;
+#endif
+}
+
+static __init void detect_csp(void)
+{
+#ifndef CONFIG_64BIT
+ int rc;
+
+ asm volatile(
+ " la 0,0\n"
+ " la 1,0\n"
+ " la 2,4\n"
+ " csp 0,2\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc", "0", "1", "2");
+ if (!rc)
+ machine_flags |= MACHINE_FLAG_CSP;
+#endif
+}
+
+static __init void detect_diag9c(void)
+{
+ unsigned int cpu_address;
+ int rc;
+
+ cpu_address = stap();
+ asm volatile(
+ " diag %2,0,0x9c\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (rc) : "0" (-EOPNOTSUPP), "d" (cpu_address) : "cc");
+ if (!rc)
+ machine_flags |= MACHINE_FLAG_DIAG9C;
+}
+
+static __init void detect_diag44(void)
+{
+#ifdef CONFIG_64BIT
+ int rc;
+
+ asm volatile(
+ " diag 0,0,0x44\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc");
+ if (!rc)
+ machine_flags |= MACHINE_FLAG_DIAG44;
+#endif
+}
+
+static __init void detect_machine_facilities(void)
+{
+#ifdef CONFIG_64BIT
+ unsigned int facilities;
+
+ facilities = stfl();
+ if (facilities & (1 << 28))
+ machine_flags |= MACHINE_FLAG_IDTE;
+ if (facilities & (1 << 23))
+ machine_flags |= MACHINE_FLAG_PFMF;
+ if (facilities & (1 << 4))
+ machine_flags |= MACHINE_FLAG_MVCOS;
+#endif
+}
+
/*
* Save ipl parameters, clear bss memory, initialize storage keys
* and create a kernel NSS at startup if the SAVESYS= parm is defined
@@ -285,6 +397,13 @@
create_kernel_nss();
sort_main_extable();
setup_lowcore_early();
+ detect_mvpg();
+ detect_ieee();
+ detect_csp();
+ detect_diag9c();
+ detect_diag44();
+ detect_machine_facilities();
+ setup_hpage();
sclp_read_info_early();
sclp_facilities_detect();
memsize = sclp_memory_detect();
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 6766e37..bdbb3bc 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -49,9 +49,9 @@
SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING)
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
@@ -316,7 +316,7 @@
bo BASED(sysc_mcck_pending)
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
bo BASED(sysc_reschedule)
- tm __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
+ tm __TI_flags+3(%r9),_TIF_SIGPENDING
bnz BASED(sysc_sigpending)
tm __TI_flags+3(%r9),_TIF_RESTART_SVC
bo BASED(sysc_restart)
@@ -342,7 +342,7 @@
br %r1 # TIF bit will be cleared by handler
#
-# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+# _TIF_SIGPENDING is set, call do_signal
#
sysc_sigpending:
ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
@@ -657,7 +657,7 @@
lr %r15,%r1
#
# One of the work bits is on. Find out which one.
-# Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGMASK, _TIF_NEED_RESCHED
+# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED
# and _TIF_MCCK_PENDING
#
io_work_loop:
@@ -665,7 +665,7 @@
bo BASED(io_mcck_pending)
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
bo BASED(io_reschedule)
- tm __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
+ tm __TI_flags+3(%r9),_TIF_SIGPENDING
bnz BASED(io_sigpending)
b BASED(io_restore)
io_work_done:
@@ -693,7 +693,7 @@
b BASED(io_work_loop)
#
-# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+# _TIF_SIGPENDING is set, call do_signal
#
io_sigpending:
TRACE_IRQS_ON
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index cd959c0..5a4a7bc 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -52,9 +52,9 @@
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING)
#define BASED(name) name-system_call(%r13)
@@ -308,7 +308,7 @@
jo sysc_mcck_pending
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jo sysc_reschedule
- tm __TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
+ tm __TI_flags+7(%r9),_TIF_SIGPENDING
jnz sysc_sigpending
tm __TI_flags+7(%r9),_TIF_RESTART_SVC
jo sysc_restart
@@ -332,7 +332,7 @@
jg s390_handle_mcck # TIF bit will be cleared by handler
#
-# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+# _TIF_SIGPENDING is set, call do_signal
#
sysc_sigpending:
ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
@@ -648,7 +648,7 @@
jo io_mcck_pending
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jo io_reschedule
- tm __TI_flags+7(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
+ tm __TI_flags+7(%r9),_TIF_SIGPENDING
jnz io_sigpending
j io_restore
io_work_done:
@@ -674,7 +674,7 @@
j io_work_loop
#
-# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
+# _TIF_SIGPENDING or is set, call do_signal
#
io_sigpending:
TRACE_IRQS_ON
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index dc364c1..a816e2d 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -57,61 +57,6 @@
#
l %r14,.Lstartup_init-.LPG1(%r13)
basr %r14,%r14
-
- l %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
-#
-# find out if we have an IEEE fpu
-#
- mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13)
- efpc %r0,0 # test IEEE extract fpc instruction
- oi 3(%r12),2 # set IEEE fpu flag
-.Lchkfpu:
-
-#
-# find out if we have the CSP instruction
-#
- mvc __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13)
- la %r0,0
- lr %r1,%r0
- la %r2,4
- csp %r0,%r2 # Test CSP instruction
- oi 3(%r12),8 # set CSP flag
-.Lchkcsp:
-
-#
-# find out if we have the MVPG instruction
-#
- mvc __LC_PGM_NEW_PSW(8),.Lpcmvpg-.LPG1(%r13)
- sr %r0,%r0
- la %r1,0
- la %r2,0
- mvpg %r1,%r2 # Test CSP instruction
- oi 3(%r12),16 # set MVPG flag
-.Lchkmvpg:
-
-#
-# find out if we have the IDTE instruction
-#
- mvc __LC_PGM_NEW_PSW(8),.Lpcidte-.LPG1(%r13)
- .long 0xb2b10000 # store facility list
- tm 0xc8,0x08 # check bit for clearing-by-ASCE
- bno .Lchkidte-.LPG1(%r13)
- lhi %r1,2094
- lhi %r2,0
- .long 0xb98e2001
- oi 3(%r12),0x80 # set IDTE flag
-.Lchkidte:
-
-#
-# find out if the diag 0x9c is available
-#
- mvc __LC_PGM_NEW_PSW(8),.Lpcdiag9c-.LPG1(%r13)
- stap __LC_CPUID+4 # store cpu address
- lh %r1,__LC_CPUID+4
- diag %r1,0,0x9c # test diag 0x9c
- oi 2(%r12),1 # set diag9c flag
-.Lchkdiag9c:
-
lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
# virtual and never return ...
.align 8
@@ -132,13 +77,7 @@
.long 0 # cr13: home space segment table
.long 0xc0000000 # cr14: machine check handling off
.long 0 # cr15: linkage stack operations
-.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
-.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
-.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
-.Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte
-.Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c
.Lmchunk:.long memory_chunk
-.Lmflags:.long machine_flags
.Lbss_bgn: .long __bss_start
.Lbss_end: .long _end
.Lparmaddr: .long PARMAREA
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index 79dccd2..1d06961 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -125,73 +125,11 @@
# and create a kernel NSS if the SAVESYS= parm is defined
#
brasl %r14,startup_init
- # set program check new psw mask
- mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
- larl %r12,machine_flags
-#
-# find out if we have the MVPG instruction
-#
- la %r1,0f-.LPG1(%r13) # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
- sgr %r0,%r0
- lghi %r1,0
- lghi %r2,0
- mvpg %r1,%r2 # test MVPG instruction
- oi 7(%r12),16 # set MVPG flag
-0:
-
-#
-# find out if the diag 0x44 works in 64 bit mode
-#
- la %r1,0f-.LPG1(%r13) # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
- diag 0,0,0x44 # test diag 0x44
- oi 7(%r12),32 # set diag44 flag
-0:
-
-#
-# find out if we have the IDTE instruction
-#
- la %r1,0f-.LPG1(%r13) # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
- .long 0xb2b10000 # store facility list
- tm 0xc8,0x08 # check bit for clearing-by-ASCE
- bno 0f-.LPG1(%r13)
- lhi %r1,2048
- lhi %r2,0
- .long 0xb98e2001
- oi 7(%r12),0x80 # set IDTE flag
-0:
-
-#
-# find out if the diag 0x9c is available
-#
- la %r1,0f-.LPG1(%r13) # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
- stap __LC_CPUID+4 # store cpu address
- lh %r1,__LC_CPUID+4
- diag %r1,0,0x9c # test diag 0x9c
- oi 6(%r12),1 # set diag9c flag
-0:
-
-#
-# find out if we have the MVCOS instruction
-#
- la %r1,0f-.LPG1(%r13) # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
- .short 0xc800 # mvcos 0(%r0),0(%r0),%r0
- .short 0x0000
- .short 0x0000
-0: tm 0x8f,0x13 # special-operation exception?
- bno 1f-.LPG1(%r13) # if yes, MVCOS is present
- oi 6(%r12),2 # set MVCOS flag
-1:
-
lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
# virtual and never return ...
.align 16
.Lentry:.quad 0x0000000180000000,_stext
-.Lctl: .quad 0x04b50002 # cr0: various things
+.Lctl: .quad 0x04350002 # cr0: various things
.quad 0 # cr1: primary space segment table
.quad .Lduct # cr2: dispatchable unit control table
.quad 0 # cr3: instruction authorization
diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c
index c36d812..c59a86d 100644
--- a/arch/s390/kernel/irq.c
+++ b/arch/s390/kernel/irq.c
@@ -60,8 +60,6 @@
/*
* Switch to the asynchronous interrupt stack for softirq execution.
*/
-extern void __do_softirq(void);
-
asmlinkage void do_softirq(void)
{
unsigned long flags, old, new;
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index c1aff19..7920861 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -180,24 +180,6 @@
}
}
-void show_regs(struct pt_regs *regs)
-{
- print_modules();
- printk("CPU: %d %s %s %.*s\n",
- task_thread_info(current)->cpu, print_tainted(),
- init_utsname()->release,
- (int)strcspn(init_utsname()->version, " "),
- init_utsname()->version);
- printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
- current->comm, current->pid, current,
- (void *) current->thread.ksp);
- show_registers(regs);
- /* Show stack backtrace if pt_regs is from kernel mode */
- if (!(regs->psw.mask & PSW_MASK_PSTATE))
- show_trace(NULL, (unsigned long *) regs->gprs[15]);
- show_last_breaking_event(regs);
-}
-
extern void kernel_thread_starter(void);
asm(
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 58a0642..7f42701 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -607,38 +607,8 @@
}
#endif
-#define PT32_IEEE_IP 0x13c
-
-static int
-do_ptrace(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
- int ret;
-
- if (request == PTRACE_ATTACH)
- return ptrace_attach(child);
-
- /*
- * Special cases to get/store the ieee instructions pointer.
- */
- if (child == current) {
- if (request == PTRACE_PEEKUSR && addr == PT_IEEE_IP)
- return peek_user(child, addr, data);
- if (request == PTRACE_POKEUSR && addr == PT_IEEE_IP)
- return poke_user(child, addr, data);
-#ifdef CONFIG_COMPAT
- if (request == PTRACE_PEEKUSR &&
- addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT))
- return peek_user_emu31(child, addr, data);
- if (request == PTRACE_POKEUSR &&
- addr == PT32_IEEE_IP && test_thread_flag(TIF_31BIT))
- return poke_user_emu31(child, addr, data);
-#endif
- }
-
- ret = ptrace_check_attach(child, request == PTRACE_KILL);
- if (ret < 0)
- return ret;
-
switch (request) {
case PTRACE_SYSCALL:
/* continue and stop at next (return from) syscall */
@@ -693,31 +663,6 @@
return -EIO;
}
-asmlinkage long
-sys_ptrace(long request, long pid, long addr, long data)
-{
- struct task_struct *child;
- int ret;
-
- lock_kernel();
- if (request == PTRACE_TRACEME) {
- ret = ptrace_traceme();
- goto out;
- }
-
- child = ptrace_get_task_struct(pid);
- if (IS_ERR(child)) {
- ret = PTR_ERR(child);
- goto out;
- }
-
- ret = do_ptrace(child, request, addr, data);
- put_task_struct(child);
-out:
- unlock_kernel();
- return ret;
-}
-
asmlinkage void
syscall_trace(struct pt_regs *regs, int entryexit)
{
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index a9d18aa..2bc70b6 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -73,7 +73,7 @@
unsigned int console_mode = 0;
unsigned int console_devno = -1;
unsigned int console_irq = -1;
-unsigned long machine_flags = 0;
+unsigned long machine_flags;
unsigned long elf_hwcap = 0;
char elf_platform[ELF_PLATFORM_SIZE];
@@ -683,15 +683,6 @@
#endif
}
-static __init unsigned int stfl(void)
-{
- asm volatile(
- " .insn s,0xb2b10000,0(0)\n" /* stfl */
- "0:\n"
- EX_TABLE(0b,0b));
- return S390_lowcore.stfl_fac_list;
-}
-
static int __init __stfle(unsigned long long *list, int doublewords)
{
typedef struct { unsigned long long _[doublewords]; } addrtype;
@@ -758,6 +749,9 @@
elf_hwcap |= 1UL << 6;
}
+ if (MACHINE_HAS_HPAGE)
+ elf_hwcap |= 1UL << 7;
+
switch (cpuinfo->cpu_id.machine) {
case 0x9672:
#if !defined(CONFIG_64BIT)
@@ -881,8 +875,9 @@
static int show_cpuinfo(struct seq_file *m, void *v)
{
- static const char *hwcap_str[7] = {
- "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp"
+ static const char *hwcap_str[8] = {
+ "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp",
+ "edat"
};
struct cpuinfo_S390 *cpuinfo;
unsigned long n = (unsigned long) v - 1;
@@ -897,7 +892,7 @@
num_online_cpus(), loops_per_jiffy/(500000/HZ),
(loops_per_jiffy/(5000/HZ))%100);
seq_puts(m, "features\t: ");
- for (i = 0; i < 7; i++)
+ for (i = 0; i < 8; i++)
if (hwcap_str[i] && (elf_hwcap & (1UL << i)))
seq_printf(m, "%s ", hwcap_str[i]);
seq_puts(m, "\n");
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 0dfa988..0aeb290 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -505,7 +505,7 @@
return rc;
}
-static int smp_rescan_cpus(void)
+static int __smp_rescan_cpus(void)
{
cpumask_t avail;
@@ -570,7 +570,7 @@
kfree(info);
printk(KERN_INFO "CPUs: %d configured, %d standby\n", c_cpus, s_cpus);
get_online_cpus();
- smp_rescan_cpus();
+ __smp_rescan_cpus();
put_online_cpus();
}
@@ -890,8 +890,8 @@
if (val != 0 && val != 1)
return -EINVAL;
- mutex_lock(&smp_cpu_state_mutex);
get_online_cpus();
+ mutex_lock(&smp_cpu_state_mutex);
rc = -EBUSY;
if (cpu_online(cpu))
goto out;
@@ -919,8 +919,8 @@
break;
}
out:
- put_online_cpus();
mutex_unlock(&smp_cpu_state_mutex);
+ put_online_cpus();
return rc ? rc : count;
}
static SYSDEV_ATTR(configure, 0644, cpu_configure_show, cpu_configure_store);
@@ -1088,17 +1088,17 @@
}
#ifdef CONFIG_HOTPLUG_CPU
-static ssize_t __ref rescan_store(struct sys_device *dev,
- const char *buf, size_t count)
+
+int smp_rescan_cpus(void)
{
cpumask_t newcpus;
int cpu;
int rc;
- mutex_lock(&smp_cpu_state_mutex);
get_online_cpus();
+ mutex_lock(&smp_cpu_state_mutex);
newcpus = cpu_present_map;
- rc = smp_rescan_cpus();
+ rc = __smp_rescan_cpus();
if (rc)
goto out;
cpus_andnot(newcpus, cpu_present_map, newcpus);
@@ -1109,10 +1109,19 @@
}
rc = 0;
out:
- put_online_cpus();
mutex_unlock(&smp_cpu_state_mutex);
+ put_online_cpus();
if (!cpus_empty(newcpus))
topology_schedule_update();
+ return rc;
+}
+
+static ssize_t __ref rescan_store(struct sys_device *dev, const char *buf,
+ size_t count)
+{
+ int rc;
+
+ rc = smp_rescan_cpus();
return rc ? rc : count;
}
static SYSDEV_ATTR(rescan, 0200, NULL, rescan_store);
@@ -1139,16 +1148,16 @@
if (val != 0 && val != 1)
return -EINVAL;
rc = 0;
- mutex_lock(&smp_cpu_state_mutex);
get_online_cpus();
+ mutex_lock(&smp_cpu_state_mutex);
if (cpu_management == val)
goto out;
rc = topology_set_cpu_management(val);
if (!rc)
cpu_management = val;
out:
- put_online_cpus();
mutex_unlock(&smp_cpu_state_mutex);
+ put_online_cpus();
return rc ? rc : count;
}
static SYSDEV_ATTR(dispatching, 0644, dispatching_show, dispatching_store);
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index 12b39b3..661a072 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/bootmem.h>
#include <linux/sched.h>
+#include <linux/kthread.h>
#include <linux/workqueue.h>
#include <linux/cpu.h>
#include <linux/smp.h>
@@ -66,6 +67,8 @@
static void set_topology_timer(void);
static DECLARE_WORK(topology_work, topology_work_fn);
+cpumask_t cpu_core_map[NR_CPUS];
+
cpumask_t cpu_coregroup_map(unsigned int cpu)
{
struct core_info *core = &core_info;
@@ -199,6 +202,14 @@
return rc;
}
+static void update_cpu_core_map(void)
+{
+ int cpu;
+
+ for_each_present_cpu(cpu)
+ cpu_core_map[cpu] = cpu_coregroup_map(cpu);
+}
+
void arch_update_cpu_topology(void)
{
struct tl_info *info = tl_info;
@@ -206,20 +217,33 @@
int cpu;
if (!machine_has_topology) {
+ update_cpu_core_map();
topology_update_polarization_simple();
return;
}
stsi(info, 15, 1, 2);
tl_to_cores(info);
+ update_cpu_core_map();
for_each_online_cpu(cpu) {
sysdev = get_cpu_sysdev(cpu);
kobject_uevent(&sysdev->kobj, KOBJ_CHANGE);
}
}
-static void topology_work_fn(struct work_struct *work)
+static int topology_kthread(void *data)
{
arch_reinit_sched_domains();
+ return 0;
+}
+
+static void topology_work_fn(struct work_struct *work)
+{
+ /* We can't call arch_reinit_sched_domains() from a multi-threaded
+ * workqueue context since it may deadlock in case of cpu hotplug.
+ * So we have to create a kernel thread in order to call
+ * arch_reinit_sched_domains().
+ */
+ kthread_run(topology_kthread, NULL, "topology_update");
}
void topology_schedule_update(void)
@@ -251,20 +275,23 @@
{
int rc;
+ rc = 0;
if (!machine_has_topology) {
topology_update_polarization_simple();
- return 0;
+ goto out;
}
init_timer_deferrable(&topology_timer);
if (machine_has_topology_irq) {
rc = register_external_interrupt(0x2005, topology_interrupt);
if (rc)
- return rc;
+ goto out;
ctl_set_bit(0, 8);
}
else
set_topology_timer();
- return 0;
+out:
+ update_cpu_core_map();
+ return rc;
}
__initcall(init_topology_update);
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 57b607b..4584d81 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -113,7 +113,7 @@
}
}
-void show_trace(struct task_struct *task, unsigned long *stack)
+static void show_trace(struct task_struct *task, unsigned long *stack)
{
register unsigned long __r15 asm ("15");
unsigned long sp;
@@ -161,14 +161,14 @@
show_trace(task, sp);
}
-#ifdef CONFIG_64BIT
-void show_last_breaking_event(struct pt_regs *regs)
+static void show_last_breaking_event(struct pt_regs *regs)
{
+#ifdef CONFIG_64BIT
printk("Last Breaking-Event-Address:\n");
printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN);
print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN);
-}
#endif
+}
/*
* The architecture-independent dump_stack generator
@@ -223,6 +223,24 @@
show_code(regs);
}
+void show_regs(struct pt_regs *regs)
+{
+ print_modules();
+ printk("CPU: %d %s %s %.*s\n",
+ task_thread_info(current)->cpu, print_tainted(),
+ init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+ printk("Process %s (pid: %d, task: %p, ksp: %p)\n",
+ current->comm, current->pid, current,
+ (void *) current->thread.ksp);
+ show_registers(regs);
+ /* Show stack backtrace if pt_regs is from kernel mode */
+ if (!(regs->psw.mask & PSW_MASK_PSTATE))
+ show_trace(NULL, (unsigned long *) regs->gprs[15]);
+ show_last_breaking_event(regs);
+}
+
/* This is called from fs/proc/array.c */
void task_show_regs(struct seq_file *m, struct task_struct *task)
{
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 1465946..c02286c 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -151,18 +151,9 @@
return 0;
}
-static unsigned int kvm_stfl(void)
-{
- asm volatile(
- " .insn s,0xb2b10000,0(0)\n" /* stfl */
- "0:\n"
- EX_TABLE(0b, 0b));
- return S390_lowcore.stfl_fac_list;
-}
-
static int handle_stfl(struct kvm_vcpu *vcpu)
{
- unsigned int facility_list = kvm_stfl();
+ unsigned int facility_list = stfl();
int rc;
vcpu->stat.instruction_stfl++;
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index 5208443..ab6735d 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -2,8 +2,6 @@
# Makefile for s390-specific library files..
#
-EXTRA_AFLAGS := -traditional
-
lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
obj-$(CONFIG_32BIT) += div64.o qrnnd.o
lib-$(CONFIG_64BIT) += uaccess_mvcos.o
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index 6d87723..3f15aaf 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -162,6 +162,7 @@
return size;
}
+#ifdef CONFIG_S390_SWITCH_AMODE
static size_t strnlen_user_mvcos(size_t count, const char __user *src)
{
char buf[256];
@@ -199,6 +200,7 @@
} while ((len_str == len) && (done < count));
return done;
}
+#endif /* CONFIG_S390_SWITCH_AMODE */
struct uaccess_ops uaccess_mvcos = {
.copy_from_user = copy_from_user_mvcos_check,
diff --git a/arch/s390/math-emu/Makefile b/arch/s390/math-emu/Makefile
index 73b3e72..c848903 100644
--- a/arch/s390/math-emu/Makefile
+++ b/arch/s390/math-emu/Makefile
@@ -5,4 +5,3 @@
obj-$(CONFIG_MATHEMU) := math.o
EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
-EXTRA_AFLAGS := -traditional
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index 6640193..fb988a4 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -4,4 +4,4 @@
obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o
obj-$(CONFIG_CMM) += cmm.o
-
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index ed2af0a..f231f5e 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -287,7 +287,7 @@
if (rc < 0)
goto out_free;
- rc = add_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+ rc = vmem_add_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
if (rc)
goto out_free;
@@ -351,7 +351,7 @@
release_resource(seg->res);
kfree(seg->res);
out_shared:
- remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+ vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
out_free:
kfree(seg);
out:
@@ -474,7 +474,7 @@
rc = 0;
goto out_unlock;
out_del:
- remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+ vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
list_del(&seg->list);
dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
kfree(seg);
@@ -508,7 +508,7 @@
goto out_unlock;
release_resource(seg->res);
kfree(seg->res);
- remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
+ vmem_remove_mapping(seg->start_addr, seg->end - seg->start_addr + 1);
list_del(&seg->list);
dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
kfree(seg);
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 2650f46..4d53720 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -28,6 +28,7 @@
#include <linux/hardirq.h>
#include <linux/kprobes.h>
#include <linux/uaccess.h>
+#include <linux/hugetlb.h>
#include <asm/system.h>
#include <asm/pgtable.h>
#include <asm/s390_ext.h>
@@ -367,6 +368,8 @@
}
survive:
+ if (is_vm_hugetlb_page(vma))
+ address &= HPAGE_MASK;
/*
* If for any reason at all we couldn't handle the fault,
* make sure we exit gracefully rather than endlessly redo
diff --git a/arch/s390/mm/hugetlbpage.c b/arch/s390/mm/hugetlbpage.c
new file mode 100644
index 0000000..f4b6124
--- /dev/null
+++ b/arch/s390/mm/hugetlbpage.c
@@ -0,0 +1,134 @@
+/*
+ * IBM System z Huge TLB Page Support for Kernel.
+ *
+ * Copyright 2007 IBM Corp.
+ * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ */
+
+#include <linux/mm.h>
+#include <linux/hugetlb.h>
+
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *pteptr, pte_t pteval)
+{
+ pmd_t *pmdp = (pmd_t *) pteptr;
+ pte_t shadow_pteval = pteval;
+ unsigned long mask;
+
+ if (!MACHINE_HAS_HPAGE) {
+ pteptr = (pte_t *) pte_page(pteval)[1].index;
+ mask = pte_val(pteval) &
+ (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
+ pte_val(pteval) = (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
+ if (mm->context.noexec) {
+ pteptr += PTRS_PER_PTE;
+ pte_val(shadow_pteval) =
+ (_SEGMENT_ENTRY + __pa(pteptr)) | mask;
+ }
+ }
+
+ pmd_val(*pmdp) = pte_val(pteval);
+ if (mm->context.noexec) {
+ pmdp = get_shadow_table(pmdp);
+ pmd_val(*pmdp) = pte_val(shadow_pteval);
+ }
+}
+
+int arch_prepare_hugepage(struct page *page)
+{
+ unsigned long addr = page_to_phys(page);
+ pte_t pte;
+ pte_t *ptep;
+ int i;
+
+ if (MACHINE_HAS_HPAGE)
+ return 0;
+
+ ptep = (pte_t *) pte_alloc_one(&init_mm, address);
+ if (!ptep)
+ return -ENOMEM;
+
+ pte = mk_pte(page, PAGE_RW);
+ for (i = 0; i < PTRS_PER_PTE; i++) {
+ set_pte_at(&init_mm, addr + i * PAGE_SIZE, ptep + i, pte);
+ pte_val(pte) += PAGE_SIZE;
+ }
+ page[1].index = (unsigned long) ptep;
+ return 0;
+}
+
+void arch_release_hugepage(struct page *page)
+{
+ pte_t *ptep;
+
+ if (MACHINE_HAS_HPAGE)
+ return;
+
+ ptep = (pte_t *) page[1].index;
+ if (!ptep)
+ return;
+ pte_free(&init_mm, ptep);
+ page[1].index = 0;
+}
+
+pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgdp;
+ pud_t *pudp;
+ pmd_t *pmdp = NULL;
+
+ pgdp = pgd_offset(mm, addr);
+ pudp = pud_alloc(mm, pgdp, addr);
+ if (pudp)
+ pmdp = pmd_alloc(mm, pudp, addr);
+ return (pte_t *) pmdp;
+}
+
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+{
+ pgd_t *pgdp;
+ pud_t *pudp;
+ pmd_t *pmdp = NULL;
+
+ pgdp = pgd_offset(mm, addr);
+ if (pgd_present(*pgdp)) {
+ pudp = pud_offset(pgdp, addr);
+ if (pud_present(*pudp))
+ pmdp = pmd_offset(pudp, addr);
+ }
+ return (pte_t *) pmdp;
+}
+
+int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
+{
+ return 0;
+}
+
+struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
+ int write)
+{
+ return ERR_PTR(-EINVAL);
+}
+
+int pmd_huge(pmd_t pmd)
+{
+ if (!MACHINE_HAS_HPAGE)
+ return 0;
+
+ return !!(pmd_val(pmd) & _SEGMENT_ENTRY_LARGE);
+}
+
+struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
+ pmd_t *pmdp, int write)
+{
+ struct page *page;
+
+ if (!MACHINE_HAS_HPAGE)
+ return NULL;
+
+ page = pmd_page(*pmdp);
+ if (page)
+ page += ((address & ~HPAGE_MASK) >> PAGE_SHIFT);
+ return page;
+}
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 202c952..fa31de6 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -77,28 +77,6 @@
printk("%lu pages pagetables\n", global_page_state(NR_PAGETABLE));
}
-static void __init setup_ro_region(void)
-{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- pte_t new_pte;
- unsigned long address, end;
-
- address = ((unsigned long)&_stext) & PAGE_MASK;
- end = PFN_ALIGN((unsigned long)&_eshared);
-
- for (; address < end; address += PAGE_SIZE) {
- pgd = pgd_offset_k(address);
- pud = pud_offset(pgd, address);
- pmd = pmd_offset(pud, address);
- pte = pte_offset_kernel(pmd, address);
- new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
- *pte = new_pte;
- }
-}
-
/*
* paging_init() sets up the page tables
*/
@@ -121,7 +99,6 @@
clear_table((unsigned long *) init_mm.pgd, pgd_type,
sizeof(unsigned long)*2048);
vmem_map_init();
- setup_ro_region();
/* enable virtual mapping in kernel mode */
__ctl_load(S390_lowcore.kernel_asce, 1, 1);
@@ -129,6 +106,8 @@
__ctl_load(S390_lowcore.kernel_asce, 13, 13);
__raw_local_irq_ssm(ssm_mask);
+ sparse_memory_present_with_active_regions(MAX_NUMNODES);
+ sparse_init();
memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
#ifdef CONFIG_ZONE_DMA
max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 35d90a4..beccacf 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -10,10 +10,12 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/list.h>
+#include <linux/hugetlb.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <asm/setup.h>
#include <asm/tlbflush.h>
+#include <asm/sections.h>
static DEFINE_MUTEX(vmem_mutex);
@@ -25,43 +27,6 @@
static LIST_HEAD(mem_segs);
-void __meminit memmap_init(unsigned long size, int nid, unsigned long zone,
- unsigned long start_pfn)
-{
- struct page *start, *end;
- struct page *map_start, *map_end;
- int i;
-
- start = pfn_to_page(start_pfn);
- end = start + size;
-
- for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
- unsigned long cstart, cend;
-
- cstart = PFN_DOWN(memory_chunk[i].addr);
- cend = cstart + PFN_DOWN(memory_chunk[i].size);
-
- map_start = mem_map + cstart;
- map_end = mem_map + cend;
-
- if (map_start < start)
- map_start = start;
- if (map_end > end)
- map_end = end;
-
- map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1))
- / sizeof(struct page);
- map_end += ((PFN_ALIGN((unsigned long) map_end)
- - (unsigned long) map_end)
- / sizeof(struct page));
-
- if (map_start < map_end)
- memmap_init_zone((unsigned long)(map_end - map_start),
- nid, zone, page_to_pfn(map_start),
- MEMMAP_EARLY);
- }
-}
-
static void __ref *vmem_alloc_pages(unsigned int order)
{
if (slab_is_available())
@@ -77,8 +42,7 @@
pud = vmem_alloc_pages(2);
if (!pud)
return NULL;
- pud_val(*pud) = _REGION3_ENTRY_EMPTY;
- memcpy(pud + 1, pud, (PTRS_PER_PUD - 1)*sizeof(pud_t));
+ clear_table((unsigned long *) pud, _REGION3_ENTRY_EMPTY, PAGE_SIZE * 4);
#endif
return pud;
}
@@ -91,7 +55,7 @@
pmd = vmem_alloc_pages(2);
if (!pmd)
return NULL;
- clear_table((unsigned long *) pmd, _SEGMENT_ENTRY_EMPTY, PAGE_SIZE*4);
+ clear_table((unsigned long *) pmd, _SEGMENT_ENTRY_EMPTY, PAGE_SIZE * 4);
#endif
return pmd;
}
@@ -114,7 +78,7 @@
/*
* Add a physical memory range to the 1:1 mapping.
*/
-static int vmem_add_range(unsigned long start, unsigned long size)
+static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
{
unsigned long address;
pgd_t *pg_dir;
@@ -141,7 +105,19 @@
pud_populate_kernel(&init_mm, pu_dir, pm_dir);
}
+ pte = mk_pte_phys(address, __pgprot(ro ? _PAGE_RO : 0));
pm_dir = pmd_offset(pu_dir, address);
+
+#ifdef __s390x__
+ if (MACHINE_HAS_HPAGE && !(address & ~HPAGE_MASK) &&
+ (address + HPAGE_SIZE <= start + size) &&
+ (address >= HPAGE_SIZE)) {
+ pte_val(pte) |= _SEGMENT_ENTRY_LARGE;
+ pmd_val(*pm_dir) = pte_val(pte);
+ address += HPAGE_SIZE - PAGE_SIZE;
+ continue;
+ }
+#endif
if (pmd_none(*pm_dir)) {
pt_dir = vmem_pte_alloc();
if (!pt_dir)
@@ -150,7 +126,6 @@
}
pt_dir = pte_offset_kernel(pm_dir, address);
- pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
*pt_dir = pte;
}
ret = 0;
@@ -181,6 +156,13 @@
pm_dir = pmd_offset(pu_dir, address);
if (pmd_none(*pm_dir))
continue;
+
+ if (pmd_huge(*pm_dir)) {
+ pmd_clear_kernel(pm_dir);
+ address += HPAGE_SIZE - PAGE_SIZE;
+ continue;
+ }
+
pt_dir = pte_offset_kernel(pm_dir, address);
*pt_dir = pte;
}
@@ -190,10 +172,9 @@
/*
* Add a backed mem_map array to the virtual mem_map array.
*/
-static int vmem_add_mem_map(unsigned long start, unsigned long size)
+int __meminit vmemmap_populate(struct page *start, unsigned long nr, int node)
{
unsigned long address, start_addr, end_addr;
- struct page *map_start, *map_end;
pgd_t *pg_dir;
pud_t *pu_dir;
pmd_t *pm_dir;
@@ -201,11 +182,8 @@
pte_t pte;
int ret = -ENOMEM;
- map_start = VMEM_MAP + PFN_DOWN(start);
- map_end = VMEM_MAP + PFN_DOWN(start + size);
-
- start_addr = (unsigned long) map_start & PAGE_MASK;
- end_addr = PFN_ALIGN((unsigned long) map_end);
+ start_addr = (unsigned long) start;
+ end_addr = (unsigned long) (start + nr);
for (address = start_addr; address < end_addr; address += PAGE_SIZE) {
pg_dir = pgd_offset_k(address);
@@ -249,16 +227,6 @@
return ret;
}
-static int vmem_add_mem(unsigned long start, unsigned long size)
-{
- int ret;
-
- ret = vmem_add_mem_map(start, size);
- if (ret)
- return ret;
- return vmem_add_range(start, size);
-}
-
/*
* Add memory segment to the segment list if it doesn't overlap with
* an already present segment.
@@ -296,7 +264,7 @@
vmem_remove_range(seg->start, seg->size);
}
-int remove_shared_memory(unsigned long start, unsigned long size)
+int vmem_remove_mapping(unsigned long start, unsigned long size)
{
struct memory_segment *seg;
int ret;
@@ -320,11 +288,9 @@
return ret;
}
-int add_shared_memory(unsigned long start, unsigned long size)
+int vmem_add_mapping(unsigned long start, unsigned long size)
{
struct memory_segment *seg;
- struct page *page;
- unsigned long pfn, num_pfn, end_pfn;
int ret;
mutex_lock(&vmem_mutex);
@@ -339,24 +305,9 @@
if (ret)
goto out_free;
- ret = vmem_add_mem(start, size);
+ ret = vmem_add_mem(start, size, 0);
if (ret)
goto out_remove;
-
- pfn = PFN_DOWN(start);
- num_pfn = PFN_DOWN(size);
- end_pfn = pfn + num_pfn;
-
- page = pfn_to_page(pfn);
- memset(page, 0, num_pfn * sizeof(struct page));
-
- for (; pfn < end_pfn; pfn++) {
- page = pfn_to_page(pfn);
- init_page_count(page);
- reset_page_mapcount(page);
- SetPageReserved(page);
- INIT_LIST_HEAD(&page->lru);
- }
goto out;
out_remove:
@@ -375,14 +326,34 @@
*/
void __init vmem_map_init(void)
{
+ unsigned long ro_start, ro_end;
+ unsigned long start, end;
int i;
INIT_LIST_HEAD(&init_mm.context.crst_list);
INIT_LIST_HEAD(&init_mm.context.pgtable_list);
init_mm.context.noexec = 0;
- NODE_DATA(0)->node_mem_map = VMEM_MAP;
- for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++)
- vmem_add_mem(memory_chunk[i].addr, memory_chunk[i].size);
+ ro_start = ((unsigned long)&_stext) & PAGE_MASK;
+ ro_end = PFN_ALIGN((unsigned long)&_eshared);
+ for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
+ start = memory_chunk[i].addr;
+ end = memory_chunk[i].addr + memory_chunk[i].size;
+ if (start >= ro_end || end <= ro_start)
+ vmem_add_mem(start, end - start, 0);
+ else if (start >= ro_start && end <= ro_end)
+ vmem_add_mem(start, end - start, 1);
+ else if (start >= ro_start) {
+ vmem_add_mem(start, ro_end - start, 1);
+ vmem_add_mem(ro_end, end - ro_end, 0);
+ } else if (end < ro_end) {
+ vmem_add_mem(start, ro_start - start, 0);
+ vmem_add_mem(ro_start, end - ro_start, 1);
+ } else {
+ vmem_add_mem(start, ro_start - start, 0);
+ vmem_add_mem(ro_start, ro_end - ro_start, 1);
+ vmem_add_mem(ro_end, end - ro_end, 0);
+ }
+ }
}
/*
diff --git a/arch/sh/boards/renesas/migor/setup.c b/arch/sh/boards/renesas/migor/setup.c
index 00d52a2..e7c150d 100644
--- a/arch/sh/boards/renesas/migor/setup.c
+++ b/arch/sh/boards/renesas/migor/setup.c
@@ -199,8 +199,7 @@
static struct i2c_board_info __initdata migor_i2c_devices[] = {
{
- I2C_BOARD_INFO("rtc-rs5c372", 0x32),
- .type = "rs5c372b",
+ I2C_BOARD_INFO("rs5c372b", 0x32),
},
{
I2C_BOARD_INFO("migor_ts", 0x51),
diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
index a5c5e92..ac0a965 100644
--- a/arch/sh/boards/renesas/r7780rp/setup.c
+++ b/arch/sh/boards/renesas/r7780rp/setup.c
@@ -199,8 +199,7 @@
static struct i2c_board_info __initdata highlander_i2c_devices[] = {
{
- I2C_BOARD_INFO("rtc-rs5c372", 0x32),
- .type = "r2025sd",
+ I2C_BOARD_INFO("r2025sd", 0x32),
},
};
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 49b435c..08d2e73 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -191,8 +191,8 @@
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (unlikely(!len || !start))
diff --git a/arch/sh/kernel/asm-offsets.c b/arch/sh/kernel/asm-offsets.c
index dc6725c..57cf0e0 100644
--- a/arch/sh/kernel/asm-offsets.c
+++ b/arch/sh/kernel/asm-offsets.c
@@ -11,13 +11,10 @@
#include <linux/stddef.h>
#include <linux/types.h>
#include <linux/mm.h>
+#include <linux/kbuild.h>
+
#include <asm/thread_info.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
int main(void)
{
/* offsets into the thread_info struct */
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 9bf19b0..a2a99e4 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -200,8 +200,6 @@
hardirq_ctx[cpu] = NULL;
}
-extern asmlinkage void __do_softirq(void);
-
asmlinkage void do_softirq(void)
{
unsigned long flags;
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 49590f8..d211fdb 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -68,6 +68,7 @@
default y
select HAVE_IDE
select HAVE_OPROFILE
+ select HAVE_ARCH_KGDB if !SMP
# Identify this as a Sparc32 build
config SPARC32
diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig
index 6a2c57a..2e3a149 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.25
-# Sun Apr 20 01:49:51 2008
+# Tue Apr 29 01:28:58 2008
#
CONFIG_MMU=y
CONFIG_HIGHMEM=y
@@ -217,12 +217,7 @@
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
# CONFIG_IP_DCCP is not set
-CONFIG_IP_SCTP=m
-# CONFIG_SCTP_DBG_MSG is not set
-CONFIG_SCTP_DBG_OBJCNT=y
-# CONFIG_SCTP_HMAC_NONE is not set
-# CONFIG_SCTP_HMAC_SHA1 is not set
-CONFIG_SCTP_HMAC_MD5=y
+# CONFIG_IP_SCTP is not set
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
@@ -245,9 +240,7 @@
# CONFIG_CAN is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-CONFIG_AF_RXRPC=m
-# CONFIG_AF_RXRPC_DEBUG is not set
-# CONFIG_RXKAD is not set
+# CONFIG_AF_RXRPC is not set
#
# Wireless
@@ -390,7 +383,7 @@
# CONFIG_BONDING is not set
# CONFIG_MACVLAN is not set
# CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
+# CONFIG_TUN is not set
# CONFIG_VETH is not set
# CONFIG_ARCNET is not set
# CONFIG_PHYLIB is not set
@@ -544,6 +537,7 @@
# CONFIG_SERIAL_SUNSAB is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_CONSOLE_POLL=y
# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
@@ -595,6 +589,7 @@
# Multifunction device drivers
#
# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
#
# Multimedia devices
@@ -645,10 +640,6 @@
# CONFIG_NEW_LEDS is not set
# CONFIG_INFINIBAND is not set
# CONFIG_RTC_CLASS is not set
-
-#
-# Userspace I/O
-#
# CONFIG_UIO is not set
#
@@ -680,16 +671,12 @@
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-CONFIG_XFS_FS=m
-CONFIG_XFS_QUOTA=y
-CONFIG_XFS_POSIX_ACL=y
-CONFIG_XFS_RT=y
+# CONFIG_XFS_FS is not set
# CONFIG_OCFS2_FS is not set
CONFIG_DNOTIFY=y
CONFIG_INOTIFY=y
CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
-CONFIG_QUOTACTL=y
CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m
# CONFIG_FUSE_FS is not set
@@ -725,11 +712,9 @@
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
-# CONFIG_ECRYPT_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
-CONFIG_BEFS_FS=m
-# CONFIG_BEFS_DEBUG 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
@@ -744,7 +729,6 @@
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
@@ -755,16 +739,10 @@
CONFIG_RPCSEC_GSS_KRB5=m
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
-CONFIG_CIFS=m
-# CONFIG_CIFS_STATS is not set
-# CONFIG_CIFS_WEAK_PW_HASH is not set
-# CONFIG_CIFS_XATTR is not set
-# CONFIG_CIFS_DEBUG2 is not set
-# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
-CONFIG_AFS_FS=m
-# CONFIG_AFS_DEBUG is not set
+# CONFIG_AFS_FS is not set
#
# Partition Types
@@ -821,6 +799,7 @@
# CONFIG_PRINTK_TIME is not set
# CONFIG_ENABLE_WARN_DEPRECATED is not set
CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_FS is not set
@@ -842,70 +821,105 @@
CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
# CONFIG_DEBUG_LIST is not set
# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
# CONFIG_BOOT_PRINTK_DELAY is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_BACKTRACE_SELF_TEST is not set
# CONFIG_FAULT_INJECTION is not set
# CONFIG_SAMPLES is not set
+CONFIG_KGDB=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_KGDB_SERIAL_CONSOLE=y
+CONFIG_KGDB_TESTS=y
+# CONFIG_KGDB_TESTS_ON_BOOT is not set
# CONFIG_DEBUG_STACK_USAGE is not set
#
# Security options
#
-CONFIG_KEYS=y
-# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
# CONFIG_SECURITY_FILE_CAPABILITIES is not set
CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
CONFIG_CRYPTO_ALGAPI=y
CONFIG_CRYPTO_AEAD=y
CONFIG_CRYPTO_BLKCIPHER=y
-# CONFIG_CRYPTO_SEQIV is not set
CONFIG_CRYPTO_HASH=y
CONFIG_CRYPTO_MANAGER=y
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
CONFIG_CRYPTO_HMAC=y
# CONFIG_CRYPTO_XCBC is not set
-CONFIG_CRYPTO_NULL=m
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
CONFIG_CRYPTO_MD4=y
CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
-# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
-# CONFIG_CRYPTO_GF128MUL is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=y
-CONFIG_CRYPTO_PCBC=m
-# CONFIG_CRYPTO_LRW is not set
-# CONFIG_CRYPTO_XTS is not set
-# CONFIG_CRYPTO_CTR is not set
-# CONFIG_CRYPTO_GCM is not set
-# CONFIG_CRYPTO_CCM is not set
-# CONFIG_CRYPTO_CRYPTD is not set
-CONFIG_CRYPTO_DES=y
-# CONFIG_CRYPTO_FCRYPT is not set
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_TWOFISH_COMMON=m
-CONFIG_CRYPTO_SERPENT=m
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+# CONFIG_CRYPTO_CAMELLIA is not set
CONFIG_CRYPTO_CAST5=m
CONFIG_CRYPTO_CAST6=m
-# CONFIG_CRYPTO_TEA is not set
-CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
# CONFIG_CRYPTO_KHAZAD is not set
-# CONFIG_CRYPTO_ANUBIS is not set
-# CONFIG_CRYPTO_SEED is not set
# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+# CONFIG_CRYPTO_TEA is not set
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
CONFIG_CRYPTO_DEFLATE=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_CRC32C=m
-# CONFIG_CRYPTO_CAMELLIA is not set
-# CONFIG_CRYPTO_TEST is not set
-CONFIG_CRYPTO_AUTHENC=y
# CONFIG_CRYPTO_LZO is not set
# CONFIG_CRYPTO_HW is not set
@@ -913,6 +927,7 @@
# Library routines
#
CONFIG_BITREVERSE=y
+# CONFIG_GENERIC_FIND_FIRST_BIT is not set
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
# CONFIG_CRC_ITU_T is not set
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 59700aa..6e03a2a 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -25,3 +25,4 @@
obj-$(CONFIG_SUN_PM) += apc.o pmc.o
obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
obj-$(CONFIG_SPARC_LED) += led.o
+obj-$(CONFIG_KGDB) += kgdb.o
diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c
index 6773ed7..cd3f769 100644
--- a/arch/sparc/kernel/asm-offsets.c
+++ b/arch/sparc/kernel/asm-offsets.c
@@ -12,11 +12,7 @@
#include <linux/sched.h>
// #include <linux/mm.h>
-
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
+#include <linux/kbuild.h>
int foo(void)
{
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
index 484c83d..57d1bbd 100644
--- a/arch/sparc/kernel/entry.S
+++ b/arch/sparc/kernel/entry.S
@@ -12,7 +12,6 @@
#include <asm/head.h>
#include <asm/asi.h>
#include <asm/smp.h>
-#include <asm/kgdb.h>
#include <asm/contregs.h>
#include <asm/ptrace.h>
#include <asm/asm-offsets.h>
@@ -45,91 +44,20 @@
_SV; _SV; _SV; _SV; _SV; _SV; _SV; \
_RS; _RS; _RS; _RS; _RS; _RS; _RS;
-/* First, KGDB low level things. This is a rewrite
- * of the routines found in the sparc-stub.c asm() statement
- * from the gdb distribution. This is also dual-purpose
- * as a software trap for userlevel programs.
- */
- .data
- .align 4
-
-in_trap_handler:
- .word 0
-
.text
+
+#ifdef CONFIG_KGDB
.align 4
-
-#if 0 /* kgdb is dropped from 2.5.33 */
-! This function is called when any SPARC trap (except window overflow or
-! underflow) occurs. It makes sure that the invalid register window is still
-! available before jumping into C code. It will also restore the world if you
-! return from handle_exception.
-
- .globl trap_low
-trap_low:
- rd %wim, %l3
- SAVE_ALL
-
- sethi %hi(in_trap_handler), %l4
- ld [%lo(in_trap_handler) + %l4], %l5
- inc %l5
- st %l5, [%lo(in_trap_handler) + %l4]
-
- /* Make sure kgdb sees the same state we just saved. */
- LOAD_PT_GLOBALS(sp)
- LOAD_PT_INS(sp)
- ld [%sp + STACKFRAME_SZ + PT_Y], %l4
- ld [%sp + STACKFRAME_SZ + PT_WIM], %l3
- ld [%sp + STACKFRAME_SZ + PT_PSR], %l0
- ld [%sp + STACKFRAME_SZ + PT_PC], %l1
- ld [%sp + STACKFRAME_SZ + PT_NPC], %l2
- rd %tbr, %l5 /* Never changes... */
-
- /* Make kgdb exception frame. */
- sub %sp,(16+1+6+1+72)*4,%sp ! Make room for input & locals
- ! + hidden arg + arg spill
- ! + doubleword alignment
- ! + registers[72] local var
- SAVE_KGDB_GLOBALS(sp)
- SAVE_KGDB_INS(sp)
- SAVE_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2)
-
- /* We are increasing PIL, so two writes. */
- or %l0, PSR_PIL, %l0
- wr %l0, 0, %psr
- WRITE_PAUSE
- wr %l0, PSR_ET, %psr
- WRITE_PAUSE
-
- call handle_exception
- add %sp, STACKFRAME_SZ, %o0 ! Pass address of registers
-
- /* Load new kgdb register set. */
- LOAD_KGDB_GLOBALS(sp)
- LOAD_KGDB_INS(sp)
- LOAD_KGDB_SREGS(sp, l4, l0, l3, l5, l1, l2)
- wr %l4, 0x0, %y
-
- sethi %hi(in_trap_handler), %l4
- ld [%lo(in_trap_handler) + %l4], %l5
- dec %l5
- st %l5, [%lo(in_trap_handler) + %l4]
-
- add %sp,(16+1+6+1+72)*4,%sp ! Undo the kgdb trap frame.
-
- /* Now take what kgdb did and place it into the pt_regs
- * frame which SparcLinux RESTORE_ALL understands.,
- */
- STORE_PT_INS(sp)
- STORE_PT_GLOBALS(sp)
- STORE_PT_YREG(sp, g2)
- STORE_PT_PRIV(sp, l0, l1, l2)
-
- RESTORE_ALL
+ .globl arch_kgdb_breakpoint
+ .type arch_kgdb_breakpoint,#function
+arch_kgdb_breakpoint:
+ ta 0x7d
+ retl
+ nop
+ .size arch_kgdb_breakpoint,.-arch_kgdb_breakpoint
#endif
#if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_BLK_DEV_FD_MODULE)
- .text
.align 4
.globl floppy_hardint
floppy_hardint:
@@ -1596,6 +1524,23 @@
RESTORE_ALL
+#ifdef CONFIG_KGDB
+ .align 4
+ .globl kgdb_trap_low
+ .type kgdb_trap_low,#function
+kgdb_trap_low:
+ rd %wim,%l3
+ SAVE_ALL
+ wr %l0, PSR_ET, %psr
+ WRITE_PAUSE
+
+ call kgdb_trap
+ add %sp, STACKFRAME_SZ, %o0
+
+ RESTORE_ALL
+ .size kgdb_trap_low,.-kgdb_trap_low
+#endif
+
.align 4
.globl __handle_exception, flush_patch_exception
__handle_exception:
@@ -1698,4 +1643,22 @@
#endif /* CONFIG_PCI */
+ .globl flushw_all
+flushw_all:
+ save %sp, -0x40, %sp
+ save %sp, -0x40, %sp
+ save %sp, -0x40, %sp
+ save %sp, -0x40, %sp
+ save %sp, -0x40, %sp
+ save %sp, -0x40, %sp
+ save %sp, -0x40, %sp
+ restore
+ restore
+ restore
+ restore
+ restore
+ restore
+ ret
+ restore
+
/* End of entry.S */
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S
index b7f1e81..8bec05f 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head.S
@@ -191,7 +191,8 @@
t_baded:BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
t_badf2:BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
t_badf7:BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
-t_badfc:BAD_TRAP(0xfc) BAD_TRAP(0xfd)
+t_badfc:BAD_TRAP(0xfc)
+t_kgdb: KGDB_TRAP(0xfd)
dbtrap: BAD_TRAP(0xfe) /* Debugger/PROM breakpoint #1 */
dbtrap2:BAD_TRAP(0xff) /* Debugger/PROM breakpoint #2 */
@@ -267,7 +268,7 @@
BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
- BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
+ BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
trapbase_cpu2:
BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
@@ -335,7 +336,7 @@
BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
- BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
+ BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
trapbase_cpu3:
BAD_TRAP(0x0) SRMMU_TFAULT TRAP_ENTRY(0x2, bad_instruction)
@@ -403,7 +404,7 @@
BAD_TRAP(0xed) BAD_TRAP(0xee) BAD_TRAP(0xef) BAD_TRAP(0xf0) BAD_TRAP(0xf1)
BAD_TRAP(0xf2) BAD_TRAP(0xf3) BAD_TRAP(0xf4) BAD_TRAP(0xf5) BAD_TRAP(0xf6)
BAD_TRAP(0xf7) BAD_TRAP(0xf8) BAD_TRAP(0xf9) BAD_TRAP(0xfa) BAD_TRAP(0xfb)
- BAD_TRAP(0xfc) BAD_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
+ BAD_TRAP(0xfc) KGDB_TRAP(0xfd) BAD_TRAP(0xfe) BAD_TRAP(0xff)
#endif
.align PAGE_SIZE
diff --git a/arch/sparc/kernel/kgdb.c b/arch/sparc/kernel/kgdb.c
new file mode 100644
index 0000000..757805c
--- /dev/null
+++ b/arch/sparc/kernel/kgdb.c
@@ -0,0 +1,164 @@
+/* kgdb.c: KGDB support for 32-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kgdb.h>
+#include <linux/kdebug.h>
+
+#include <asm/kdebug.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+
+extern unsigned long trapbase;
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ struct reg_window *win;
+ int i;
+
+ gdb_regs[GDB_G0] = 0;
+ for (i = 0; i < 15; i++)
+ gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
+
+ win = (struct reg_window *) regs->u_regs[UREG_FP];
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_L0 + i] = win->locals[i];
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_I0 + i] = win->ins[i];
+
+ for (i = GDB_F0; i <= GDB_F31; i++)
+ gdb_regs[i] = 0;
+
+ gdb_regs[GDB_Y] = regs->y;
+ gdb_regs[GDB_PSR] = regs->psr;
+ gdb_regs[GDB_WIM] = 0;
+ gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
+ gdb_regs[GDB_PC] = regs->pc;
+ gdb_regs[GDB_NPC] = regs->npc;
+ gdb_regs[GDB_FSR] = 0;
+ gdb_regs[GDB_CSR] = 0;
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+ struct thread_info *t = task_thread_info(p);
+ struct reg_window *win;
+ int i;
+
+ for (i = GDB_G0; i < GDB_G6; i++)
+ gdb_regs[i] = 0;
+ gdb_regs[GDB_G6] = (unsigned long) t;
+ gdb_regs[GDB_G7] = 0;
+ for (i = GDB_O0; i < GDB_SP; i++)
+ gdb_regs[i] = 0;
+ gdb_regs[GDB_SP] = t->ksp;
+ gdb_regs[GDB_O7] = 0;
+
+ win = (struct reg_window *) t->ksp;
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_L0 + i] = win->locals[i];
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_I0 + i] = win->ins[i];
+
+ for (i = GDB_F0; i <= GDB_F31; i++)
+ gdb_regs[i] = 0;
+
+ gdb_regs[GDB_Y] = 0;
+
+ gdb_regs[GDB_PSR] = t->kpsr;
+ gdb_regs[GDB_WIM] = t->kwim;
+ gdb_regs[GDB_TBR] = (unsigned long) &trapbase;
+ gdb_regs[GDB_PC] = t->kpc;
+ gdb_regs[GDB_NPC] = t->kpc + 4;
+ gdb_regs[GDB_FSR] = 0;
+ gdb_regs[GDB_CSR] = 0;
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ struct reg_window *win;
+ int i;
+
+ for (i = 0; i < 15; i++)
+ regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
+
+ /* If the PSR register is changing, we have to preserve
+ * the CWP field, otherwise window save/restore explodes.
+ */
+ if (regs->psr != gdb_regs[GDB_PSR]) {
+ unsigned long cwp = regs->psr & PSR_CWP;
+
+ regs->psr = (gdb_regs[GDB_PSR] & ~PSR_CWP) | cwp;
+ }
+
+ regs->pc = gdb_regs[GDB_PC];
+ regs->npc = gdb_regs[GDB_NPC];
+ regs->y = gdb_regs[GDB_Y];
+
+ win = (struct reg_window *) regs->u_regs[UREG_FP];
+ for (i = 0; i < 8; i++)
+ win->locals[i] = gdb_regs[GDB_L0 + i];
+ for (i = 0; i < 8; i++)
+ win->ins[i] = gdb_regs[GDB_I0 + i];
+}
+
+int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
+ char *remcomInBuffer, char *remcomOutBuffer,
+ struct pt_regs *linux_regs)
+{
+ unsigned long addr;
+ char *ptr;
+
+ switch (remcomInBuffer[0]) {
+ case 'c':
+ /* try to read optional parameter, pc unchanged if no parm */
+ ptr = &remcomInBuffer[1];
+ if (kgdb_hex2long(&ptr, &addr)) {
+ linux_regs->pc = addr;
+ linux_regs->npc = addr + 4;
+ }
+ /* fallthru */
+
+ case 'D':
+ case 'k':
+ if (linux_regs->pc == (unsigned long) arch_kgdb_breakpoint) {
+ linux_regs->pc = linux_regs->npc;
+ linux_regs->npc += 4;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+extern void do_hw_interrupt(struct pt_regs *regs, unsigned long type);
+
+asmlinkage void kgdb_trap(struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ if (user_mode(regs)) {
+ do_hw_interrupt(regs, 0xfd);
+ return;
+ }
+
+ flushw_all();
+
+ local_irq_save(flags);
+ kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
+ local_irq_restore(flags);
+}
+
+int kgdb_arch_init(void)
+{
+ return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+ /* Breakpoint instruction: ta 0x7d */
+ .gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x7d },
+};
diff --git a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c
deleted file mode 100644
index e84f815..0000000
--- a/arch/sparc/kernel/sparc-stub.c
+++ /dev/null
@@ -1,724 +0,0 @@
-/* $Id: sparc-stub.c,v 1.28 2001/10/30 04:54:21 davem Exp $
- * sparc-stub.c: KGDB support for the Linux kernel.
- *
- * Modifications to run under Linux
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- * This file originally came from the gdb sources, and the
- * copyright notices have been retained below.
- */
-
-/****************************************************************************
-
- THIS SOFTWARE IS NOT COPYRIGHTED
-
- HP offers the following for use in the public domain. HP makes no
- warranty with regard to the software or its performance and the
- user accepts the software "AS IS" with all faults.
-
- HP DISCLAIMS ANY WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD
- TO THIS SOFTWARE INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
-
-****************************************************************************/
-
-/****************************************************************************
- * Header: remcom.c,v 1.34 91/03/09 12:29:49 glenne Exp $
- *
- * Module name: remcom.c $
- * Revision: 1.34 $
- * Date: 91/03/09 12:29:49 $
- * Contributor: Lake Stevens Instrument Division$
- *
- * Description: low level support for gdb debugger. $
- *
- * Considerations: only works on target hardware $
- *
- * Written by: Glenn Engel $
- * ModuleState: Experimental $
- *
- * NOTES: See Below $
- *
- * Modified for SPARC by Stu Grossman, Cygnus Support.
- *
- * This code has been extensively tested on the Fujitsu SPARClite demo board.
- *
- * To enable debugger support, two things need to happen. One, a
- * call to set_debug_traps() is necessary in order to allow any breakpoints
- * or error conditions to be properly intercepted and reported to gdb.
- * Two, a breakpoint needs to be generated to begin communication. This
- * is most easily accomplished by a call to breakpoint(). Breakpoint()
- * simulates a breakpoint by executing a trap #1.
- *
- *************
- *
- * The following gdb commands are supported:
- *
- * command function Return value
- *
- * g return the value of the CPU registers hex data or ENN
- * G set the value of the CPU registers OK or ENN
- *
- * mAA..AA,LLLL Read LLLL bytes at address AA..AA hex data or ENN
- * MAA..AA,LLLL: Write LLLL bytes at address AA.AA OK or ENN
- *
- * c Resume at current address SNN ( signal NN)
- * cAA..AA Continue at address AA..AA SNN
- *
- * s Step one instruction SNN
- * sAA..AA Step one instruction from AA..AA SNN
- *
- * k kill
- *
- * ? What was the last sigval ? SNN (signal NN)
- *
- * bBB..BB Set baud rate to BB..BB OK or BNN, then sets
- * baud rate
- *
- * All commands and responses are sent with a packet which includes a
- * checksum. A packet consists of
- *
- * $<packet info>#<checksum>.
- *
- * where
- * <packet info> :: <characters representing the command or response>
- * <checksum> :: < two hex digits computed as modulo 256 sum of <packetinfo>>
- *
- * When a packet is received, it is first acknowledged with either '+' or '-'.
- * '+' indicates a successful transfer. '-' indicates a failed transfer.
- *
- * Example:
- *
- * Host: Reply:
- * $m0,10#2a +$00010203040506070809101112131415#42
- *
- ****************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-#include <asm/system.h>
-#include <asm/signal.h>
-#include <asm/oplib.h>
-#include <asm/head.h>
-#include <asm/traps.h>
-#include <asm/vac-ops.h>
-#include <asm/kgdb.h>
-#include <asm/pgalloc.h>
-#include <asm/pgtable.h>
-#include <asm/cacheflush.h>
-
-/*
- *
- * external low-level support routines
- */
-
-extern void putDebugChar(char); /* write a single character */
-extern char getDebugChar(void); /* read and return a single char */
-
-/*
- * BUFMAX defines the maximum number of characters in inbound/outbound buffers
- * at least NUMREGBYTES*2 are needed for register packets
- */
-#define BUFMAX 2048
-
-static int initialized; /* !0 means we've been initialized */
-
-static const char hexchars[]="0123456789abcdef";
-
-#define NUMREGS 72
-
-/* Number of bytes of registers. */
-#define NUMREGBYTES (NUMREGS * 4)
-enum regnames {G0, G1, G2, G3, G4, G5, G6, G7,
- O0, O1, O2, O3, O4, O5, SP, O7,
- L0, L1, L2, L3, L4, L5, L6, L7,
- I0, I1, I2, I3, I4, I5, FP, I7,
-
- F0, F1, F2, F3, F4, F5, F6, F7,
- F8, F9, F10, F11, F12, F13, F14, F15,
- F16, F17, F18, F19, F20, F21, F22, F23,
- F24, F25, F26, F27, F28, F29, F30, F31,
- Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR };
-
-
-extern void trap_low(void); /* In arch/sparc/kernel/entry.S */
-
-unsigned long get_sun4cpte(unsigned long addr)
-{
- unsigned long entry;
-
- __asm__ __volatile__("\n\tlda [%1] %2, %0\n\t" :
- "=r" (entry) :
- "r" (addr), "i" (ASI_PTE));
- return entry;
-}
-
-unsigned long get_sun4csegmap(unsigned long addr)
-{
- unsigned long entry;
-
- __asm__ __volatile__("\n\tlduba [%1] %2, %0\n\t" :
- "=r" (entry) :
- "r" (addr), "i" (ASI_SEGMAP));
- return entry;
-}
-
-#if 0
-/* Have to sort this out. This cannot be done after initialization. */
-static void flush_cache_all_nop(void) {}
-#endif
-
-/* Place where we save old trap entries for restoration */
-struct tt_entry kgdb_savettable[256];
-typedef void (*trapfunc_t)(void);
-
-/* Helper routine for manipulation of kgdb_savettable */
-static inline void copy_ttentry(struct tt_entry *src, struct tt_entry *dest)
-{
- dest->inst_one = src->inst_one;
- dest->inst_two = src->inst_two;
- dest->inst_three = src->inst_three;
- dest->inst_four = src->inst_four;
-}
-
-/* Initialize the kgdb_savettable so that debugging can commence */
-static void eh_init(void)
-{
- int i;
-
- for(i=0; i < 256; i++)
- copy_ttentry(&sparc_ttable[i], &kgdb_savettable[i]);
-}
-
-/* Install an exception handler for kgdb */
-static void exceptionHandler(int tnum, trapfunc_t trap_entry)
-{
- unsigned long te_addr = (unsigned long) trap_entry;
-
- /* Make new vector */
- sparc_ttable[tnum].inst_one =
- SPARC_BRANCH((unsigned long) te_addr,
- (unsigned long) &sparc_ttable[tnum].inst_one);
- sparc_ttable[tnum].inst_two = SPARC_RD_PSR_L0;
- sparc_ttable[tnum].inst_three = SPARC_NOP;
- sparc_ttable[tnum].inst_four = SPARC_NOP;
-}
-
-/* Convert ch from a hex digit to an int */
-static int
-hex(unsigned char ch)
-{
- if (ch >= 'a' && ch <= 'f')
- return ch-'a'+10;
- if (ch >= '0' && ch <= '9')
- return ch-'0';
- if (ch >= 'A' && ch <= 'F')
- return ch-'A'+10;
- return -1;
-}
-
-/* scan for the sequence $<data>#<checksum> */
-static void
-getpacket(char *buffer)
-{
- unsigned char checksum;
- unsigned char xmitcsum;
- int i;
- int count;
- unsigned char ch;
-
- do {
- /* wait around for the start character, ignore all other characters */
- while ((ch = (getDebugChar() & 0x7f)) != '$') ;
-
- checksum = 0;
- xmitcsum = -1;
-
- count = 0;
-
- /* now, read until a # or end of buffer is found */
- while (count < BUFMAX) {
- ch = getDebugChar() & 0x7f;
- if (ch == '#')
- break;
- checksum = checksum + ch;
- buffer[count] = ch;
- count = count + 1;
- }
-
- if (count >= BUFMAX)
- continue;
-
- buffer[count] = 0;
-
- if (ch == '#') {
- xmitcsum = hex(getDebugChar() & 0x7f) << 4;
- xmitcsum |= hex(getDebugChar() & 0x7f);
- if (checksum != xmitcsum)
- putDebugChar('-'); /* failed checksum */
- else {
- putDebugChar('+'); /* successful transfer */
- /* if a sequence char is present, reply the ID */
- if (buffer[2] == ':') {
- putDebugChar(buffer[0]);
- putDebugChar(buffer[1]);
- /* remove sequence chars from buffer */
- count = strlen(buffer);
- for (i=3; i <= count; i++)
- buffer[i-3] = buffer[i];
- }
- }
- }
- } while (checksum != xmitcsum);
-}
-
-/* send the packet in buffer. */
-
-static void
-putpacket(unsigned char *buffer)
-{
- unsigned char checksum;
- int count;
- unsigned char ch, recv;
-
- /* $<packet info>#<checksum>. */
- do {
- putDebugChar('$');
- checksum = 0;
- count = 0;
-
- while ((ch = buffer[count])) {
- putDebugChar(ch);
- checksum += ch;
- count += 1;
- }
-
- putDebugChar('#');
- putDebugChar(hexchars[checksum >> 4]);
- putDebugChar(hexchars[checksum & 0xf]);
- recv = getDebugChar();
- } while ((recv & 0x7f) != '+');
-}
-
-static char remcomInBuffer[BUFMAX];
-static char remcomOutBuffer[BUFMAX];
-
-/* Convert the memory pointed to by mem into hex, placing result in buf.
- * Return a pointer to the last char put in buf (null), in case of mem fault,
- * return 0.
- */
-
-static unsigned char *
-mem2hex(char *mem, char *buf, int count)
-{
- unsigned char ch;
-
- while (count-- > 0) {
- /* This assembler code is basically: ch = *mem++;
- * except that we use the SPARC/Linux exception table
- * mechanism (see how "fixup" works in kernel_mna_trap_fault)
- * to arrange for a "return 0" upon a memory fault
- */
- __asm__(
- "\n1:\n\t"
- "ldub [%0], %1\n\t"
- "inc %0\n\t"
- ".section .fixup,#alloc,#execinstr\n\t"
- ".align 4\n"
- "2:\n\t"
- "retl\n\t"
- " mov 0, %%o0\n\t"
- ".section __ex_table, #alloc\n\t"
- ".align 4\n\t"
- ".word 1b, 2b\n\t"
- ".text\n"
- : "=r" (mem), "=r" (ch) : "0" (mem));
- *buf++ = hexchars[ch >> 4];
- *buf++ = hexchars[ch & 0xf];
- }
-
- *buf = 0;
- return buf;
-}
-
-/* convert the hex array pointed to by buf into binary to be placed in mem
- * return a pointer to the character AFTER the last byte written.
-*/
-static char *
-hex2mem(char *buf, char *mem, int count)
-{
- int i;
- unsigned char ch;
-
- for (i=0; i<count; i++) {
-
- ch = hex(*buf++) << 4;
- ch |= hex(*buf++);
- /* Assembler code is *mem++ = ch; with return 0 on fault */
- __asm__(
- "\n1:\n\t"
- "stb %1, [%0]\n\t"
- "inc %0\n\t"
- ".section .fixup,#alloc,#execinstr\n\t"
- ".align 4\n"
- "2:\n\t"
- "retl\n\t"
- " mov 0, %%o0\n\t"
- ".section __ex_table, #alloc\n\t"
- ".align 4\n\t"
- ".word 1b, 2b\n\t"
- ".text\n"
- : "=r" (mem) : "r" (ch) , "0" (mem));
- }
- return mem;
-}
-
-/* This table contains the mapping between SPARC hardware trap types, and
- signals, which are primarily what GDB understands. It also indicates
- which hardware traps we need to commandeer when initializing the stub. */
-
-static struct hard_trap_info
-{
- unsigned char tt; /* Trap type code for SPARC */
- unsigned char signo; /* Signal that we map this trap into */
-} hard_trap_info[] = {
- {SP_TRAP_SBPT, SIGTRAP}, /* ta 1 - Linux/KGDB software breakpoint */
- {0, 0} /* Must be last */
-};
-
-/* Set up exception handlers for tracing and breakpoints */
-
-void
-set_debug_traps(void)
-{
- struct hard_trap_info *ht;
- unsigned long flags;
-
- local_irq_save(flags);
-#if 0
-/* Have to sort this out. This cannot be done after initialization. */
- BTFIXUPSET_CALL(flush_cache_all, flush_cache_all_nop, BTFIXUPCALL_NOP);
-#endif
-
- /* Initialize our copy of the Linux Sparc trap table */
- eh_init();
-
- for (ht = hard_trap_info; ht->tt && ht->signo; ht++) {
- /* Only if it doesn't destroy our fault handlers */
- if((ht->tt != SP_TRAP_TFLT) &&
- (ht->tt != SP_TRAP_DFLT))
- exceptionHandler(ht->tt, trap_low);
- }
-
- /* In case GDB is started before us, ack any packets (presumably
- * "$?#xx") sitting there.
- *
- * I've found this code causes more problems than it solves,
- * so that's why it's commented out. GDB seems to work fine
- * now starting either before or after the kernel -bwb
- */
-#if 0
- while((c = getDebugChar()) != '$');
- while((c = getDebugChar()) != '#');
- c = getDebugChar(); /* eat first csum byte */
- c = getDebugChar(); /* eat second csum byte */
- putDebugChar('+'); /* ack it */
-#endif
-
- initialized = 1; /* connect! */
- local_irq_restore(flags);
-}
-
-/* Convert the SPARC hardware trap type code to a unix signal number. */
-
-static int
-computeSignal(int tt)
-{
- struct hard_trap_info *ht;
-
- for (ht = hard_trap_info; ht->tt && ht->signo; ht++)
- if (ht->tt == tt)
- return ht->signo;
-
- return SIGHUP; /* default for things we don't know about */
-}
-
-/*
- * While we find nice hex chars, build an int.
- * Return number of chars processed.
- */
-
-static int
-hexToInt(char **ptr, int *intValue)
-{
- int numChars = 0;
- int hexValue;
-
- *intValue = 0;
-
- while (**ptr) {
- hexValue = hex(**ptr);
- if (hexValue < 0)
- break;
-
- *intValue = (*intValue << 4) | hexValue;
- numChars ++;
-
- (*ptr)++;
- }
-
- return (numChars);
-}
-
-/*
- * This function does all command processing for interfacing to gdb. It
- * returns 1 if you should skip the instruction at the trap address, 0
- * otherwise.
- */
-
-extern void breakinst(void);
-
-void
-handle_exception (unsigned long *registers)
-{
- int tt; /* Trap type */
- int sigval;
- int addr;
- int length;
- char *ptr;
- unsigned long *sp;
-
- /* First, we must force all of the windows to be spilled out */
-
- asm("save %sp, -64, %sp\n\t"
- "save %sp, -64, %sp\n\t"
- "save %sp, -64, %sp\n\t"
- "save %sp, -64, %sp\n\t"
- "save %sp, -64, %sp\n\t"
- "save %sp, -64, %sp\n\t"
- "save %sp, -64, %sp\n\t"
- "save %sp, -64, %sp\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t"
- "restore\n\t");
-
- lock_kernel();
- if (registers[PC] == (unsigned long)breakinst) {
- /* Skip over breakpoint trap insn */
- registers[PC] = registers[NPC];
- registers[NPC] += 4;
- }
-
- sp = (unsigned long *)registers[SP];
-
- tt = (registers[TBR] >> 4) & 0xff;
-
- /* reply to host that an exception has occurred */
- sigval = computeSignal(tt);
- ptr = remcomOutBuffer;
-
- *ptr++ = 'T';
- *ptr++ = hexchars[sigval >> 4];
- *ptr++ = hexchars[sigval & 0xf];
-
- *ptr++ = hexchars[PC >> 4];
- *ptr++ = hexchars[PC & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)®isters[PC], ptr, 4);
- *ptr++ = ';';
-
- *ptr++ = hexchars[FP >> 4];
- *ptr++ = hexchars[FP & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *) (sp + 8 + 6), ptr, 4); /* FP */
- *ptr++ = ';';
-
- *ptr++ = hexchars[SP >> 4];
- *ptr++ = hexchars[SP & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)&sp, ptr, 4);
- *ptr++ = ';';
-
- *ptr++ = hexchars[NPC >> 4];
- *ptr++ = hexchars[NPC & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)®isters[NPC], ptr, 4);
- *ptr++ = ';';
-
- *ptr++ = hexchars[O7 >> 4];
- *ptr++ = hexchars[O7 & 0xf];
- *ptr++ = ':';
- ptr = mem2hex((char *)®isters[O7], ptr, 4);
- *ptr++ = ';';
-
- *ptr++ = 0;
-
- putpacket(remcomOutBuffer);
-
- /* XXX We may want to add some features dealing with poking the
- * XXX page tables, the real ones on the srmmu, and what is currently
- * XXX loaded in the sun4/sun4c tlb at this point in time. But this
- * XXX also required hacking to the gdb sources directly...
- */
-
- while (1) {
- remcomOutBuffer[0] = 0;
-
- getpacket(remcomInBuffer);
- switch (remcomInBuffer[0]) {
- case '?':
- remcomOutBuffer[0] = 'S';
- remcomOutBuffer[1] = hexchars[sigval >> 4];
- remcomOutBuffer[2] = hexchars[sigval & 0xf];
- remcomOutBuffer[3] = 0;
- break;
-
- case 'd':
- /* toggle debug flag */
- break;
-
- case 'g': /* return the value of the CPU registers */
- {
- ptr = remcomOutBuffer;
- /* G & O regs */
- ptr = mem2hex((char *)registers, ptr, 16 * 4);
- /* L & I regs */
- ptr = mem2hex((char *) (sp + 0), ptr, 16 * 4);
- /* Floating point */
- memset(ptr, '0', 32 * 8);
- /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
- mem2hex((char *)®isters[Y], (ptr + 32 * 4 * 2), (8 * 4));
- }
- break;
-
- case 'G': /* set the value of the CPU registers - return OK */
- {
- unsigned long *newsp, psr;
-
- psr = registers[PSR];
-
- ptr = &remcomInBuffer[1];
- /* G & O regs */
- hex2mem(ptr, (char *)registers, 16 * 4);
- /* L & I regs */
- hex2mem(ptr + 16 * 4 * 2, (char *) (sp + 0), 16 * 4);
- /* Y, PSR, WIM, TBR, PC, NPC, FPSR, CPSR */
- hex2mem(ptr + 64 * 4 * 2, (char *)®isters[Y], 8 * 4);
-
- /* See if the stack pointer has moved. If so,
- * then copy the saved locals and ins to the
- * new location. This keeps the window
- * overflow and underflow routines happy.
- */
-
- newsp = (unsigned long *)registers[SP];
- if (sp != newsp)
- sp = memcpy(newsp, sp, 16 * 4);
-
- /* Don't allow CWP to be modified. */
-
- if (psr != registers[PSR])
- registers[PSR] = (psr & 0x1f) | (registers[PSR] & ~0x1f);
-
- strcpy(remcomOutBuffer,"OK");
- }
- break;
-
- case 'm': /* mAA..AA,LLLL Read LLLL bytes at address AA..AA */
- /* Try to read %x,%x. */
-
- ptr = &remcomInBuffer[1];
-
- if (hexToInt(&ptr, &addr)
- && *ptr++ == ','
- && hexToInt(&ptr, &length)) {
- if (mem2hex((char *)addr, remcomOutBuffer, length))
- break;
-
- strcpy (remcomOutBuffer, "E03");
- } else {
- strcpy(remcomOutBuffer,"E01");
- }
- break;
-
- case 'M': /* MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK */
- /* Try to read '%x,%x:'. */
-
- ptr = &remcomInBuffer[1];
-
- if (hexToInt(&ptr, &addr)
- && *ptr++ == ','
- && hexToInt(&ptr, &length)
- && *ptr++ == ':') {
- if (hex2mem(ptr, (char *)addr, length)) {
- strcpy(remcomOutBuffer, "OK");
- } else {
- strcpy(remcomOutBuffer, "E03");
- }
- } else {
- strcpy(remcomOutBuffer, "E02");
- }
- break;
-
- case 'c': /* cAA..AA Continue at address AA..AA(optional) */
- /* try to read optional parameter, pc unchanged if no parm */
-
- ptr = &remcomInBuffer[1];
- if (hexToInt(&ptr, &addr)) {
- registers[PC] = addr;
- registers[NPC] = addr + 4;
- }
-
-/* Need to flush the instruction cache here, as we may have deposited a
- * breakpoint, and the icache probably has no way of knowing that a data ref to
- * some location may have changed something that is in the instruction cache.
- */
- flush_cache_all();
- unlock_kernel();
- return;
-
- /* kill the program */
- case 'k' : /* do nothing */
- break;
- case 'r': /* Reset */
- asm ("call 0\n\t"
- "nop\n\t");
- break;
- } /* switch */
-
- /* reply to the request */
- putpacket(remcomOutBuffer);
- } /* while(1) */
-}
-
-/* This function will generate a breakpoint exception. It is used at the
- beginning of a program to sync up with a debugger and can be used
- otherwise as a quick means to stop program execution and "break" into
- the debugger. */
-
-void
-breakpoint(void)
-{
- if (!initialized)
- return;
-
- /* Again, watch those c-prefixes for ELF kernels */
-#if defined(__svr4__) || defined(__ELF__)
- asm(".globl breakinst\n"
- "breakinst:\n\t"
- "ta 1\n");
-#else
- asm(".globl _breakinst\n"
- "_breakinst:\n\t"
- "ta 1\n");
-#endif
-}
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 0bcf98a..aa8ee06 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -282,3 +282,5 @@
/* Sun Power Management Idle Handler */
EXPORT_SYMBOL(pm_idle);
+
+EXPORT_SYMBOL(empty_zero_page);
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 0def481..dfde77f 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -335,37 +335,6 @@
ccall_info.processors_out[i] = 1;
}
-static int smp4d_stop_cpu_sender;
-
-static void smp4d_stop_cpu(void)
-{
- int me = hard_smp4d_processor_id();
-
- if (me != smp4d_stop_cpu_sender)
- while(1) barrier();
-}
-
-/* Cross calls, in order to work efficiently and atomically do all
- * the message passing work themselves, only stopcpu and reschedule
- * messages come through here.
- */
-void smp4d_message_pass(int target, int msg, unsigned long data, int wait)
-{
- int me = hard_smp4d_processor_id();
-
- SMP_PRINTK(("smp4d_message_pass %d %d %08lx %d\n", target, msg, data, wait));
- if (msg == MSG_STOP_CPU && target == MSG_ALL_BUT_SELF) {
- unsigned long flags;
- static DEFINE_SPINLOCK(stop_cpu_lock);
- spin_lock_irqsave(&stop_cpu_lock, flags);
- smp4d_stop_cpu_sender = me;
- smp4d_cross_call((smpfunc_t)smp4d_stop_cpu, 0, 0, 0, 0, 0);
- spin_unlock_irqrestore(&stop_cpu_lock, flags);
- }
- printk("Yeeee, trying to send SMP msg(%d) to %d on cpu %d\n", msg, target, me);
- panic("Bogon SMP message pass.");
-}
-
void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
{
struct pt_regs *old_regs;
@@ -439,7 +408,6 @@
BTFIXUPSET_BLACKBOX(hard_smp_processor_id, smp4d_blackbox_id);
BTFIXUPSET_BLACKBOX(load_current, smp4d_blackbox_current);
BTFIXUPSET_CALL(smp_cross_call, smp4d_cross_call, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(smp_message_pass, smp4d_message_pass, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4d_processor_id, BTFIXUPCALL_NORM);
for (i = 0; i < NR_CPUS; i++) {
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 0b94072..ffb875a 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -34,8 +34,6 @@
#include "irq.h"
-#define IRQ_RESCHEDULE 13
-#define IRQ_STOP_CPU 14
#define IRQ_CROSS_CALL 15
extern ctxd_t *srmmu_ctx_table_phys;
@@ -232,48 +230,6 @@
set_irq_udt(next);
}
-/* Cross calls, in order to work efficiently and atomically do all
- * the message passing work themselves, only stopcpu and reschedule
- * messages come through here.
- */
-void smp4m_message_pass(int target, int msg, unsigned long data, int wait)
-{
- static unsigned long smp_cpu_in_msg[NR_CPUS];
- cpumask_t mask;
- int me = smp_processor_id();
- int irq, i;
-
- if(msg == MSG_RESCHEDULE) {
- irq = IRQ_RESCHEDULE;
-
- if(smp_cpu_in_msg[me])
- return;
- } else if(msg == MSG_STOP_CPU) {
- irq = IRQ_STOP_CPU;
- } else {
- goto barf;
- }
-
- smp_cpu_in_msg[me]++;
- if(target == MSG_ALL_BUT_SELF || target == MSG_ALL) {
- mask = cpu_online_map;
- if(target == MSG_ALL_BUT_SELF)
- cpu_clear(me, mask);
- for(i = 0; i < 4; i++) {
- if (cpu_isset(i, mask))
- set_cpu_int(i, irq);
- }
- } else {
- set_cpu_int(target, irq);
- }
- smp_cpu_in_msg[me]--;
-
- return;
-barf:
- printk("Yeeee, trying to send SMP msg(%d) on cpu %d\n", msg, me);
- panic("Bogon SMP message pass.");
-}
-
static struct smp_funcall {
smpfunc_t func;
unsigned long arg1;
@@ -413,6 +369,5 @@
BTFIXUPSET_BLACKBOX(hard_smp_processor_id, smp4m_blackbox_id);
BTFIXUPSET_BLACKBOX(load_current, smp4m_blackbox_current);
BTFIXUPSET_CALL(smp_cross_call, smp4m_cross_call, BTFIXUPCALL_NORM);
- BTFIXUPSET_CALL(smp_message_pass, smp4m_message_pass, BTFIXUPCALL_NORM);
BTFIXUPSET_CALL(__hard_smp_processor_id, __smp4m_processor_id, BTFIXUPCALL_NORM);
}
diff --git a/arch/sparc/lib/iomap.c b/arch/sparc/lib/iomap.c
index 54501c1..9ef37e1 100644
--- a/arch/sparc/lib/iomap.c
+++ b/arch/sparc/lib/iomap.c
@@ -21,8 +21,8 @@
/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index edbe71e..eb36f3b 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -13,6 +13,7 @@
default y
select HAVE_IDE
select HAVE_LMB
+ select HAVE_ARCH_KGDB
config GENERIC_TIME
bool
diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile
index 2bd0340..ec4f5eb 100644
--- a/arch/sparc64/kernel/Makefile
+++ b/arch/sparc64/kernel/Makefile
@@ -29,3 +29,4 @@
obj-$(CONFIG_AUDIT) += audit.o
obj-$(CONFIG_AUDIT)$(CONFIG_COMPAT) += compat_audit.o
obj-y += $(obj-yy)
+obj-$(CONFIG_KGDB) += kgdb.o
diff --git a/arch/sparc64/kernel/cherrs.S b/arch/sparc64/kernel/cherrs.S
new file mode 100644
index 0000000..89afebd
--- /dev/null
+++ b/arch/sparc64/kernel/cherrs.S
@@ -0,0 +1,579 @@
+ /* These get patched into the trap table at boot time
+ * once we know we have a cheetah processor.
+ */
+ .globl cheetah_fecc_trap_vector
+ .type cheetah_fecc_trap_vector,#function
+cheetah_fecc_trap_vector:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ andn %g1, DCU_DC | DCU_IC, %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ sethi %hi(cheetah_fast_ecc), %g2
+ jmpl %g2 + %lo(cheetah_fast_ecc), %g0
+ mov 0, %g1
+ .size cheetah_fecc_trap_vector,.-cheetah_fecc_trap_vector
+
+ .globl cheetah_fecc_trap_vector_tl1
+ .type cheetah_fecc_trap_vector_tl1,#function
+cheetah_fecc_trap_vector_tl1:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ andn %g1, DCU_DC | DCU_IC, %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ sethi %hi(cheetah_fast_ecc), %g2
+ jmpl %g2 + %lo(cheetah_fast_ecc), %g0
+ mov 1, %g1
+ .size cheetah_fecc_trap_vector_tl1,.-cheetah_fecc_trap_vector_tl1
+
+ .globl cheetah_cee_trap_vector
+ .type cheetah_cee_trap_vector,#function
+cheetah_cee_trap_vector:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ andn %g1, DCU_IC, %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ sethi %hi(cheetah_cee), %g2
+ jmpl %g2 + %lo(cheetah_cee), %g0
+ mov 0, %g1
+ .size cheetah_cee_trap_vector,.-cheetah_cee_trap_vector
+
+ .globl cheetah_cee_trap_vector_tl1
+ .type cheetah_cee_trap_vector_tl1,#function
+cheetah_cee_trap_vector_tl1:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ andn %g1, DCU_IC, %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ sethi %hi(cheetah_cee), %g2
+ jmpl %g2 + %lo(cheetah_cee), %g0
+ mov 1, %g1
+ .size cheetah_cee_trap_vector_tl1,.-cheetah_cee_trap_vector_tl1
+
+ .globl cheetah_deferred_trap_vector
+ .type cheetah_deferred_trap_vector,#function
+cheetah_deferred_trap_vector:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1;
+ andn %g1, DCU_DC | DCU_IC, %g1;
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG;
+ membar #Sync;
+ sethi %hi(cheetah_deferred_trap), %g2
+ jmpl %g2 + %lo(cheetah_deferred_trap), %g0
+ mov 0, %g1
+ .size cheetah_deferred_trap_vector,.-cheetah_deferred_trap_vector
+
+ .globl cheetah_deferred_trap_vector_tl1
+ .type cheetah_deferred_trap_vector_tl1,#function
+cheetah_deferred_trap_vector_tl1:
+ membar #Sync;
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1;
+ andn %g1, DCU_DC | DCU_IC, %g1;
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG;
+ membar #Sync;
+ sethi %hi(cheetah_deferred_trap), %g2
+ jmpl %g2 + %lo(cheetah_deferred_trap), %g0
+ mov 1, %g1
+ .size cheetah_deferred_trap_vector_tl1,.-cheetah_deferred_trap_vector_tl1
+
+ /* Cheetah+ specific traps. These are for the new I/D cache parity
+ * error traps. The first argument to cheetah_plus_parity_handler
+ * is encoded as follows:
+ *
+ * Bit0: 0=dcache,1=icache
+ * Bit1: 0=recoverable,1=unrecoverable
+ */
+ .globl cheetah_plus_dcpe_trap_vector
+ .type cheetah_plus_dcpe_trap_vector,#function
+cheetah_plus_dcpe_trap_vector:
+ membar #Sync
+ sethi %hi(do_cheetah_plus_data_parity), %g7
+ jmpl %g7 + %lo(do_cheetah_plus_data_parity), %g0
+ nop
+ nop
+ nop
+ nop
+ nop
+ .size cheetah_plus_dcpe_trap_vector,.-cheetah_plus_dcpe_trap_vector
+
+ .type do_cheetah_plus_data_parity,#function
+do_cheetah_plus_data_parity:
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov 0x0, %o0
+ call cheetah_plus_parity_error
+ add %sp, PTREGS_OFF, %o1
+ ba,a,pt %xcc, rtrap_irq
+ .size do_cheetah_plus_data_parity,.-do_cheetah_plus_data_parity
+
+ .globl cheetah_plus_dcpe_trap_vector_tl1
+ .type cheetah_plus_dcpe_trap_vector_tl1,#function
+cheetah_plus_dcpe_trap_vector_tl1:
+ membar #Sync
+ wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+ sethi %hi(do_dcpe_tl1), %g3
+ jmpl %g3 + %lo(do_dcpe_tl1), %g0
+ nop
+ nop
+ nop
+ nop
+ .size cheetah_plus_dcpe_trap_vector_tl1,.-cheetah_plus_dcpe_trap_vector_tl1
+
+ .globl cheetah_plus_icpe_trap_vector
+ .type cheetah_plus_icpe_trap_vector,#function
+cheetah_plus_icpe_trap_vector:
+ membar #Sync
+ sethi %hi(do_cheetah_plus_insn_parity), %g7
+ jmpl %g7 + %lo(do_cheetah_plus_insn_parity), %g0
+ nop
+ nop
+ nop
+ nop
+ nop
+ .size cheetah_plus_icpe_trap_vector,.-cheetah_plus_icpe_trap_vector
+
+ .type do_cheetah_plus_insn_parity,#function
+do_cheetah_plus_insn_parity:
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov 0x1, %o0
+ call cheetah_plus_parity_error
+ add %sp, PTREGS_OFF, %o1
+ ba,a,pt %xcc, rtrap_irq
+ .size do_cheetah_plus_insn_parity,.-do_cheetah_plus_insn_parity
+
+ .globl cheetah_plus_icpe_trap_vector_tl1
+ .type cheetah_plus_icpe_trap_vector_tl1,#function
+cheetah_plus_icpe_trap_vector_tl1:
+ membar #Sync
+ wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+ sethi %hi(do_icpe_tl1), %g3
+ jmpl %g3 + %lo(do_icpe_tl1), %g0
+ nop
+ nop
+ nop
+ nop
+ .size cheetah_plus_icpe_trap_vector_tl1,.-cheetah_plus_icpe_trap_vector_tl1
+
+ /* If we take one of these traps when tl >= 1, then we
+ * jump to interrupt globals. If some trap level above us
+ * was also using interrupt globals, we cannot recover.
+ * We may use all interrupt global registers except %g6.
+ */
+ .globl do_dcpe_tl1
+ .type do_dcpe_tl1,#function
+do_dcpe_tl1:
+ rdpr %tl, %g1 ! Save original trap level
+ mov 1, %g2 ! Setup TSTATE checking loop
+ sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit
+1: wrpr %g2, %tl ! Set trap level to check
+ rdpr %tstate, %g4 ! Read TSTATE for this level
+ andcc %g4, %g3, %g0 ! Interrupt globals in use?
+ bne,a,pn %xcc, do_dcpe_tl1_fatal ! Yep, irrecoverable
+ wrpr %g1, %tl ! Restore original trap level
+ add %g2, 1, %g2 ! Next trap level
+ cmp %g2, %g1 ! Hit them all yet?
+ ble,pt %icc, 1b ! Not yet
+ nop
+ wrpr %g1, %tl ! Restore original trap level
+do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
+ sethi %hi(dcache_parity_tl1_occurred), %g2
+ lduw [%g2 + %lo(dcache_parity_tl1_occurred)], %g1
+ add %g1, 1, %g1
+ stw %g1, [%g2 + %lo(dcache_parity_tl1_occurred)]
+ /* Reset D-cache parity */
+ sethi %hi(1 << 16), %g1 ! D-cache size
+ mov (1 << 5), %g2 ! D-cache line size
+ sub %g1, %g2, %g1 ! Move down 1 cacheline
+1: srl %g1, 14, %g3 ! Compute UTAG
+ membar #Sync
+ stxa %g3, [%g1] ASI_DCACHE_UTAG
+ membar #Sync
+ sub %g2, 8, %g3 ! 64-bit data word within line
+2: membar #Sync
+ stxa %g0, [%g1 + %g3] ASI_DCACHE_DATA
+ membar #Sync
+ subcc %g3, 8, %g3 ! Next 64-bit data word
+ bge,pt %icc, 2b
+ nop
+ subcc %g1, %g2, %g1 ! Next cacheline
+ bge,pt %icc, 1b
+ nop
+ ba,pt %xcc, dcpe_icpe_tl1_common
+ nop
+
+do_dcpe_tl1_fatal:
+ sethi %hi(1f), %g7
+ ba,pt %xcc, etraptl1
+1: or %g7, %lo(1b), %g7
+ mov 0x2, %o0
+ call cheetah_plus_parity_error
+ add %sp, PTREGS_OFF, %o1
+ ba,pt %xcc, rtrap
+ nop
+ .size do_dcpe_tl1,.-do_dcpe_tl1
+
+ .globl do_icpe_tl1
+ .type do_icpe_tl1,#function
+do_icpe_tl1:
+ rdpr %tl, %g1 ! Save original trap level
+ mov 1, %g2 ! Setup TSTATE checking loop
+ sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit
+1: wrpr %g2, %tl ! Set trap level to check
+ rdpr %tstate, %g4 ! Read TSTATE for this level
+ andcc %g4, %g3, %g0 ! Interrupt globals in use?
+ bne,a,pn %xcc, do_icpe_tl1_fatal ! Yep, irrecoverable
+ wrpr %g1, %tl ! Restore original trap level
+ add %g2, 1, %g2 ! Next trap level
+ cmp %g2, %g1 ! Hit them all yet?
+ ble,pt %icc, 1b ! Not yet
+ nop
+ wrpr %g1, %tl ! Restore original trap level
+do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
+ sethi %hi(icache_parity_tl1_occurred), %g2
+ lduw [%g2 + %lo(icache_parity_tl1_occurred)], %g1
+ add %g1, 1, %g1
+ stw %g1, [%g2 + %lo(icache_parity_tl1_occurred)]
+ /* Flush I-cache */
+ sethi %hi(1 << 15), %g1 ! I-cache size
+ mov (1 << 5), %g2 ! I-cache line size
+ sub %g1, %g2, %g1
+1: or %g1, (2 << 3), %g3
+ stxa %g0, [%g3] ASI_IC_TAG
+ membar #Sync
+ subcc %g1, %g2, %g1
+ bge,pt %icc, 1b
+ nop
+ ba,pt %xcc, dcpe_icpe_tl1_common
+ nop
+
+do_icpe_tl1_fatal:
+ sethi %hi(1f), %g7
+ ba,pt %xcc, etraptl1
+1: or %g7, %lo(1b), %g7
+ mov 0x3, %o0
+ call cheetah_plus_parity_error
+ add %sp, PTREGS_OFF, %o1
+ ba,pt %xcc, rtrap
+ nop
+ .size do_icpe_tl1,.-do_icpe_tl1
+
+ .type dcpe_icpe_tl1_common,#function
+dcpe_icpe_tl1_common:
+ /* Flush D-cache, re-enable D/I caches in DCU and finally
+ * retry the trapping instruction.
+ */
+ sethi %hi(1 << 16), %g1 ! D-cache size
+ mov (1 << 5), %g2 ! D-cache line size
+ sub %g1, %g2, %g1
+1: stxa %g0, [%g1] ASI_DCACHE_TAG
+ membar #Sync
+ subcc %g1, %g2, %g1
+ bge,pt %icc, 1b
+ nop
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ or %g1, (DCU_DC | DCU_IC), %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ retry
+ .size dcpe_icpe_tl1_common,.-dcpe_icpe_tl1_common
+
+ /* 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: unused, will have current thread ptr after etrap
+ * %g7: scratch
+ */
+ .type __cheetah_log_error,#function
+__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
+ .size __cheetah_log_error,.-__cheetah_log_error
+
+ /* 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
+ * control register. The I-cache is disabled so that we may
+ * capture the corrupted cache line, and the D-cache is disabled
+ * because corrupt data may have been placed there and we don't
+ * want to reference it.
+ *
+ * %g1 is one if this trap occurred at %tl >= 1.
+ *
+ * Next, we turn off error reporting so that we don't recurse.
+ */
+ .globl cheetah_fast_ecc
+ .type cheetah_fast_ecc,#function
+cheetah_fast_ecc:
+ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2
+ andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2
+ stxa %g2, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ /* Fetch and clear AFSR/AFAR */
+ ldxa [%g0] ASI_AFSR, %g4
+ ldxa [%g0] ASI_AFAR, %g5
+ stxa %g4, [%g0] ASI_AFSR
+ membar #Sync
+
+ ba,pt %xcc, __cheetah_log_error
+ nop
+ .size cheetah_fast_ecc,.-cheetah_fast_ecc
+
+ .type c_fast_ecc,#function
+c_fast_ecc:
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov %l4, %o1
+ mov %l5, %o2
+ call cheetah_fecc_handler
+ add %sp, PTREGS_OFF, %o0
+ ba,a,pt %xcc, rtrap_irq
+ .size c_fast_ecc,.-c_fast_ecc
+
+ /* Our caller has disabled I-cache and performed membar Sync. */
+ .globl cheetah_cee
+ .type cheetah_cee,#function
+cheetah_cee:
+ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2
+ andn %g2, ESTATE_ERROR_CEEN, %g2
+ stxa %g2, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ /* Fetch and clear AFSR/AFAR */
+ ldxa [%g0] ASI_AFSR, %g4
+ ldxa [%g0] ASI_AFAR, %g5
+ stxa %g4, [%g0] ASI_AFSR
+ membar #Sync
+
+ ba,pt %xcc, __cheetah_log_error
+ nop
+ .size cheetah_cee,.-cheetah_cee
+
+ .type c_cee,#function
+c_cee:
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov %l4, %o1
+ mov %l5, %o2
+ call cheetah_cee_handler
+ add %sp, PTREGS_OFF, %o0
+ ba,a,pt %xcc, rtrap_irq
+ .size c_cee,.-c_cee
+
+ /* Our caller has disabled I-cache+D-cache and performed membar Sync. */
+ .globl cheetah_deferred_trap
+ .type cheetah_deferred_trap,#function
+cheetah_deferred_trap:
+ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2
+ andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2
+ stxa %g2, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ /* Fetch and clear AFSR/AFAR */
+ ldxa [%g0] ASI_AFSR, %g4
+ ldxa [%g0] ASI_AFAR, %g5
+ stxa %g4, [%g0] ASI_AFSR
+ membar #Sync
+
+ ba,pt %xcc, __cheetah_log_error
+ nop
+ .size cheetah_deferred_trap,.-cheetah_deferred_trap
+
+ .type c_deferred,#function
+c_deferred:
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov %l4, %o1
+ mov %l5, %o2
+ call cheetah_deferred_handler
+ add %sp, PTREGS_OFF, %o0
+ ba,a,pt %xcc, rtrap_irq
+ .size c_deferred,.-c_deferred
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
deleted file mode 100644
index fd06e93..0000000
--- a/arch/sparc64/kernel/entry.S
+++ /dev/null
@@ -1,2575 +0,0 @@
-/* $Id: entry.S,v 1.144 2002/02/09 19:49:30 davem Exp $
- * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
- *
- * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
- * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
- * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
- * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
- */
-
-#include <linux/errno.h>
-
-#include <asm/head.h>
-#include <asm/asi.h>
-#include <asm/smp.h>
-#include <asm/ptrace.h>
-#include <asm/page.h>
-#include <asm/signal.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/visasm.h>
-#include <asm/estate.h>
-#include <asm/auxio.h>
-#include <asm/sfafsr.h>
-#include <asm/pil.h>
-#include <asm/unistd.h>
-
-#define curptr g6
-
- .text
- .align 32
-
- /* This is trivial with the new code... */
- .globl do_fpdis
-do_fpdis:
- sethi %hi(TSTATE_PEF), %g4
- rdpr %tstate, %g5
- andcc %g5, %g4, %g0
- be,pt %xcc, 1f
- nop
- rd %fprs, %g5
- andcc %g5, FPRS_FEF, %g0
- be,pt %xcc, 1f
- nop
-
- /* Legal state when DCR_IFPOE is set in Cheetah %dcr. */
- sethi %hi(109f), %g7
- ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- add %g0, %g0, %g0
- ba,a,pt %xcc, rtrap
-
-1: TRAP_LOAD_THREAD_REG(%g6, %g1)
- ldub [%g6 + TI_FPSAVED], %g5
- wr %g0, FPRS_FEF, %fprs
- andcc %g5, FPRS_FEF, %g0
- be,a,pt %icc, 1f
- clr %g7
- ldx [%g6 + TI_GSR], %g7
-1: andcc %g5, FPRS_DL, %g0
- bne,pn %icc, 2f
- fzero %f0
- andcc %g5, FPRS_DU, %g0
- bne,pn %icc, 1f
- fzero %f2
- faddd %f0, %f2, %f4
- fmuld %f0, %f2, %f6
- faddd %f0, %f2, %f8
- fmuld %f0, %f2, %f10
- faddd %f0, %f2, %f12
- fmuld %f0, %f2, %f14
- faddd %f0, %f2, %f16
- fmuld %f0, %f2, %f18
- faddd %f0, %f2, %f20
- fmuld %f0, %f2, %f22
- faddd %f0, %f2, %f24
- fmuld %f0, %f2, %f26
- faddd %f0, %f2, %f28
- fmuld %f0, %f2, %f30
- faddd %f0, %f2, %f32
- fmuld %f0, %f2, %f34
- faddd %f0, %f2, %f36
- fmuld %f0, %f2, %f38
- faddd %f0, %f2, %f40
- fmuld %f0, %f2, %f42
- faddd %f0, %f2, %f44
- fmuld %f0, %f2, %f46
- faddd %f0, %f2, %f48
- fmuld %f0, %f2, %f50
- faddd %f0, %f2, %f52
- fmuld %f0, %f2, %f54
- faddd %f0, %f2, %f56
- fmuld %f0, %f2, %f58
- b,pt %xcc, fpdis_exit2
- faddd %f0, %f2, %f60
-1: mov SECONDARY_CONTEXT, %g3
- add %g6, TI_FPREGS + 0x80, %g1
- faddd %f0, %f2, %f4
- fmuld %f0, %f2, %f6
-
-661: ldxa [%g3] ASI_DMMU, %g5
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- ldxa [%g3] ASI_MMU, %g5
- .previous
-
- sethi %hi(sparc64_kern_sec_context), %g2
- ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
-
-661: stxa %g2, [%g3] ASI_DMMU
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- stxa %g2, [%g3] ASI_MMU
- .previous
-
- membar #Sync
- add %g6, TI_FPREGS + 0xc0, %g2
- faddd %f0, %f2, %f8
- fmuld %f0, %f2, %f10
- membar #Sync
- ldda [%g1] ASI_BLK_S, %f32
- ldda [%g2] ASI_BLK_S, %f48
- membar #Sync
- faddd %f0, %f2, %f12
- fmuld %f0, %f2, %f14
- faddd %f0, %f2, %f16
- fmuld %f0, %f2, %f18
- faddd %f0, %f2, %f20
- fmuld %f0, %f2, %f22
- faddd %f0, %f2, %f24
- fmuld %f0, %f2, %f26
- faddd %f0, %f2, %f28
- fmuld %f0, %f2, %f30
- b,pt %xcc, fpdis_exit
- nop
-2: andcc %g5, FPRS_DU, %g0
- bne,pt %icc, 3f
- fzero %f32
- mov SECONDARY_CONTEXT, %g3
- fzero %f34
-
-661: ldxa [%g3] ASI_DMMU, %g5
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- ldxa [%g3] ASI_MMU, %g5
- .previous
-
- add %g6, TI_FPREGS, %g1
- sethi %hi(sparc64_kern_sec_context), %g2
- ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
-
-661: stxa %g2, [%g3] ASI_DMMU
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- stxa %g2, [%g3] ASI_MMU
- .previous
-
- membar #Sync
- add %g6, TI_FPREGS + 0x40, %g2
- faddd %f32, %f34, %f36
- fmuld %f32, %f34, %f38
- membar #Sync
- ldda [%g1] ASI_BLK_S, %f0
- ldda [%g2] ASI_BLK_S, %f16
- membar #Sync
- faddd %f32, %f34, %f40
- fmuld %f32, %f34, %f42
- faddd %f32, %f34, %f44
- fmuld %f32, %f34, %f46
- faddd %f32, %f34, %f48
- fmuld %f32, %f34, %f50
- faddd %f32, %f34, %f52
- fmuld %f32, %f34, %f54
- faddd %f32, %f34, %f56
- fmuld %f32, %f34, %f58
- faddd %f32, %f34, %f60
- fmuld %f32, %f34, %f62
- ba,pt %xcc, fpdis_exit
- nop
-3: mov SECONDARY_CONTEXT, %g3
- add %g6, TI_FPREGS, %g1
-
-661: ldxa [%g3] ASI_DMMU, %g5
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- ldxa [%g3] ASI_MMU, %g5
- .previous
-
- sethi %hi(sparc64_kern_sec_context), %g2
- ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
-
-661: stxa %g2, [%g3] ASI_DMMU
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- stxa %g2, [%g3] ASI_MMU
- .previous
-
- membar #Sync
- mov 0x40, %g2
- membar #Sync
- ldda [%g1] ASI_BLK_S, %f0
- ldda [%g1 + %g2] ASI_BLK_S, %f16
- add %g1, 0x80, %g1
- ldda [%g1] ASI_BLK_S, %f32
- ldda [%g1 + %g2] ASI_BLK_S, %f48
- membar #Sync
-fpdis_exit:
-
-661: stxa %g5, [%g3] ASI_DMMU
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- stxa %g5, [%g3] ASI_MMU
- .previous
-
- membar #Sync
-fpdis_exit2:
- wr %g7, 0, %gsr
- ldx [%g6 + TI_XFSR], %fsr
- rdpr %tstate, %g3
- or %g3, %g4, %g3 ! anal...
- wrpr %g3, %tstate
- wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits
- retry
-
- .align 32
-fp_other_bounce:
- call do_fpother
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
- .globl do_fpother_check_fitos
- .align 32
-do_fpother_check_fitos:
- TRAP_LOAD_THREAD_REG(%g6, %g1)
- sethi %hi(fp_other_bounce - 4), %g7
- or %g7, %lo(fp_other_bounce - 4), %g7
-
- /* NOTE: Need to preserve %g7 until we fully commit
- * to the fitos fixup.
- */
- stx %fsr, [%g6 + TI_XFSR]
- rdpr %tstate, %g3
- andcc %g3, TSTATE_PRIV, %g0
- bne,pn %xcc, do_fptrap_after_fsr
- nop
- ldx [%g6 + TI_XFSR], %g3
- srlx %g3, 14, %g1
- and %g1, 7, %g1
- cmp %g1, 2 ! Unfinished FP-OP
- bne,pn %xcc, do_fptrap_after_fsr
- sethi %hi(1 << 23), %g1 ! Inexact
- andcc %g3, %g1, %g0
- bne,pn %xcc, do_fptrap_after_fsr
- rdpr %tpc, %g1
- lduwa [%g1] ASI_AIUP, %g3 ! This cannot ever fail
-#define FITOS_MASK 0xc1f83fe0
-#define FITOS_COMPARE 0x81a01880
- sethi %hi(FITOS_MASK), %g1
- or %g1, %lo(FITOS_MASK), %g1
- and %g3, %g1, %g1
- sethi %hi(FITOS_COMPARE), %g2
- or %g2, %lo(FITOS_COMPARE), %g2
- cmp %g1, %g2
- bne,pn %xcc, do_fptrap_after_fsr
- nop
- std %f62, [%g6 + TI_FPREGS + (62 * 4)]
- sethi %hi(fitos_table_1), %g1
- and %g3, 0x1f, %g2
- or %g1, %lo(fitos_table_1), %g1
- sllx %g2, 2, %g2
- jmpl %g1 + %g2, %g0
- ba,pt %xcc, fitos_emul_continue
-
-fitos_table_1:
- fitod %f0, %f62
- fitod %f1, %f62
- fitod %f2, %f62
- fitod %f3, %f62
- fitod %f4, %f62
- fitod %f5, %f62
- fitod %f6, %f62
- fitod %f7, %f62
- fitod %f8, %f62
- fitod %f9, %f62
- fitod %f10, %f62
- fitod %f11, %f62
- fitod %f12, %f62
- fitod %f13, %f62
- fitod %f14, %f62
- fitod %f15, %f62
- fitod %f16, %f62
- fitod %f17, %f62
- fitod %f18, %f62
- fitod %f19, %f62
- fitod %f20, %f62
- fitod %f21, %f62
- fitod %f22, %f62
- fitod %f23, %f62
- fitod %f24, %f62
- fitod %f25, %f62
- fitod %f26, %f62
- fitod %f27, %f62
- fitod %f28, %f62
- fitod %f29, %f62
- fitod %f30, %f62
- fitod %f31, %f62
-
-fitos_emul_continue:
- sethi %hi(fitos_table_2), %g1
- srl %g3, 25, %g2
- or %g1, %lo(fitos_table_2), %g1
- and %g2, 0x1f, %g2
- sllx %g2, 2, %g2
- jmpl %g1 + %g2, %g0
- ba,pt %xcc, fitos_emul_fini
-
-fitos_table_2:
- fdtos %f62, %f0
- fdtos %f62, %f1
- fdtos %f62, %f2
- fdtos %f62, %f3
- fdtos %f62, %f4
- fdtos %f62, %f5
- fdtos %f62, %f6
- fdtos %f62, %f7
- fdtos %f62, %f8
- fdtos %f62, %f9
- fdtos %f62, %f10
- fdtos %f62, %f11
- fdtos %f62, %f12
- fdtos %f62, %f13
- fdtos %f62, %f14
- fdtos %f62, %f15
- fdtos %f62, %f16
- fdtos %f62, %f17
- fdtos %f62, %f18
- fdtos %f62, %f19
- fdtos %f62, %f20
- fdtos %f62, %f21
- fdtos %f62, %f22
- fdtos %f62, %f23
- fdtos %f62, %f24
- fdtos %f62, %f25
- fdtos %f62, %f26
- fdtos %f62, %f27
- fdtos %f62, %f28
- fdtos %f62, %f29
- fdtos %f62, %f30
- fdtos %f62, %f31
-
-fitos_emul_fini:
- ldd [%g6 + TI_FPREGS + (62 * 4)], %f62
- done
-
- .globl do_fptrap
- .align 32
-do_fptrap:
- TRAP_LOAD_THREAD_REG(%g6, %g1)
- stx %fsr, [%g6 + TI_XFSR]
-do_fptrap_after_fsr:
- ldub [%g6 + TI_FPSAVED], %g3
- rd %fprs, %g1
- or %g3, %g1, %g3
- stb %g3, [%g6 + TI_FPSAVED]
- rd %gsr, %g3
- stx %g3, [%g6 + TI_GSR]
- mov SECONDARY_CONTEXT, %g3
-
-661: ldxa [%g3] ASI_DMMU, %g5
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- ldxa [%g3] ASI_MMU, %g5
- .previous
-
- sethi %hi(sparc64_kern_sec_context), %g2
- ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
-
-661: stxa %g2, [%g3] ASI_DMMU
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- stxa %g2, [%g3] ASI_MMU
- .previous
-
- membar #Sync
- add %g6, TI_FPREGS, %g2
- andcc %g1, FPRS_DL, %g0
- be,pn %icc, 4f
- mov 0x40, %g3
- stda %f0, [%g2] ASI_BLK_S
- stda %f16, [%g2 + %g3] ASI_BLK_S
- andcc %g1, FPRS_DU, %g0
- be,pn %icc, 5f
-4: add %g2, 128, %g2
- stda %f32, [%g2] ASI_BLK_S
- stda %f48, [%g2 + %g3] ASI_BLK_S
-5: mov SECONDARY_CONTEXT, %g1
- membar #Sync
-
-661: stxa %g5, [%g1] ASI_DMMU
- .section .sun4v_1insn_patch, "ax"
- .word 661b
- stxa %g5, [%g1] ASI_MMU
- .previous
-
- membar #Sync
- ba,pt %xcc, etrap
- wr %g0, 0, %fprs
-
- /* The registers for cross calls will be:
- *
- * DATA 0: [low 32-bits] Address of function to call, jmp to this
- * [high 32-bits] MMU Context Argument 0, place in %g5
- * DATA 1: Address Argument 1, place in %g1
- * DATA 2: Address Argument 2, place in %g7
- *
- * With this method we can do most of the cross-call tlb/cache
- * flushing very quickly.
- */
- .text
- .align 32
- .globl do_ivec
-do_ivec:
- mov 0x40, %g3
- ldxa [%g3 + %g0] ASI_INTR_R, %g3
- sethi %hi(KERNBASE), %g4
- cmp %g3, %g4
- bgeu,pn %xcc, do_ivec_xcall
- srlx %g3, 32, %g5
- stxa %g0, [%g0] ASI_INTR_RECEIVE
- membar #Sync
-
- sethi %hi(ivector_table_pa), %g2
- ldx [%g2 + %lo(ivector_table_pa)], %g2
- sllx %g3, 4, %g3
- add %g2, %g3, %g3
-
- TRAP_LOAD_IRQ_WORK_PA(%g6, %g1)
-
- ldx [%g6], %g5
- stxa %g5, [%g3] ASI_PHYS_USE_EC
- stx %g3, [%g6]
- wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
- retry
-do_ivec_xcall:
- mov 0x50, %g1
- ldxa [%g1 + %g0] ASI_INTR_R, %g1
- srl %g3, 0, %g3
-
- mov 0x60, %g7
- ldxa [%g7 + %g0] ASI_INTR_R, %g7
- stxa %g0, [%g0] ASI_INTR_RECEIVE
- membar #Sync
- ba,pt %xcc, 1f
- nop
-
- .align 32
-1: jmpl %g3, %g0
- nop
-
- .globl getcc, setcc
-getcc:
- ldx [%o0 + PT_V9_TSTATE], %o1
- srlx %o1, 32, %o1
- and %o1, 0xf, %o1
- retl
- stx %o1, [%o0 + PT_V9_G1]
-setcc:
- ldx [%o0 + PT_V9_TSTATE], %o1
- ldx [%o0 + PT_V9_G1], %o2
- or %g0, %ulo(TSTATE_ICC), %o3
- sllx %o3, 32, %o3
- andn %o1, %o3, %o1
- sllx %o2, 32, %o2
- and %o2, %o3, %o2
- or %o1, %o2, %o1
- retl
- stx %o1, [%o0 + PT_V9_TSTATE]
-
- .globl utrap_trap
-utrap_trap: /* %g3=handler,%g4=level */
- TRAP_LOAD_THREAD_REG(%g6, %g1)
- ldx [%g6 + TI_UTRAPS], %g1
- brnz,pt %g1, invoke_utrap
- nop
-
- ba,pt %xcc, etrap
- rd %pc, %g7
- mov %l4, %o1
- call bad_trap
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
-invoke_utrap:
- sllx %g3, 3, %g3
- ldx [%g1 + %g3], %g1
- save %sp, -128, %sp
- rdpr %tstate, %l6
- rdpr %cwp, %l7
- andn %l6, TSTATE_CWP, %l6
- wrpr %l6, %l7, %tstate
- rdpr %tpc, %l6
- rdpr %tnpc, %l7
- wrpr %g1, 0, %tnpc
- done
-
- /* We need to carefully read the error status, ACK
- * the errors, prevent recursive traps, and pass the
- * information on to C code for logging.
- *
- * We pass the AFAR in as-is, and we encode the status
- * information as described in asm-sparc64/sfafsr.h
- */
- .globl __spitfire_access_error
-__spitfire_access_error:
- /* Disable ESTATE error reporting so that we do not
- * take recursive traps and RED state the processor.
- */
- stxa %g0, [%g0] ASI_ESTATE_ERROR_EN
- membar #Sync
-
- mov UDBE_UE, %g1
- ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR
-
- /* __spitfire_cee_trap branches here with AFSR in %g4 and
- * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the
- * ESTATE Error Enable register.
- */
-__spitfire_cee_trap_continue:
- ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR
-
- rdpr %tt, %g3
- and %g3, 0x1ff, %g3 ! Paranoia
- sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3
- or %g4, %g3, %g4
- rdpr %tl, %g3
- cmp %g3, 1
- mov 1, %g3
- bleu %xcc, 1f
- sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3
-
- or %g4, %g3, %g4
-
- /* Read in the UDB error register state, clearing the
- * sticky error bits as-needed. We only clear them if
- * the UE bit is set. Likewise, __spitfire_cee_trap
- * below will only do so if the CE bit is set.
- *
- * NOTE: UltraSparc-I/II have high and low UDB error
- * registers, corresponding to the two UDB units
- * present on those chips. UltraSparc-IIi only
- * has a single UDB, called "SDB" in the manual.
- * For IIi the upper UDB register always reads
- * as zero so for our purposes things will just
- * work with the checks below.
- */
-1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3
- and %g3, 0x3ff, %g7 ! Paranoia
- sllx %g7, SFSTAT_UDBH_SHIFT, %g7
- or %g4, %g7, %g4
- andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE
- be,pn %xcc, 1f
- nop
- stxa %g3, [%g0] ASI_UDB_ERROR_W
- membar #Sync
-
-1: mov 0x18, %g3
- ldxa [%g3] ASI_UDBL_ERROR_R, %g3
- and %g3, 0x3ff, %g7 ! Paranoia
- sllx %g7, SFSTAT_UDBL_SHIFT, %g7
- or %g4, %g7, %g4
- andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE
- be,pn %xcc, 1f
- nop
- mov 0x18, %g7
- stxa %g3, [%g7] ASI_UDB_ERROR_W
- membar #Sync
-
-1: /* Ok, now that we've latched the error state,
- * clear the sticky bits in the AFSR.
- */
- stxa %g4, [%g0] ASI_AFSR
- membar #Sync
-
- rdpr %tl, %g2
- cmp %g2, 1
- rdpr %pil, %g2
- bleu,pt %xcc, 1f
- wrpr %g0, 15, %pil
-
- ba,pt %xcc, etraptl1
- rd %pc, %g7
-
- ba,pt %xcc, 2f
- nop
-
-1: ba,pt %xcc, etrap_irq
- rd %pc, %g7
-
-2:
-#ifdef CONFIG_TRACE_IRQFLAGS
- call trace_hardirqs_off
- nop
-#endif
- mov %l4, %o1
- mov %l5, %o2
- call spitfire_access_error
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
- /* This is the trap handler entry point for ECC correctable
- * errors. They are corrected, but we listen for the trap
- * so that the event can be logged.
- *
- * Disrupting errors are either:
- * 1) single-bit ECC errors during UDB reads to system
- * memory
- * 2) data parity errors during write-back events
- *
- * As far as I can make out from the manual, the CEE trap
- * is only for correctable errors during memory read
- * accesses by the front-end of the processor.
- *
- * The code below is only for trap level 1 CEE events,
- * as it is the only situation where we can safely record
- * and log. For trap level >1 we just clear the CE bit
- * in the AFSR and return.
- *
- * This is just like __spiftire_access_error above, but it
- * specifically handles correctable errors. If an
- * uncorrectable error is indicated in the AFSR we
- * will branch directly above to __spitfire_access_error
- * to handle it instead. Uncorrectable therefore takes
- * priority over correctable, and the error logging
- * C code will notice this case by inspecting the
- * trap type.
- */
- .globl __spitfire_cee_trap
-__spitfire_cee_trap:
- ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR
- mov 1, %g3
- sllx %g3, SFAFSR_UE_SHIFT, %g3
- andcc %g4, %g3, %g0 ! Check for UE
- bne,pn %xcc, __spitfire_access_error
- nop
-
- /* Ok, in this case we only have a correctable error.
- * Indicate we only wish to capture that state in register
- * %g1, and we only disable CE error reporting unlike UE
- * handling which disables all errors.
- */
- ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3
- andn %g3, ESTATE_ERR_CE, %g3
- stxa %g3, [%g0] ASI_ESTATE_ERROR_EN
- membar #Sync
-
- /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */
- ba,pt %xcc, __spitfire_cee_trap_continue
- mov UDBE_CE, %g1
-
- .globl __spitfire_data_access_exception
- .globl __spitfire_data_access_exception_tl1
-__spitfire_data_access_exception_tl1:
- rdpr %pstate, %g4
- wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
- mov TLB_SFSR, %g3
- mov DMMU_SFAR, %g5
- ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR
- ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
- stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit
- membar #Sync
- rdpr %tt, %g3
- cmp %g3, 0x80 ! first win spill/fill trap
- blu,pn %xcc, 1f
- cmp %g3, 0xff ! last win spill/fill trap
- bgu,pn %xcc, 1f
- nop
- ba,pt %xcc, winfix_dax
- rdpr %tpc, %g3
-1: sethi %hi(109f), %g7
- ba,pt %xcc, etraptl1
-109: or %g7, %lo(109b), %g7
- mov %l4, %o1
- mov %l5, %o2
- call spitfire_data_access_exception_tl1
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
-__spitfire_data_access_exception:
- rdpr %pstate, %g4
- wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
- mov TLB_SFSR, %g3
- mov DMMU_SFAR, %g5
- ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR
- ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
- stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit
- membar #Sync
- sethi %hi(109f), %g7
- ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- mov %l4, %o1
- mov %l5, %o2
- call spitfire_data_access_exception
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
- .globl __spitfire_insn_access_exception
- .globl __spitfire_insn_access_exception_tl1
-__spitfire_insn_access_exception_tl1:
- rdpr %pstate, %g4
- wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
- mov TLB_SFSR, %g3
- ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR
- rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC
- stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit
- membar #Sync
- sethi %hi(109f), %g7
- ba,pt %xcc, etraptl1
-109: or %g7, %lo(109b), %g7
- mov %l4, %o1
- mov %l5, %o2
- call spitfire_insn_access_exception_tl1
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
-__spitfire_insn_access_exception:
- rdpr %pstate, %g4
- wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
- mov TLB_SFSR, %g3
- ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR
- rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC
- stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit
- membar #Sync
- sethi %hi(109f), %g7
- ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- mov %l4, %o1
- mov %l5, %o2
- call spitfire_insn_access_exception
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
- /* These get patched into the trap table at boot time
- * once we know we have a cheetah processor.
- */
- .globl cheetah_fecc_trap_vector, cheetah_fecc_trap_vector_tl1
-cheetah_fecc_trap_vector:
- membar #Sync
- ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
- andn %g1, DCU_DC | DCU_IC, %g1
- stxa %g1, [%g0] ASI_DCU_CONTROL_REG
- membar #Sync
- sethi %hi(cheetah_fast_ecc), %g2
- jmpl %g2 + %lo(cheetah_fast_ecc), %g0
- mov 0, %g1
-cheetah_fecc_trap_vector_tl1:
- membar #Sync
- ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
- andn %g1, DCU_DC | DCU_IC, %g1
- stxa %g1, [%g0] ASI_DCU_CONTROL_REG
- membar #Sync
- sethi %hi(cheetah_fast_ecc), %g2
- jmpl %g2 + %lo(cheetah_fast_ecc), %g0
- mov 1, %g1
- .globl cheetah_cee_trap_vector, cheetah_cee_trap_vector_tl1
-cheetah_cee_trap_vector:
- membar #Sync
- ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
- andn %g1, DCU_IC, %g1
- stxa %g1, [%g0] ASI_DCU_CONTROL_REG
- membar #Sync
- sethi %hi(cheetah_cee), %g2
- jmpl %g2 + %lo(cheetah_cee), %g0
- mov 0, %g1
-cheetah_cee_trap_vector_tl1:
- membar #Sync
- ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
- andn %g1, DCU_IC, %g1
- stxa %g1, [%g0] ASI_DCU_CONTROL_REG
- membar #Sync
- sethi %hi(cheetah_cee), %g2
- jmpl %g2 + %lo(cheetah_cee), %g0
- mov 1, %g1
- .globl cheetah_deferred_trap_vector, cheetah_deferred_trap_vector_tl1
-cheetah_deferred_trap_vector:
- membar #Sync
- ldxa [%g0] ASI_DCU_CONTROL_REG, %g1;
- andn %g1, DCU_DC | DCU_IC, %g1;
- stxa %g1, [%g0] ASI_DCU_CONTROL_REG;
- membar #Sync;
- sethi %hi(cheetah_deferred_trap), %g2
- jmpl %g2 + %lo(cheetah_deferred_trap), %g0
- mov 0, %g1
-cheetah_deferred_trap_vector_tl1:
- membar #Sync;
- ldxa [%g0] ASI_DCU_CONTROL_REG, %g1;
- andn %g1, DCU_DC | DCU_IC, %g1;
- stxa %g1, [%g0] ASI_DCU_CONTROL_REG;
- membar #Sync;
- sethi %hi(cheetah_deferred_trap), %g2
- jmpl %g2 + %lo(cheetah_deferred_trap), %g0
- mov 1, %g1
-
- /* Cheetah+ specific traps. These are for the new I/D cache parity
- * error traps. The first argument to cheetah_plus_parity_handler
- * is encoded as follows:
- *
- * Bit0: 0=dcache,1=icache
- * Bit1: 0=recoverable,1=unrecoverable
- */
- .globl cheetah_plus_dcpe_trap_vector, cheetah_plus_dcpe_trap_vector_tl1
-cheetah_plus_dcpe_trap_vector:
- membar #Sync
- sethi %hi(do_cheetah_plus_data_parity), %g7
- jmpl %g7 + %lo(do_cheetah_plus_data_parity), %g0
- nop
- nop
- nop
- nop
- nop
-
-do_cheetah_plus_data_parity:
- rdpr %pil, %g2
- wrpr %g0, 15, %pil
- ba,pt %xcc, etrap_irq
- rd %pc, %g7
-#ifdef CONFIG_TRACE_IRQFLAGS
- call trace_hardirqs_off
- nop
-#endif
- mov 0x0, %o0
- call cheetah_plus_parity_error
- add %sp, PTREGS_OFF, %o1
- ba,a,pt %xcc, rtrap_irq
-
-cheetah_plus_dcpe_trap_vector_tl1:
- membar #Sync
- wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
- sethi %hi(do_dcpe_tl1), %g3
- jmpl %g3 + %lo(do_dcpe_tl1), %g0
- nop
- nop
- nop
- nop
-
- .globl cheetah_plus_icpe_trap_vector, cheetah_plus_icpe_trap_vector_tl1
-cheetah_plus_icpe_trap_vector:
- membar #Sync
- sethi %hi(do_cheetah_plus_insn_parity), %g7
- jmpl %g7 + %lo(do_cheetah_plus_insn_parity), %g0
- nop
- nop
- nop
- nop
- nop
-
-do_cheetah_plus_insn_parity:
- rdpr %pil, %g2
- wrpr %g0, 15, %pil
- ba,pt %xcc, etrap_irq
- rd %pc, %g7
-#ifdef CONFIG_TRACE_IRQFLAGS
- call trace_hardirqs_off
- nop
-#endif
- mov 0x1, %o0
- call cheetah_plus_parity_error
- add %sp, PTREGS_OFF, %o1
- ba,a,pt %xcc, rtrap_irq
-
-cheetah_plus_icpe_trap_vector_tl1:
- membar #Sync
- wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
- sethi %hi(do_icpe_tl1), %g3
- jmpl %g3 + %lo(do_icpe_tl1), %g0
- nop
- nop
- nop
- nop
-
- /* If we take one of these traps when tl >= 1, then we
- * jump to interrupt globals. If some trap level above us
- * was also using interrupt globals, we cannot recover.
- * We may use all interrupt global registers except %g6.
- */
- .globl do_dcpe_tl1, do_icpe_tl1
-do_dcpe_tl1:
- rdpr %tl, %g1 ! Save original trap level
- mov 1, %g2 ! Setup TSTATE checking loop
- sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit
-1: wrpr %g2, %tl ! Set trap level to check
- rdpr %tstate, %g4 ! Read TSTATE for this level
- andcc %g4, %g3, %g0 ! Interrupt globals in use?
- bne,a,pn %xcc, do_dcpe_tl1_fatal ! Yep, irrecoverable
- wrpr %g1, %tl ! Restore original trap level
- add %g2, 1, %g2 ! Next trap level
- cmp %g2, %g1 ! Hit them all yet?
- ble,pt %icc, 1b ! Not yet
- nop
- wrpr %g1, %tl ! Restore original trap level
-do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
- sethi %hi(dcache_parity_tl1_occurred), %g2
- lduw [%g2 + %lo(dcache_parity_tl1_occurred)], %g1
- add %g1, 1, %g1
- stw %g1, [%g2 + %lo(dcache_parity_tl1_occurred)]
- /* Reset D-cache parity */
- sethi %hi(1 << 16), %g1 ! D-cache size
- mov (1 << 5), %g2 ! D-cache line size
- sub %g1, %g2, %g1 ! Move down 1 cacheline
-1: srl %g1, 14, %g3 ! Compute UTAG
- membar #Sync
- stxa %g3, [%g1] ASI_DCACHE_UTAG
- membar #Sync
- sub %g2, 8, %g3 ! 64-bit data word within line
-2: membar #Sync
- stxa %g0, [%g1 + %g3] ASI_DCACHE_DATA
- membar #Sync
- subcc %g3, 8, %g3 ! Next 64-bit data word
- bge,pt %icc, 2b
- nop
- subcc %g1, %g2, %g1 ! Next cacheline
- bge,pt %icc, 1b
- nop
- ba,pt %xcc, dcpe_icpe_tl1_common
- nop
-
-do_dcpe_tl1_fatal:
- sethi %hi(1f), %g7
- ba,pt %xcc, etraptl1
-1: or %g7, %lo(1b), %g7
- mov 0x2, %o0
- call cheetah_plus_parity_error
- add %sp, PTREGS_OFF, %o1
- ba,pt %xcc, rtrap
- nop
-
-do_icpe_tl1:
- rdpr %tl, %g1 ! Save original trap level
- mov 1, %g2 ! Setup TSTATE checking loop
- sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit
-1: wrpr %g2, %tl ! Set trap level to check
- rdpr %tstate, %g4 ! Read TSTATE for this level
- andcc %g4, %g3, %g0 ! Interrupt globals in use?
- bne,a,pn %xcc, do_icpe_tl1_fatal ! Yep, irrecoverable
- wrpr %g1, %tl ! Restore original trap level
- add %g2, 1, %g2 ! Next trap level
- cmp %g2, %g1 ! Hit them all yet?
- ble,pt %icc, 1b ! Not yet
- nop
- wrpr %g1, %tl ! Restore original trap level
-do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
- sethi %hi(icache_parity_tl1_occurred), %g2
- lduw [%g2 + %lo(icache_parity_tl1_occurred)], %g1
- add %g1, 1, %g1
- stw %g1, [%g2 + %lo(icache_parity_tl1_occurred)]
- /* Flush I-cache */
- sethi %hi(1 << 15), %g1 ! I-cache size
- mov (1 << 5), %g2 ! I-cache line size
- sub %g1, %g2, %g1
-1: or %g1, (2 << 3), %g3
- stxa %g0, [%g3] ASI_IC_TAG
- membar #Sync
- subcc %g1, %g2, %g1
- bge,pt %icc, 1b
- nop
- ba,pt %xcc, dcpe_icpe_tl1_common
- nop
-
-do_icpe_tl1_fatal:
- sethi %hi(1f), %g7
- ba,pt %xcc, etraptl1
-1: or %g7, %lo(1b), %g7
- mov 0x3, %o0
- call cheetah_plus_parity_error
- add %sp, PTREGS_OFF, %o1
- ba,pt %xcc, rtrap
- nop
-
-dcpe_icpe_tl1_common:
- /* Flush D-cache, re-enable D/I caches in DCU and finally
- * retry the trapping instruction.
- */
- sethi %hi(1 << 16), %g1 ! D-cache size
- mov (1 << 5), %g2 ! D-cache line size
- sub %g1, %g2, %g1
-1: stxa %g0, [%g1] ASI_DCACHE_TAG
- membar #Sync
- subcc %g1, %g2, %g1
- bge,pt %icc, 1b
- nop
- ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
- or %g1, (DCU_DC | DCU_IC), %g1
- stxa %g1, [%g0] ASI_DCU_CONTROL_REG
- 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: unused, will have current thread ptr after etrap
- * %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
- * control register. The I-cache is disabled so that we may
- * capture the corrupted cache line, and the D-cache is disabled
- * because corrupt data may have been placed there and we don't
- * want to reference it.
- *
- * %g1 is one if this trap occurred at %tl >= 1.
- *
- * Next, we turn off error reporting so that we don't recurse.
- */
- .globl cheetah_fast_ecc
-cheetah_fast_ecc:
- ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2
- andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2
- stxa %g2, [%g0] ASI_ESTATE_ERROR_EN
- membar #Sync
-
- /* Fetch and clear AFSR/AFAR */
- ldxa [%g0] ASI_AFSR, %g4
- ldxa [%g0] ASI_AFAR, %g5
- stxa %g4, [%g0] ASI_AFSR
- membar #Sync
-
- ba,pt %xcc, __cheetah_log_error
- nop
-
-c_fast_ecc:
- rdpr %pil, %g2
- wrpr %g0, 15, %pil
- ba,pt %xcc, etrap_irq
- rd %pc, %g7
-#ifdef CONFIG_TRACE_IRQFLAGS
- call trace_hardirqs_off
- nop
-#endif
- mov %l4, %o1
- mov %l5, %o2
- call cheetah_fecc_handler
- add %sp, PTREGS_OFF, %o0
- ba,a,pt %xcc, rtrap_irq
-
- /* Our caller has disabled I-cache and performed membar Sync. */
- .globl cheetah_cee
-cheetah_cee:
- ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2
- andn %g2, ESTATE_ERROR_CEEN, %g2
- stxa %g2, [%g0] ASI_ESTATE_ERROR_EN
- membar #Sync
-
- /* Fetch and clear AFSR/AFAR */
- ldxa [%g0] ASI_AFSR, %g4
- ldxa [%g0] ASI_AFAR, %g5
- stxa %g4, [%g0] ASI_AFSR
- membar #Sync
-
- ba,pt %xcc, __cheetah_log_error
- nop
-
-c_cee:
- rdpr %pil, %g2
- wrpr %g0, 15, %pil
- ba,pt %xcc, etrap_irq
- rd %pc, %g7
-#ifdef CONFIG_TRACE_IRQFLAGS
- call trace_hardirqs_off
- nop
-#endif
- mov %l4, %o1
- mov %l5, %o2
- call cheetah_cee_handler
- add %sp, PTREGS_OFF, %o0
- ba,a,pt %xcc, rtrap_irq
-
- /* Our caller has disabled I-cache+D-cache and performed membar Sync. */
- .globl cheetah_deferred_trap
-cheetah_deferred_trap:
- ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2
- andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2
- stxa %g2, [%g0] ASI_ESTATE_ERROR_EN
- membar #Sync
-
- /* Fetch and clear AFSR/AFAR */
- ldxa [%g0] ASI_AFSR, %g4
- ldxa [%g0] ASI_AFAR, %g5
- stxa %g4, [%g0] ASI_AFSR
- membar #Sync
-
- ba,pt %xcc, __cheetah_log_error
- nop
-
-c_deferred:
- rdpr %pil, %g2
- wrpr %g0, 15, %pil
- ba,pt %xcc, etrap_irq
- rd %pc, %g7
-#ifdef CONFIG_TRACE_IRQFLAGS
- call trace_hardirqs_off
- nop
-#endif
- mov %l4, %o1
- mov %l5, %o2
- call cheetah_deferred_handler
- add %sp, PTREGS_OFF, %o0
- ba,a,pt %xcc, rtrap_irq
-
- .globl __do_privact
-__do_privact:
- mov TLB_SFSR, %g3
- stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit
- membar #Sync
- sethi %hi(109f), %g7
- ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- call do_privact
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
- .globl do_mna
-do_mna:
- rdpr %tl, %g3
- cmp %g3, 1
-
- /* Setup %g4/%g5 now as they are used in the
- * winfixup code.
- */
- mov TLB_SFSR, %g3
- mov DMMU_SFAR, %g4
- ldxa [%g4] ASI_DMMU, %g4
- ldxa [%g3] ASI_DMMU, %g5
- stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit
- membar #Sync
- bgu,pn %icc, winfix_mna
- rdpr %tpc, %g3
-
-1: sethi %hi(109f), %g7
- ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- mov %l4, %o1
- mov %l5, %o2
- call mem_address_unaligned
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
- .globl do_lddfmna
-do_lddfmna:
- sethi %hi(109f), %g7
- mov TLB_SFSR, %g4
- ldxa [%g4] ASI_DMMU, %g5
- stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit
- membar #Sync
- mov DMMU_SFAR, %g4
- ldxa [%g4] ASI_DMMU, %g4
- ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- mov %l4, %o1
- mov %l5, %o2
- call handle_lddfmna
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
- .globl do_stdfmna
-do_stdfmna:
- sethi %hi(109f), %g7
- mov TLB_SFSR, %g4
- ldxa [%g4] ASI_DMMU, %g5
- stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit
- membar #Sync
- mov DMMU_SFAR, %g4
- ldxa [%g4] ASI_DMMU, %g4
- ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- mov %l4, %o1
- mov %l5, %o2
- call handle_stdfmna
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
- .globl breakpoint_trap
-breakpoint_trap:
- call sparc_breakpoint
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- nop
-
- /* SunOS's execv() call only specifies the argv argument, the
- * environment settings are the same as the calling processes.
- */
- .globl sunos_execv
-sys_execve:
- sethi %hi(sparc_execve), %g1
- ba,pt %xcc, execve_merge
- or %g1, %lo(sparc_execve), %g1
-#ifdef CONFIG_COMPAT
- .globl sys_execve
-sunos_execv:
- stx %g0, [%sp + PTREGS_OFF + PT_V9_I2]
- .globl sys32_execve
-sys32_execve:
- sethi %hi(sparc32_execve), %g1
- or %g1, %lo(sparc32_execve), %g1
-#endif
-execve_merge:
- flushw
- jmpl %g1, %g0
- add %sp, PTREGS_OFF, %o0
-
- .globl sys_pipe, sys_sigpause, sys_nis_syscall
- .globl sys_rt_sigreturn
- .globl sys_ptrace
- .globl sys_sigaltstack
- .align 32
-sys_pipe: ba,pt %xcc, sparc_pipe
- add %sp, PTREGS_OFF, %o0
-sys_nis_syscall:ba,pt %xcc, c_sys_nis_syscall
- add %sp, PTREGS_OFF, %o0
-sys_memory_ordering:
- ba,pt %xcc, sparc_memory_ordering
- add %sp, PTREGS_OFF, %o1
-sys_sigaltstack:ba,pt %xcc, do_sigaltstack
- add %i6, STACK_BIAS, %o2
-#ifdef CONFIG_COMPAT
- .globl sys32_sigstack
-sys32_sigstack: ba,pt %xcc, do_sys32_sigstack
- mov %i6, %o2
- .globl sys32_sigaltstack
-sys32_sigaltstack:
- ba,pt %xcc, do_sys32_sigaltstack
- mov %i6, %o2
-#endif
- .align 32
-#ifdef CONFIG_COMPAT
- .globl sys32_sigreturn
-sys32_sigreturn:
- add %sp, PTREGS_OFF, %o0
- call do_sigreturn32
- add %o7, 1f-.-4, %o7
- nop
-#endif
-sys_rt_sigreturn:
- add %sp, PTREGS_OFF, %o0
- call do_rt_sigreturn
- add %o7, 1f-.-4, %o7
- nop
-#ifdef CONFIG_COMPAT
- .globl sys32_rt_sigreturn
-sys32_rt_sigreturn:
- add %sp, PTREGS_OFF, %o0
- call do_rt_sigreturn32
- add %o7, 1f-.-4, %o7
- nop
-#endif
- .align 32
-1: ldx [%curptr + TI_FLAGS], %l5
- andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
- be,pt %icc, rtrap
- nop
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- mov 1, %o1
-
- ba,pt %xcc, rtrap
- nop
-
- /* This is how fork() was meant to be done, 8 instruction entry.
- *
- * I questioned the following code briefly, let me clear things
- * up so you must not reason on it like I did.
- *
- * Know the fork_kpsr etc. we use in the sparc32 port? We don't
- * need it here because the only piece of window state we copy to
- * the child is the CWP register. Even if the parent sleeps,
- * we are safe because we stuck it into pt_regs of the parent
- * so it will not change.
- *
- * XXX This raises the question, whether we can do the same on
- * XXX sparc32 to get rid of fork_kpsr _and_ fork_kwim. The
- * XXX answer is yes. We stick fork_kpsr in UREG_G0 and
- * XXX fork_kwim in UREG_G1 (global registers are considered
- * XXX volatile across a system call in the sparc ABI I think
- * XXX if it isn't we can use regs->y instead, anyone who depends
- * XXX upon the Y register being preserved across a fork deserves
- * XXX to lose).
- *
- * In fact we should take advantage of that fact for other things
- * during system calls...
- */
- .globl sys_fork, sys_vfork, sys_clone, sparc_exit
- .globl ret_from_syscall
- .align 32
-sys_vfork: /* Under Linux, vfork and fork are just special cases of clone. */
- sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0
- or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
- ba,pt %xcc, sys_clone
-sys_fork: clr %o1
- mov SIGCHLD, %o0
-sys_clone: flushw
- movrz %o1, %fp, %o1
- mov 0, %o3
- ba,pt %xcc, sparc_do_fork
- add %sp, PTREGS_OFF, %o2
-ret_from_syscall:
- /* Clear current_thread_info()->new_child, and
- * check performance counter stuff too.
- */
- stb %g0, [%g6 + TI_NEW_CHILD]
- ldx [%g6 + TI_FLAGS], %l0
- call schedule_tail
- mov %g7, %o0
- andcc %l0, _TIF_PERFCTR, %g0
- be,pt %icc, 1f
- nop
- ldx [%g6 + TI_PCR], %o7
- wr %g0, %o7, %pcr
-
- /* Blackbird errata workaround. See commentary in
- * smp.c:smp_percpu_timer_interrupt() for more
- * information.
- */
- ba,pt %xcc, 99f
- nop
- .align 64
-99: wr %g0, %g0, %pic
- rd %pic, %g0
-
-1: b,pt %xcc, ret_sys_call
- ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0
-sparc_exit: rdpr %pstate, %g2
- wrpr %g2, PSTATE_IE, %pstate
- rdpr %otherwin, %g1
- rdpr %cansave, %g3
- add %g3, %g1, %g3
- wrpr %g3, 0x0, %cansave
- wrpr %g0, 0x0, %otherwin
- wrpr %g2, 0x0, %pstate
- ba,pt %xcc, sys_exit
- stb %g0, [%g6 + TI_WSAVED]
-
-linux_sparc_ni_syscall:
- sethi %hi(sys_ni_syscall), %l7
- b,pt %xcc, 4f
- or %l7, %lo(sys_ni_syscall), %l7
-
-linux_syscall_trace32:
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- clr %o1
- srl %i0, 0, %o0
- srl %i4, 0, %o4
- srl %i1, 0, %o1
- srl %i2, 0, %o2
- b,pt %xcc, 2f
- srl %i3, 0, %o3
-
-linux_syscall_trace:
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- clr %o1
- mov %i0, %o0
- mov %i1, %o1
- mov %i2, %o2
- mov %i3, %o3
- b,pt %xcc, 2f
- mov %i4, %o4
-
-
- /* Linux 32-bit system calls enter here... */
- .align 32
- .globl linux_sparc_syscall32
-linux_sparc_syscall32:
- /* Direct access to user regs, much faster. */
- cmp %g1, NR_SYSCALLS ! IEU1 Group
- bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
- srl %i0, 0, %o0 ! IEU0
- sll %g1, 2, %l4 ! IEU0 Group
- srl %i4, 0, %o4 ! IEU1
- lduw [%l7 + %l4], %l7 ! Load
- srl %i1, 0, %o1 ! IEU0 Group
- ldx [%curptr + TI_FLAGS], %l0 ! Load
-
- srl %i5, 0, %o5 ! IEU1
- srl %i2, 0, %o2 ! IEU0 Group
- andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
- bne,pn %icc, linux_syscall_trace32 ! CTI
- mov %i0, %l5 ! IEU1
- call %l7 ! CTI Group brk forced
- srl %i3, 0, %o3 ! IEU0
- ba,a,pt %xcc, 3f
-
- /* Linux native system calls enter here... */
- .align 32
- .globl linux_sparc_syscall
-linux_sparc_syscall:
- /* Direct access to user regs, much faster. */
- cmp %g1, NR_SYSCALLS ! IEU1 Group
- bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
- mov %i0, %o0 ! IEU0
- sll %g1, 2, %l4 ! IEU0 Group
- mov %i1, %o1 ! IEU1
- lduw [%l7 + %l4], %l7 ! Load
-4: mov %i2, %o2 ! IEU0 Group
- ldx [%curptr + TI_FLAGS], %l0 ! Load
-
- mov %i3, %o3 ! IEU1
- mov %i4, %o4 ! IEU0 Group
- andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
- bne,pn %icc, linux_syscall_trace ! CTI Group
- mov %i0, %l5 ! IEU0
-2: call %l7 ! CTI Group brk forced
- mov %i5, %o5 ! IEU0
- nop
-
-3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
-ret_sys_call:
- ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
- ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
- sra %o0, 0, %o0
- mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
- sllx %g2, 32, %g2
-
- /* Check if force_successful_syscall_return()
- * was invoked.
- */
- ldub [%curptr + TI_SYS_NOERROR], %l2
- brnz,a,pn %l2, 80f
- stb %g0, [%curptr + TI_SYS_NOERROR]
-
- cmp %o0, -ERESTART_RESTARTBLOCK
- bgeu,pn %xcc, 1f
- andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6
-80:
- /* System call success, clear Carry condition code. */
- andn %g3, %g2, %g3
- stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
- bne,pn %icc, linux_syscall_trace2
- add %l1, 0x4, %l2 ! npc = npc+4
- stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
- ba,pt %xcc, rtrap
- stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
-
-1:
- /* System call failure, set Carry condition code.
- * Also, get abs(errno) to return to the process.
- */
- andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6
- sub %g0, %o0, %o0
- or %g3, %g2, %g3
- stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
- stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
- bne,pn %icc, linux_syscall_trace2
- add %l1, 0x4, %l2 ! npc = npc+4
- stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
-
- b,pt %xcc, rtrap
- stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
-linux_syscall_trace2:
- add %sp, PTREGS_OFF, %o0
- call syscall_trace
- mov 1, %o1
- stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
- ba,pt %xcc, rtrap
- stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
-
- .align 32
- .globl __flushw_user
-__flushw_user:
- rdpr %otherwin, %g1
- brz,pn %g1, 2f
- clr %g2
-1: save %sp, -128, %sp
- rdpr %otherwin, %g1
- brnz,pt %g1, 1b
- add %g2, 1, %g2
-1: sub %g2, 1, %g2
- brnz,pt %g2, 1b
- restore %g0, %g0, %g0
-2: retl
- nop
-
- /* Flush %fp and %i7 to the stack for all register
- * windows active inside of the cpu. This allows
- * show_stack_trace() to avoid using an expensive
- * 'flushw'.
- */
- .globl stack_trace_flush
- .type stack_trace_flush,#function
-stack_trace_flush:
- rdpr %pstate, %o0
- wrpr %o0, PSTATE_IE, %pstate
-
- rdpr %cwp, %g1
- rdpr %canrestore, %g2
- sub %g1, 1, %g3
-
-1: brz,pn %g2, 2f
- sub %g2, 1, %g2
- wrpr %g3, %cwp
- stx %fp, [%sp + STACK_BIAS + RW_V9_I6]
- stx %i7, [%sp + STACK_BIAS + RW_V9_I7]
- ba,pt %xcc, 1b
- sub %g3, 1, %g3
-
-2: wrpr %g1, %cwp
- wrpr %o0, %pstate
-
- retl
- nop
- .size stack_trace_flush,.-stack_trace_flush
-
-#ifdef CONFIG_SMP
- .globl hard_smp_processor_id
-hard_smp_processor_id:
-#endif
- .globl real_hard_smp_processor_id
-real_hard_smp_processor_id:
- __GET_CPUID(%o0)
- retl
- nop
-
- /* %o0: devhandle
- * %o1: devino
- *
- * returns %o0: sysino
- */
- .globl sun4v_devino_to_sysino
- .type sun4v_devino_to_sysino,#function
-sun4v_devino_to_sysino:
- mov HV_FAST_INTR_DEVINO2SYSINO, %o5
- ta HV_FAST_TRAP
- retl
- mov %o1, %o0
- .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino
-
- /* %o0: sysino
- *
- * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
- */
- .globl sun4v_intr_getenabled
- .type sun4v_intr_getenabled,#function
-sun4v_intr_getenabled:
- mov HV_FAST_INTR_GETENABLED, %o5
- ta HV_FAST_TRAP
- retl
- mov %o1, %o0
- .size sun4v_intr_getenabled, .-sun4v_intr_getenabled
-
- /* %o0: sysino
- * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
- */
- .globl sun4v_intr_setenabled
- .type sun4v_intr_setenabled,#function
-sun4v_intr_setenabled:
- mov HV_FAST_INTR_SETENABLED, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_intr_setenabled, .-sun4v_intr_setenabled
-
- /* %o0: sysino
- *
- * returns %o0: intr_state (HV_INTR_STATE_*)
- */
- .globl sun4v_intr_getstate
- .type sun4v_intr_getstate,#function
-sun4v_intr_getstate:
- mov HV_FAST_INTR_GETSTATE, %o5
- ta HV_FAST_TRAP
- retl
- mov %o1, %o0
- .size sun4v_intr_getstate, .-sun4v_intr_getstate
-
- /* %o0: sysino
- * %o1: intr_state (HV_INTR_STATE_*)
- */
- .globl sun4v_intr_setstate
- .type sun4v_intr_setstate,#function
-sun4v_intr_setstate:
- mov HV_FAST_INTR_SETSTATE, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_intr_setstate, .-sun4v_intr_setstate
-
- /* %o0: sysino
- *
- * returns %o0: cpuid
- */
- .globl sun4v_intr_gettarget
- .type sun4v_intr_gettarget,#function
-sun4v_intr_gettarget:
- mov HV_FAST_INTR_GETTARGET, %o5
- ta HV_FAST_TRAP
- retl
- mov %o1, %o0
- .size sun4v_intr_gettarget, .-sun4v_intr_gettarget
-
- /* %o0: sysino
- * %o1: cpuid
- */
- .globl sun4v_intr_settarget
- .type sun4v_intr_settarget,#function
-sun4v_intr_settarget:
- mov HV_FAST_INTR_SETTARGET, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_intr_settarget, .-sun4v_intr_settarget
-
- /* %o0: cpuid
- * %o1: pc
- * %o2: rtba
- * %o3: arg0
- *
- * returns %o0: status
- */
- .globl sun4v_cpu_start
- .type sun4v_cpu_start,#function
-sun4v_cpu_start:
- mov HV_FAST_CPU_START, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_cpu_start, .-sun4v_cpu_start
-
- /* %o0: cpuid
- *
- * returns %o0: status
- */
- .globl sun4v_cpu_stop
- .type sun4v_cpu_stop,#function
-sun4v_cpu_stop:
- mov HV_FAST_CPU_STOP, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_cpu_stop, .-sun4v_cpu_stop
-
- /* returns %o0: status */
- .globl sun4v_cpu_yield
- .type sun4v_cpu_yield, #function
-sun4v_cpu_yield:
- mov HV_FAST_CPU_YIELD, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_cpu_yield, .-sun4v_cpu_yield
-
- /* %o0: type
- * %o1: queue paddr
- * %o2: num queue entries
- *
- * returns %o0: status
- */
- .globl sun4v_cpu_qconf
- .type sun4v_cpu_qconf,#function
-sun4v_cpu_qconf:
- mov HV_FAST_CPU_QCONF, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_cpu_qconf, .-sun4v_cpu_qconf
-
- /* %o0: num cpus in cpu list
- * %o1: cpu list paddr
- * %o2: mondo block paddr
- *
- * returns %o0: status
- */
- .globl sun4v_cpu_mondo_send
- .type sun4v_cpu_mondo_send,#function
-sun4v_cpu_mondo_send:
- mov HV_FAST_CPU_MONDO_SEND, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send
-
- /* %o0: CPU ID
- *
- * returns %o0: -status if status non-zero, else
- * %o0: cpu state as HV_CPU_STATE_*
- */
- .globl sun4v_cpu_state
- .type sun4v_cpu_state,#function
-sun4v_cpu_state:
- mov HV_FAST_CPU_STATE, %o5
- ta HV_FAST_TRAP
- brnz,pn %o0, 1f
- sub %g0, %o0, %o0
- mov %o1, %o0
-1: retl
- nop
- .size sun4v_cpu_state, .-sun4v_cpu_state
-
- /* %o0: virtual address
- * %o1: must be zero
- * %o2: TTE
- * %o3: HV_MMU_* flags
- *
- * returns %o0: status
- */
- .globl sun4v_mmu_map_perm_addr
- .type sun4v_mmu_map_perm_addr,#function
-sun4v_mmu_map_perm_addr:
- mov HV_FAST_MMU_MAP_PERM_ADDR, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr
-
- /* %o0: number of TSB descriptions
- * %o1: TSB descriptions real address
- *
- * returns %o0: status
- */
- .globl sun4v_mmu_tsb_ctx0
- .type sun4v_mmu_tsb_ctx0,#function
-sun4v_mmu_tsb_ctx0:
- mov HV_FAST_MMU_TSB_CTX0, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0
-
- /* %o0: API group number
- * %o1: pointer to unsigned long major number storage
- * %o2: pointer to unsigned long minor number storage
- *
- * returns %o0: status
- */
- .globl sun4v_get_version
- .type sun4v_get_version,#function
-sun4v_get_version:
- mov HV_CORE_GET_VER, %o5
- mov %o1, %o3
- mov %o2, %o4
- ta HV_CORE_TRAP
- stx %o1, [%o3]
- retl
- stx %o2, [%o4]
- .size sun4v_get_version, .-sun4v_get_version
-
- /* %o0: API group number
- * %o1: desired major number
- * %o2: desired minor number
- * %o3: pointer to unsigned long actual minor number storage
- *
- * returns %o0: status
- */
- .globl sun4v_set_version
- .type sun4v_set_version,#function
-sun4v_set_version:
- mov HV_CORE_SET_VER, %o5
- mov %o3, %o4
- ta HV_CORE_TRAP
- retl
- stx %o1, [%o4]
- .size sun4v_set_version, .-sun4v_set_version
-
- /* %o0: pointer to unsigned long time
- *
- * returns %o0: status
- */
- .globl sun4v_tod_get
- .type sun4v_tod_get,#function
-sun4v_tod_get:
- mov %o0, %o4
- mov HV_FAST_TOD_GET, %o5
- ta HV_FAST_TRAP
- stx %o1, [%o4]
- retl
- nop
- .size sun4v_tod_get, .-sun4v_tod_get
-
- /* %o0: time
- *
- * returns %o0: status
- */
- .globl sun4v_tod_set
- .type sun4v_tod_set,#function
-sun4v_tod_set:
- mov HV_FAST_TOD_SET, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_tod_set, .-sun4v_tod_set
-
- /* %o0: pointer to unsigned long status
- *
- * returns %o0: signed character
- */
- .globl sun4v_con_getchar
- .type sun4v_con_getchar,#function
-sun4v_con_getchar:
- mov %o0, %o4
- mov HV_FAST_CONS_GETCHAR, %o5
- clr %o0
- clr %o1
- ta HV_FAST_TRAP
- stx %o0, [%o4]
- retl
- sra %o1, 0, %o0
- .size sun4v_con_getchar, .-sun4v_con_getchar
-
- /* %o0: signed long character
- *
- * returns %o0: status
- */
- .globl sun4v_con_putchar
- .type sun4v_con_putchar,#function
-sun4v_con_putchar:
- mov HV_FAST_CONS_PUTCHAR, %o5
- ta HV_FAST_TRAP
- retl
- sra %o0, 0, %o0
- .size sun4v_con_putchar, .-sun4v_con_putchar
-
- /* %o0: buffer real address
- * %o1: buffer size
- * %o2: pointer to unsigned long bytes_read
- *
- * returns %o0: status
- */
- .globl sun4v_con_read
- .type sun4v_con_read,#function
-sun4v_con_read:
- mov %o2, %o4
- mov HV_FAST_CONS_READ, %o5
- ta HV_FAST_TRAP
- brnz %o0, 1f
- cmp %o1, -1 /* break */
- be,a,pn %icc, 1f
- mov %o1, %o0
- cmp %o1, -2 /* hup */
- be,a,pn %icc, 1f
- mov %o1, %o0
- stx %o1, [%o4]
-1: retl
- nop
- .size sun4v_con_read, .-sun4v_con_read
-
- /* %o0: buffer real address
- * %o1: buffer size
- * %o2: pointer to unsigned long bytes_written
- *
- * returns %o0: status
- */
- .globl sun4v_con_write
- .type sun4v_con_write,#function
-sun4v_con_write:
- mov %o2, %o4
- mov HV_FAST_CONS_WRITE, %o5
- ta HV_FAST_TRAP
- stx %o1, [%o4]
- retl
- nop
- .size sun4v_con_write, .-sun4v_con_write
-
- /* %o0: soft state
- * %o1: address of description string
- *
- * returns %o0: status
- */
- .globl sun4v_mach_set_soft_state
- .type sun4v_mach_set_soft_state,#function
-sun4v_mach_set_soft_state:
- mov HV_FAST_MACH_SET_SOFT_STATE, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state
-
- /* %o0: exit code
- *
- * Does not return.
- */
- .globl sun4v_mach_exit
- .type sun4v_mach_exit,#function
-sun4v_mach_exit:
- mov HV_FAST_MACH_EXIT, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_mach_exit, .-sun4v_mach_exit
-
- /* %o0: buffer real address
- * %o1: buffer length
- * %o2: pointer to unsigned long real_buf_len
- *
- * returns %o0: status
- */
- .globl sun4v_mach_desc
- .type sun4v_mach_desc,#function
-sun4v_mach_desc:
- mov %o2, %o4
- mov HV_FAST_MACH_DESC, %o5
- ta HV_FAST_TRAP
- stx %o1, [%o4]
- retl
- nop
- .size sun4v_mach_desc, .-sun4v_mach_desc
-
- /* %o0: new timeout in milliseconds
- * %o1: pointer to unsigned long orig_timeout
- *
- * returns %o0: status
- */
- .globl sun4v_mach_set_watchdog
- .type sun4v_mach_set_watchdog,#function
-sun4v_mach_set_watchdog:
- mov %o1, %o4
- mov HV_FAST_MACH_SET_WATCHDOG, %o5
- ta HV_FAST_TRAP
- stx %o1, [%o4]
- retl
- nop
- .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog
-
- /* No inputs and does not return. */
- .globl sun4v_mach_sir
- .type sun4v_mach_sir,#function
-sun4v_mach_sir:
- mov %o1, %o4
- mov HV_FAST_MACH_SIR, %o5
- ta HV_FAST_TRAP
- stx %o1, [%o4]
- retl
- nop
- .size sun4v_mach_sir, .-sun4v_mach_sir
-
- /* %o0: channel
- * %o1: ra
- * %o2: num_entries
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_tx_qconf
- .type sun4v_ldc_tx_qconf,#function
-sun4v_ldc_tx_qconf:
- mov HV_FAST_LDC_TX_QCONF, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf
-
- /* %o0: channel
- * %o1: pointer to unsigned long ra
- * %o2: pointer to unsigned long num_entries
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_tx_qinfo
- .type sun4v_ldc_tx_qinfo,#function
-sun4v_ldc_tx_qinfo:
- mov %o1, %g1
- mov %o2, %g2
- mov HV_FAST_LDC_TX_QINFO, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- stx %o2, [%g2]
- retl
- nop
- .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo
-
- /* %o0: channel
- * %o1: pointer to unsigned long head_off
- * %o2: pointer to unsigned long tail_off
- * %o2: pointer to unsigned long chan_state
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_tx_get_state
- .type sun4v_ldc_tx_get_state,#function
-sun4v_ldc_tx_get_state:
- mov %o1, %g1
- mov %o2, %g2
- mov %o3, %g3
- mov HV_FAST_LDC_TX_GET_STATE, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- stx %o2, [%g2]
- stx %o3, [%g3]
- retl
- nop
- .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state
-
- /* %o0: channel
- * %o1: tail_off
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_tx_set_qtail
- .type sun4v_ldc_tx_set_qtail,#function
-sun4v_ldc_tx_set_qtail:
- mov HV_FAST_LDC_TX_SET_QTAIL, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail
-
- /* %o0: channel
- * %o1: ra
- * %o2: num_entries
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_rx_qconf
- .type sun4v_ldc_rx_qconf,#function
-sun4v_ldc_rx_qconf:
- mov HV_FAST_LDC_RX_QCONF, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf
-
- /* %o0: channel
- * %o1: pointer to unsigned long ra
- * %o2: pointer to unsigned long num_entries
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_rx_qinfo
- .type sun4v_ldc_rx_qinfo,#function
-sun4v_ldc_rx_qinfo:
- mov %o1, %g1
- mov %o2, %g2
- mov HV_FAST_LDC_RX_QINFO, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- stx %o2, [%g2]
- retl
- nop
- .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo
-
- /* %o0: channel
- * %o1: pointer to unsigned long head_off
- * %o2: pointer to unsigned long tail_off
- * %o2: pointer to unsigned long chan_state
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_rx_get_state
- .type sun4v_ldc_rx_get_state,#function
-sun4v_ldc_rx_get_state:
- mov %o1, %g1
- mov %o2, %g2
- mov %o3, %g3
- mov HV_FAST_LDC_RX_GET_STATE, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- stx %o2, [%g2]
- stx %o3, [%g3]
- retl
- nop
- .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state
-
- /* %o0: channel
- * %o1: head_off
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_rx_set_qhead
- .type sun4v_ldc_rx_set_qhead,#function
-sun4v_ldc_rx_set_qhead:
- mov HV_FAST_LDC_RX_SET_QHEAD, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead
-
- /* %o0: channel
- * %o1: ra
- * %o2: num_entries
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_set_map_table
- .type sun4v_ldc_set_map_table,#function
-sun4v_ldc_set_map_table:
- mov HV_FAST_LDC_SET_MAP_TABLE, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table
-
- /* %o0: channel
- * %o1: pointer to unsigned long ra
- * %o2: pointer to unsigned long num_entries
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_get_map_table
- .type sun4v_ldc_get_map_table,#function
-sun4v_ldc_get_map_table:
- mov %o1, %g1
- mov %o2, %g2
- mov HV_FAST_LDC_GET_MAP_TABLE, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- stx %o2, [%g2]
- retl
- nop
- .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table
-
- /* %o0: channel
- * %o1: dir_code
- * %o2: tgt_raddr
- * %o3: lcl_raddr
- * %o4: len
- * %o5: pointer to unsigned long actual_len
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_copy
- .type sun4v_ldc_copy,#function
-sun4v_ldc_copy:
- mov %o5, %g1
- mov HV_FAST_LDC_COPY, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- retl
- nop
- .size sun4v_ldc_copy, .-sun4v_ldc_copy
-
- /* %o0: channel
- * %o1: cookie
- * %o2: pointer to unsigned long ra
- * %o3: pointer to unsigned long perm
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_mapin
- .type sun4v_ldc_mapin,#function
-sun4v_ldc_mapin:
- mov %o2, %g1
- mov %o3, %g2
- mov HV_FAST_LDC_MAPIN, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- stx %o2, [%g2]
- retl
- nop
- .size sun4v_ldc_mapin, .-sun4v_ldc_mapin
-
- /* %o0: ra
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_unmap
- .type sun4v_ldc_unmap,#function
-sun4v_ldc_unmap:
- mov HV_FAST_LDC_UNMAP, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_ldc_unmap, .-sun4v_ldc_unmap
-
- /* %o0: channel
- * %o1: cookie
- * %o2: mte_cookie
- *
- * returns %o0: status
- */
- .globl sun4v_ldc_revoke
- .type sun4v_ldc_revoke,#function
-sun4v_ldc_revoke:
- mov HV_FAST_LDC_REVOKE, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_ldc_revoke, .-sun4v_ldc_revoke
-
- /* %o0: device handle
- * %o1: device INO
- * %o2: pointer to unsigned long cookie
- *
- * returns %o0: status
- */
- .globl sun4v_vintr_get_cookie
- .type sun4v_vintr_get_cookie,#function
-sun4v_vintr_get_cookie:
- mov %o2, %g1
- mov HV_FAST_VINTR_GET_COOKIE, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- retl
- nop
- .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie
-
- /* %o0: device handle
- * %o1: device INO
- * %o2: cookie
- *
- * returns %o0: status
- */
- .globl sun4v_vintr_set_cookie
- .type sun4v_vintr_set_cookie,#function
-sun4v_vintr_set_cookie:
- mov HV_FAST_VINTR_SET_COOKIE, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie
-
- /* %o0: device handle
- * %o1: device INO
- * %o2: pointer to unsigned long valid_state
- *
- * returns %o0: status
- */
- .globl sun4v_vintr_get_valid
- .type sun4v_vintr_get_valid,#function
-sun4v_vintr_get_valid:
- mov %o2, %g1
- mov HV_FAST_VINTR_GET_VALID, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- retl
- nop
- .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid
-
- /* %o0: device handle
- * %o1: device INO
- * %o2: valid_state
- *
- * returns %o0: status
- */
- .globl sun4v_vintr_set_valid
- .type sun4v_vintr_set_valid,#function
-sun4v_vintr_set_valid:
- mov HV_FAST_VINTR_SET_VALID, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid
-
- /* %o0: device handle
- * %o1: device INO
- * %o2: pointer to unsigned long state
- *
- * returns %o0: status
- */
- .globl sun4v_vintr_get_state
- .type sun4v_vintr_get_state,#function
-sun4v_vintr_get_state:
- mov %o2, %g1
- mov HV_FAST_VINTR_GET_STATE, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- retl
- nop
- .size sun4v_vintr_get_state, .-sun4v_vintr_get_state
-
- /* %o0: device handle
- * %o1: device INO
- * %o2: state
- *
- * returns %o0: status
- */
- .globl sun4v_vintr_set_state
- .type sun4v_vintr_set_state,#function
-sun4v_vintr_set_state:
- mov HV_FAST_VINTR_SET_STATE, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_vintr_set_state, .-sun4v_vintr_set_state
-
- /* %o0: device handle
- * %o1: device INO
- * %o2: pointer to unsigned long cpuid
- *
- * returns %o0: status
- */
- .globl sun4v_vintr_get_target
- .type sun4v_vintr_get_target,#function
-sun4v_vintr_get_target:
- mov %o2, %g1
- mov HV_FAST_VINTR_GET_TARGET, %o5
- ta HV_FAST_TRAP
- stx %o1, [%g1]
- retl
- nop
- .size sun4v_vintr_get_target, .-sun4v_vintr_get_target
-
- /* %o0: device handle
- * %o1: device INO
- * %o2: cpuid
- *
- * returns %o0: status
- */
- .globl sun4v_vintr_set_target
- .type sun4v_vintr_set_target,#function
-sun4v_vintr_set_target:
- mov HV_FAST_VINTR_SET_TARGET, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_vintr_set_target, .-sun4v_vintr_set_target
-
- /* %o0: NCS sub-function
- * %o1: sub-function arg real-address
- * %o2: sub-function arg size
- *
- * returns %o0: status
- */
- .globl sun4v_ncs_request
- .type sun4v_ncs_request,#function
-sun4v_ncs_request:
- mov HV_FAST_NCS_REQUEST, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_ncs_request, .-sun4v_ncs_request
-
- .globl sun4v_svc_send
- .type sun4v_svc_send,#function
-sun4v_svc_send:
- save %sp, -192, %sp
- mov %i0, %o0
- mov %i1, %o1
- mov %i2, %o2
- mov HV_FAST_SVC_SEND, %o5
- ta HV_FAST_TRAP
- stx %o1, [%i3]
- ret
- restore
- .size sun4v_svc_send, .-sun4v_svc_send
-
- .globl sun4v_svc_recv
- .type sun4v_svc_recv,#function
-sun4v_svc_recv:
- save %sp, -192, %sp
- mov %i0, %o0
- mov %i1, %o1
- mov %i2, %o2
- mov HV_FAST_SVC_RECV, %o5
- ta HV_FAST_TRAP
- stx %o1, [%i3]
- ret
- restore
- .size sun4v_svc_recv, .-sun4v_svc_recv
-
- .globl sun4v_svc_getstatus
- .type sun4v_svc_getstatus,#function
-sun4v_svc_getstatus:
- mov HV_FAST_SVC_GETSTATUS, %o5
- mov %o1, %o4
- ta HV_FAST_TRAP
- stx %o1, [%o4]
- retl
- nop
- .size sun4v_svc_getstatus, .-sun4v_svc_getstatus
-
- .globl sun4v_svc_setstatus
- .type sun4v_svc_setstatus,#function
-sun4v_svc_setstatus:
- mov HV_FAST_SVC_SETSTATUS, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_svc_setstatus, .-sun4v_svc_setstatus
-
- .globl sun4v_svc_clrstatus
- .type sun4v_svc_clrstatus,#function
-sun4v_svc_clrstatus:
- mov HV_FAST_SVC_CLRSTATUS, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus
-
- .globl sun4v_mmustat_conf
- .type sun4v_mmustat_conf,#function
-sun4v_mmustat_conf:
- mov %o1, %o4
- mov HV_FAST_MMUSTAT_CONF, %o5
- ta HV_FAST_TRAP
- stx %o1, [%o4]
- retl
- nop
- .size sun4v_mmustat_conf, .-sun4v_mmustat_conf
-
- .globl sun4v_mmustat_info
- .type sun4v_mmustat_info,#function
-sun4v_mmustat_info:
- mov %o0, %o4
- mov HV_FAST_MMUSTAT_INFO, %o5
- ta HV_FAST_TRAP
- stx %o1, [%o4]
- retl
- nop
- .size sun4v_mmustat_info, .-sun4v_mmustat_info
-
- .globl sun4v_mmu_demap_all
- .type sun4v_mmu_demap_all,#function
-sun4v_mmu_demap_all:
- clr %o0
- clr %o1
- mov HV_MMU_ALL, %o2
- mov HV_FAST_MMU_DEMAP_ALL, %o5
- ta HV_FAST_TRAP
- retl
- nop
- .size sun4v_mmu_demap_all, .-sun4v_mmu_demap_all
diff --git a/arch/sparc64/kernel/fpu_traps.S b/arch/sparc64/kernel/fpu_traps.S
new file mode 100644
index 0000000..a686482
--- /dev/null
+++ b/arch/sparc64/kernel/fpu_traps.S
@@ -0,0 +1,384 @@
+ /* This is trivial with the new code... */
+ .globl do_fpdis
+ .type do_fpdis,#function
+do_fpdis:
+ sethi %hi(TSTATE_PEF), %g4
+ rdpr %tstate, %g5
+ andcc %g5, %g4, %g0
+ be,pt %xcc, 1f
+ nop
+ rd %fprs, %g5
+ andcc %g5, FPRS_FEF, %g0
+ be,pt %xcc, 1f
+ nop
+
+ /* Legal state when DCR_IFPOE is set in Cheetah %dcr. */
+ sethi %hi(109f), %g7
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ add %g0, %g0, %g0
+ ba,a,pt %xcc, rtrap
+
+1: TRAP_LOAD_THREAD_REG(%g6, %g1)
+ ldub [%g6 + TI_FPSAVED], %g5
+ wr %g0, FPRS_FEF, %fprs
+ andcc %g5, FPRS_FEF, %g0
+ be,a,pt %icc, 1f
+ clr %g7
+ ldx [%g6 + TI_GSR], %g7
+1: andcc %g5, FPRS_DL, %g0
+ bne,pn %icc, 2f
+ fzero %f0
+ andcc %g5, FPRS_DU, %g0
+ bne,pn %icc, 1f
+ fzero %f2
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
+ faddd %f0, %f2, %f32
+ fmuld %f0, %f2, %f34
+ faddd %f0, %f2, %f36
+ fmuld %f0, %f2, %f38
+ faddd %f0, %f2, %f40
+ fmuld %f0, %f2, %f42
+ faddd %f0, %f2, %f44
+ fmuld %f0, %f2, %f46
+ faddd %f0, %f2, %f48
+ fmuld %f0, %f2, %f50
+ faddd %f0, %f2, %f52
+ fmuld %f0, %f2, %f54
+ faddd %f0, %f2, %f56
+ fmuld %f0, %f2, %f58
+ b,pt %xcc, fpdis_exit2
+ faddd %f0, %f2, %f60
+1: mov SECONDARY_CONTEXT, %g3
+ add %g6, TI_FPREGS + 0x80, %g1
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+
+661: ldxa [%g3] ASI_DMMU, %g5
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ ldxa [%g3] ASI_MMU, %g5
+ .previous
+
+ sethi %hi(sparc64_kern_sec_context), %g2
+ ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
+
+661: stxa %g2, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g2, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+ add %g6, TI_FPREGS + 0xc0, %g2
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ membar #Sync
+ ldda [%g1] ASI_BLK_S, %f32
+ ldda [%g2] ASI_BLK_S, %f48
+ membar #Sync
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
+ b,pt %xcc, fpdis_exit
+ nop
+2: andcc %g5, FPRS_DU, %g0
+ bne,pt %icc, 3f
+ fzero %f32
+ mov SECONDARY_CONTEXT, %g3
+ fzero %f34
+
+661: ldxa [%g3] ASI_DMMU, %g5
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ ldxa [%g3] ASI_MMU, %g5
+ .previous
+
+ add %g6, TI_FPREGS, %g1
+ sethi %hi(sparc64_kern_sec_context), %g2
+ ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
+
+661: stxa %g2, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g2, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+ add %g6, TI_FPREGS + 0x40, %g2
+ faddd %f32, %f34, %f36
+ fmuld %f32, %f34, %f38
+ membar #Sync
+ ldda [%g1] ASI_BLK_S, %f0
+ ldda [%g2] ASI_BLK_S, %f16
+ membar #Sync
+ faddd %f32, %f34, %f40
+ fmuld %f32, %f34, %f42
+ faddd %f32, %f34, %f44
+ fmuld %f32, %f34, %f46
+ faddd %f32, %f34, %f48
+ fmuld %f32, %f34, %f50
+ faddd %f32, %f34, %f52
+ fmuld %f32, %f34, %f54
+ faddd %f32, %f34, %f56
+ fmuld %f32, %f34, %f58
+ faddd %f32, %f34, %f60
+ fmuld %f32, %f34, %f62
+ ba,pt %xcc, fpdis_exit
+ nop
+3: mov SECONDARY_CONTEXT, %g3
+ add %g6, TI_FPREGS, %g1
+
+661: ldxa [%g3] ASI_DMMU, %g5
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ ldxa [%g3] ASI_MMU, %g5
+ .previous
+
+ sethi %hi(sparc64_kern_sec_context), %g2
+ ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
+
+661: stxa %g2, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g2, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+ mov 0x40, %g2
+ membar #Sync
+ ldda [%g1] ASI_BLK_S, %f0
+ ldda [%g1 + %g2] ASI_BLK_S, %f16
+ add %g1, 0x80, %g1
+ ldda [%g1] ASI_BLK_S, %f32
+ ldda [%g1 + %g2] ASI_BLK_S, %f48
+ membar #Sync
+fpdis_exit:
+
+661: stxa %g5, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g5, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+fpdis_exit2:
+ wr %g7, 0, %gsr
+ ldx [%g6 + TI_XFSR], %fsr
+ rdpr %tstate, %g3
+ or %g3, %g4, %g3 ! anal...
+ wrpr %g3, %tstate
+ wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits
+ retry
+ .size do_fpdis,.-do_fpdis
+
+ .align 32
+ .type fp_other_bounce,#function
+fp_other_bounce:
+ call do_fpother
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size fp_other_bounce,.-fp_other_bounce
+
+ .align 32
+ .globl do_fpother_check_fitos
+ .type do_fpother_check_fitos,#function
+do_fpother_check_fitos:
+ TRAP_LOAD_THREAD_REG(%g6, %g1)
+ sethi %hi(fp_other_bounce - 4), %g7
+ or %g7, %lo(fp_other_bounce - 4), %g7
+
+ /* NOTE: Need to preserve %g7 until we fully commit
+ * to the fitos fixup.
+ */
+ stx %fsr, [%g6 + TI_XFSR]
+ rdpr %tstate, %g3
+ andcc %g3, TSTATE_PRIV, %g0
+ bne,pn %xcc, do_fptrap_after_fsr
+ nop
+ ldx [%g6 + TI_XFSR], %g3
+ srlx %g3, 14, %g1
+ and %g1, 7, %g1
+ cmp %g1, 2 ! Unfinished FP-OP
+ bne,pn %xcc, do_fptrap_after_fsr
+ sethi %hi(1 << 23), %g1 ! Inexact
+ andcc %g3, %g1, %g0
+ bne,pn %xcc, do_fptrap_after_fsr
+ rdpr %tpc, %g1
+ lduwa [%g1] ASI_AIUP, %g3 ! This cannot ever fail
+#define FITOS_MASK 0xc1f83fe0
+#define FITOS_COMPARE 0x81a01880
+ sethi %hi(FITOS_MASK), %g1
+ or %g1, %lo(FITOS_MASK), %g1
+ and %g3, %g1, %g1
+ sethi %hi(FITOS_COMPARE), %g2
+ or %g2, %lo(FITOS_COMPARE), %g2
+ cmp %g1, %g2
+ bne,pn %xcc, do_fptrap_after_fsr
+ nop
+ std %f62, [%g6 + TI_FPREGS + (62 * 4)]
+ sethi %hi(fitos_table_1), %g1
+ and %g3, 0x1f, %g2
+ or %g1, %lo(fitos_table_1), %g1
+ sllx %g2, 2, %g2
+ jmpl %g1 + %g2, %g0
+ ba,pt %xcc, fitos_emul_continue
+
+fitos_table_1:
+ fitod %f0, %f62
+ fitod %f1, %f62
+ fitod %f2, %f62
+ fitod %f3, %f62
+ fitod %f4, %f62
+ fitod %f5, %f62
+ fitod %f6, %f62
+ fitod %f7, %f62
+ fitod %f8, %f62
+ fitod %f9, %f62
+ fitod %f10, %f62
+ fitod %f11, %f62
+ fitod %f12, %f62
+ fitod %f13, %f62
+ fitod %f14, %f62
+ fitod %f15, %f62
+ fitod %f16, %f62
+ fitod %f17, %f62
+ fitod %f18, %f62
+ fitod %f19, %f62
+ fitod %f20, %f62
+ fitod %f21, %f62
+ fitod %f22, %f62
+ fitod %f23, %f62
+ fitod %f24, %f62
+ fitod %f25, %f62
+ fitod %f26, %f62
+ fitod %f27, %f62
+ fitod %f28, %f62
+ fitod %f29, %f62
+ fitod %f30, %f62
+ fitod %f31, %f62
+
+fitos_emul_continue:
+ sethi %hi(fitos_table_2), %g1
+ srl %g3, 25, %g2
+ or %g1, %lo(fitos_table_2), %g1
+ and %g2, 0x1f, %g2
+ sllx %g2, 2, %g2
+ jmpl %g1 + %g2, %g0
+ ba,pt %xcc, fitos_emul_fini
+
+fitos_table_2:
+ fdtos %f62, %f0
+ fdtos %f62, %f1
+ fdtos %f62, %f2
+ fdtos %f62, %f3
+ fdtos %f62, %f4
+ fdtos %f62, %f5
+ fdtos %f62, %f6
+ fdtos %f62, %f7
+ fdtos %f62, %f8
+ fdtos %f62, %f9
+ fdtos %f62, %f10
+ fdtos %f62, %f11
+ fdtos %f62, %f12
+ fdtos %f62, %f13
+ fdtos %f62, %f14
+ fdtos %f62, %f15
+ fdtos %f62, %f16
+ fdtos %f62, %f17
+ fdtos %f62, %f18
+ fdtos %f62, %f19
+ fdtos %f62, %f20
+ fdtos %f62, %f21
+ fdtos %f62, %f22
+ fdtos %f62, %f23
+ fdtos %f62, %f24
+ fdtos %f62, %f25
+ fdtos %f62, %f26
+ fdtos %f62, %f27
+ fdtos %f62, %f28
+ fdtos %f62, %f29
+ fdtos %f62, %f30
+ fdtos %f62, %f31
+
+fitos_emul_fini:
+ ldd [%g6 + TI_FPREGS + (62 * 4)], %f62
+ done
+ .size do_fpother_check_fitos,.-do_fpother_check_fitos
+
+ .align 32
+ .globl do_fptrap
+ .type do_fptrap,#function
+do_fptrap:
+ TRAP_LOAD_THREAD_REG(%g6, %g1)
+ stx %fsr, [%g6 + TI_XFSR]
+do_fptrap_after_fsr:
+ ldub [%g6 + TI_FPSAVED], %g3
+ rd %fprs, %g1
+ or %g3, %g1, %g3
+ stb %g3, [%g6 + TI_FPSAVED]
+ rd %gsr, %g3
+ stx %g3, [%g6 + TI_GSR]
+ mov SECONDARY_CONTEXT, %g3
+
+661: ldxa [%g3] ASI_DMMU, %g5
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ ldxa [%g3] ASI_MMU, %g5
+ .previous
+
+ sethi %hi(sparc64_kern_sec_context), %g2
+ ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
+
+661: stxa %g2, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g2, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+ add %g6, TI_FPREGS, %g2
+ andcc %g1, FPRS_DL, %g0
+ be,pn %icc, 4f
+ mov 0x40, %g3
+ stda %f0, [%g2] ASI_BLK_S
+ stda %f16, [%g2 + %g3] ASI_BLK_S
+ andcc %g1, FPRS_DU, %g0
+ be,pn %icc, 5f
+4: add %g2, 128, %g2
+ stda %f32, [%g2] ASI_BLK_S
+ stda %f48, [%g2 + %g3] ASI_BLK_S
+5: mov SECONDARY_CONTEXT, %g1
+ membar #Sync
+
+661: stxa %g5, [%g1] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g5, [%g1] ASI_MMU
+ .previous
+
+ membar #Sync
+ ba,pt %xcc, etrap
+ wr %g0, 0, %fprs
+ .size do_fptrap,.-do_fptrap
diff --git a/arch/sparc64/kernel/getsetcc.S b/arch/sparc64/kernel/getsetcc.S
new file mode 100644
index 0000000..a14d272
--- /dev/null
+++ b/arch/sparc64/kernel/getsetcc.S
@@ -0,0 +1,24 @@
+ .globl getcc
+ .type getcc,#function
+getcc:
+ ldx [%o0 + PT_V9_TSTATE], %o1
+ srlx %o1, 32, %o1
+ and %o1, 0xf, %o1
+ retl
+ stx %o1, [%o0 + PT_V9_G1]
+ .size getcc,.-getcc
+
+ .globl setcc
+ .type setcc,#function
+setcc:
+ ldx [%o0 + PT_V9_TSTATE], %o1
+ ldx [%o0 + PT_V9_G1], %o2
+ or %g0, %ulo(TSTATE_ICC), %o3
+ sllx %o3, 32, %o3
+ andn %o1, %o3, %o1
+ sllx %o2, 32, %o2
+ and %o2, %o3, %o2
+ or %o1, %o2, %o1
+ retl
+ stx %o1, [%o0 + PT_V9_TSTATE]
+ .size setcc,.-setcc
diff --git a/arch/sparc64/kernel/head.S b/arch/sparc64/kernel/head.S
index 34f8ff5..c9afef0 100644
--- a/arch/sparc64/kernel/head.S
+++ b/arch/sparc64/kernel/head.S
@@ -27,6 +27,10 @@
#include <asm/ttable.h>
#include <asm/mmu.h>
#include <asm/cpudata.h>
+#include <asm/pil.h>
+#include <asm/estate.h>
+#include <asm/sfafsr.h>
+#include <asm/unistd.h>
/* This section from from _start to sparc64_boot_end should fit into
* 0x0000000000404000 to 0x0000000000408000.
@@ -823,7 +827,16 @@
#include "etrap.S"
#include "rtrap.S"
#include "winfixup.S"
-#include "entry.S"
+#include "fpu_traps.S"
+#include "ivec.S"
+#include "getsetcc.S"
+#include "utrap.S"
+#include "spiterrs.S"
+#include "cherrs.S"
+#include "misctrap.S"
+#include "syscalls.S"
+#include "helpers.S"
+#include "hvcalls.S"
#include "sun4v_tlb_miss.S"
#include "sun4v_ivec.S"
#include "ktlb.S"
diff --git a/arch/sparc64/kernel/helpers.S b/arch/sparc64/kernel/helpers.S
new file mode 100644
index 0000000..314dd0c
--- /dev/null
+++ b/arch/sparc64/kernel/helpers.S
@@ -0,0 +1,63 @@
+ .align 32
+ .globl __flushw_user
+ .type __flushw_user,#function
+__flushw_user:
+ rdpr %otherwin, %g1
+ brz,pn %g1, 2f
+ clr %g2
+1: save %sp, -128, %sp
+ rdpr %otherwin, %g1
+ brnz,pt %g1, 1b
+ add %g2, 1, %g2
+1: sub %g2, 1, %g2
+ brnz,pt %g2, 1b
+ restore %g0, %g0, %g0
+2: retl
+ nop
+ .size __flushw_user,.-__flushw_user
+
+ /* Flush %fp and %i7 to the stack for all register
+ * windows active inside of the cpu. This allows
+ * show_stack_trace() to avoid using an expensive
+ * 'flushw'.
+ */
+ .globl stack_trace_flush
+ .type stack_trace_flush,#function
+stack_trace_flush:
+ rdpr %pstate, %o0
+ wrpr %o0, PSTATE_IE, %pstate
+
+ rdpr %cwp, %g1
+ rdpr %canrestore, %g2
+ sub %g1, 1, %g3
+
+1: brz,pn %g2, 2f
+ sub %g2, 1, %g2
+ wrpr %g3, %cwp
+ stx %fp, [%sp + STACK_BIAS + RW_V9_I6]
+ stx %i7, [%sp + STACK_BIAS + RW_V9_I7]
+ ba,pt %xcc, 1b
+ sub %g3, 1, %g3
+
+2: wrpr %g1, %cwp
+ wrpr %o0, %pstate
+
+ retl
+ nop
+ .size stack_trace_flush,.-stack_trace_flush
+
+#ifdef CONFIG_SMP
+ .globl hard_smp_processor_id
+ .type hard_smp_processor_id,#function
+hard_smp_processor_id:
+#endif
+ .globl real_hard_smp_processor_id
+ .type real_hard_smp_processor_id,#function
+real_hard_smp_processor_id:
+ __GET_CPUID(%o0)
+ retl
+ nop
+#ifdef CONFIG_SMP
+ .size hard_smp_processor_id,.-hard_smp_processor_id
+#endif
+ .size real_hard_smp_processor_id,.-real_hard_smp_processor_id
diff --git a/arch/sparc64/kernel/hvcalls.S b/arch/sparc64/kernel/hvcalls.S
new file mode 100644
index 0000000..a2810f3
--- /dev/null
+++ b/arch/sparc64/kernel/hvcalls.S
@@ -0,0 +1,886 @@
+ /* %o0: devhandle
+ * %o1: devino
+ *
+ * returns %o0: sysino
+ */
+ .globl sun4v_devino_to_sysino
+ .type sun4v_devino_to_sysino,#function
+sun4v_devino_to_sysino:
+ mov HV_FAST_INTR_DEVINO2SYSINO, %o5
+ ta HV_FAST_TRAP
+ retl
+ mov %o1, %o0
+ .size sun4v_devino_to_sysino, .-sun4v_devino_to_sysino
+
+ /* %o0: sysino
+ *
+ * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
+ */
+ .globl sun4v_intr_getenabled
+ .type sun4v_intr_getenabled,#function
+sun4v_intr_getenabled:
+ mov HV_FAST_INTR_GETENABLED, %o5
+ ta HV_FAST_TRAP
+ retl
+ mov %o1, %o0
+ .size sun4v_intr_getenabled, .-sun4v_intr_getenabled
+
+ /* %o0: sysino
+ * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
+ */
+ .globl sun4v_intr_setenabled
+ .type sun4v_intr_setenabled,#function
+sun4v_intr_setenabled:
+ mov HV_FAST_INTR_SETENABLED, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_intr_setenabled, .-sun4v_intr_setenabled
+
+ /* %o0: sysino
+ *
+ * returns %o0: intr_state (HV_INTR_STATE_*)
+ */
+ .globl sun4v_intr_getstate
+ .type sun4v_intr_getstate,#function
+sun4v_intr_getstate:
+ mov HV_FAST_INTR_GETSTATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ mov %o1, %o0
+ .size sun4v_intr_getstate, .-sun4v_intr_getstate
+
+ /* %o0: sysino
+ * %o1: intr_state (HV_INTR_STATE_*)
+ */
+ .globl sun4v_intr_setstate
+ .type sun4v_intr_setstate,#function
+sun4v_intr_setstate:
+ mov HV_FAST_INTR_SETSTATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_intr_setstate, .-sun4v_intr_setstate
+
+ /* %o0: sysino
+ *
+ * returns %o0: cpuid
+ */
+ .globl sun4v_intr_gettarget
+ .type sun4v_intr_gettarget,#function
+sun4v_intr_gettarget:
+ mov HV_FAST_INTR_GETTARGET, %o5
+ ta HV_FAST_TRAP
+ retl
+ mov %o1, %o0
+ .size sun4v_intr_gettarget, .-sun4v_intr_gettarget
+
+ /* %o0: sysino
+ * %o1: cpuid
+ */
+ .globl sun4v_intr_settarget
+ .type sun4v_intr_settarget,#function
+sun4v_intr_settarget:
+ mov HV_FAST_INTR_SETTARGET, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_intr_settarget, .-sun4v_intr_settarget
+
+ /* %o0: cpuid
+ * %o1: pc
+ * %o2: rtba
+ * %o3: arg0
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_cpu_start
+ .type sun4v_cpu_start,#function
+sun4v_cpu_start:
+ mov HV_FAST_CPU_START, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_cpu_start, .-sun4v_cpu_start
+
+ /* %o0: cpuid
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_cpu_stop
+ .type sun4v_cpu_stop,#function
+sun4v_cpu_stop:
+ mov HV_FAST_CPU_STOP, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_cpu_stop, .-sun4v_cpu_stop
+
+ /* returns %o0: status */
+ .globl sun4v_cpu_yield
+ .type sun4v_cpu_yield, #function
+sun4v_cpu_yield:
+ mov HV_FAST_CPU_YIELD, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_cpu_yield, .-sun4v_cpu_yield
+
+ /* %o0: type
+ * %o1: queue paddr
+ * %o2: num queue entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_cpu_qconf
+ .type sun4v_cpu_qconf,#function
+sun4v_cpu_qconf:
+ mov HV_FAST_CPU_QCONF, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_cpu_qconf, .-sun4v_cpu_qconf
+
+ /* %o0: num cpus in cpu list
+ * %o1: cpu list paddr
+ * %o2: mondo block paddr
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_cpu_mondo_send
+ .type sun4v_cpu_mondo_send,#function
+sun4v_cpu_mondo_send:
+ mov HV_FAST_CPU_MONDO_SEND, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_cpu_mondo_send, .-sun4v_cpu_mondo_send
+
+ /* %o0: CPU ID
+ *
+ * returns %o0: -status if status non-zero, else
+ * %o0: cpu state as HV_CPU_STATE_*
+ */
+ .globl sun4v_cpu_state
+ .type sun4v_cpu_state,#function
+sun4v_cpu_state:
+ mov HV_FAST_CPU_STATE, %o5
+ ta HV_FAST_TRAP
+ brnz,pn %o0, 1f
+ sub %g0, %o0, %o0
+ mov %o1, %o0
+1: retl
+ nop
+ .size sun4v_cpu_state, .-sun4v_cpu_state
+
+ /* %o0: virtual address
+ * %o1: must be zero
+ * %o2: TTE
+ * %o3: HV_MMU_* flags
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mmu_map_perm_addr
+ .type sun4v_mmu_map_perm_addr,#function
+sun4v_mmu_map_perm_addr:
+ mov HV_FAST_MMU_MAP_PERM_ADDR, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_mmu_map_perm_addr, .-sun4v_mmu_map_perm_addr
+
+ /* %o0: number of TSB descriptions
+ * %o1: TSB descriptions real address
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mmu_tsb_ctx0
+ .type sun4v_mmu_tsb_ctx0,#function
+sun4v_mmu_tsb_ctx0:
+ mov HV_FAST_MMU_TSB_CTX0, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_mmu_tsb_ctx0, .-sun4v_mmu_tsb_ctx0
+
+ /* %o0: API group number
+ * %o1: pointer to unsigned long major number storage
+ * %o2: pointer to unsigned long minor number storage
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_get_version
+ .type sun4v_get_version,#function
+sun4v_get_version:
+ mov HV_CORE_GET_VER, %o5
+ mov %o1, %o3
+ mov %o2, %o4
+ ta HV_CORE_TRAP
+ stx %o1, [%o3]
+ retl
+ stx %o2, [%o4]
+ .size sun4v_get_version, .-sun4v_get_version
+
+ /* %o0: API group number
+ * %o1: desired major number
+ * %o2: desired minor number
+ * %o3: pointer to unsigned long actual minor number storage
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_set_version
+ .type sun4v_set_version,#function
+sun4v_set_version:
+ mov HV_CORE_SET_VER, %o5
+ mov %o3, %o4
+ ta HV_CORE_TRAP
+ retl
+ stx %o1, [%o4]
+ .size sun4v_set_version, .-sun4v_set_version
+
+ /* %o0: pointer to unsigned long time
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_tod_get
+ .type sun4v_tod_get,#function
+sun4v_tod_get:
+ mov %o0, %o4
+ mov HV_FAST_TOD_GET, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_tod_get, .-sun4v_tod_get
+
+ /* %o0: time
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_tod_set
+ .type sun4v_tod_set,#function
+sun4v_tod_set:
+ mov HV_FAST_TOD_SET, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_tod_set, .-sun4v_tod_set
+
+ /* %o0: pointer to unsigned long status
+ *
+ * returns %o0: signed character
+ */
+ .globl sun4v_con_getchar
+ .type sun4v_con_getchar,#function
+sun4v_con_getchar:
+ mov %o0, %o4
+ mov HV_FAST_CONS_GETCHAR, %o5
+ clr %o0
+ clr %o1
+ ta HV_FAST_TRAP
+ stx %o0, [%o4]
+ retl
+ sra %o1, 0, %o0
+ .size sun4v_con_getchar, .-sun4v_con_getchar
+
+ /* %o0: signed long character
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_con_putchar
+ .type sun4v_con_putchar,#function
+sun4v_con_putchar:
+ mov HV_FAST_CONS_PUTCHAR, %o5
+ ta HV_FAST_TRAP
+ retl
+ sra %o0, 0, %o0
+ .size sun4v_con_putchar, .-sun4v_con_putchar
+
+ /* %o0: buffer real address
+ * %o1: buffer size
+ * %o2: pointer to unsigned long bytes_read
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_con_read
+ .type sun4v_con_read,#function
+sun4v_con_read:
+ mov %o2, %o4
+ mov HV_FAST_CONS_READ, %o5
+ ta HV_FAST_TRAP
+ brnz %o0, 1f
+ cmp %o1, -1 /* break */
+ be,a,pn %icc, 1f
+ mov %o1, %o0
+ cmp %o1, -2 /* hup */
+ be,a,pn %icc, 1f
+ mov %o1, %o0
+ stx %o1, [%o4]
+1: retl
+ nop
+ .size sun4v_con_read, .-sun4v_con_read
+
+ /* %o0: buffer real address
+ * %o1: buffer size
+ * %o2: pointer to unsigned long bytes_written
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_con_write
+ .type sun4v_con_write,#function
+sun4v_con_write:
+ mov %o2, %o4
+ mov HV_FAST_CONS_WRITE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_con_write, .-sun4v_con_write
+
+ /* %o0: soft state
+ * %o1: address of description string
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mach_set_soft_state
+ .type sun4v_mach_set_soft_state,#function
+sun4v_mach_set_soft_state:
+ mov HV_FAST_MACH_SET_SOFT_STATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_mach_set_soft_state, .-sun4v_mach_set_soft_state
+
+ /* %o0: exit code
+ *
+ * Does not return.
+ */
+ .globl sun4v_mach_exit
+ .type sun4v_mach_exit,#function
+sun4v_mach_exit:
+ mov HV_FAST_MACH_EXIT, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_mach_exit, .-sun4v_mach_exit
+
+ /* %o0: buffer real address
+ * %o1: buffer length
+ * %o2: pointer to unsigned long real_buf_len
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mach_desc
+ .type sun4v_mach_desc,#function
+sun4v_mach_desc:
+ mov %o2, %o4
+ mov HV_FAST_MACH_DESC, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_mach_desc, .-sun4v_mach_desc
+
+ /* %o0: new timeout in milliseconds
+ * %o1: pointer to unsigned long orig_timeout
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_mach_set_watchdog
+ .type sun4v_mach_set_watchdog,#function
+sun4v_mach_set_watchdog:
+ mov %o1, %o4
+ mov HV_FAST_MACH_SET_WATCHDOG, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_mach_set_watchdog, .-sun4v_mach_set_watchdog
+
+ /* No inputs and does not return. */
+ .globl sun4v_mach_sir
+ .type sun4v_mach_sir,#function
+sun4v_mach_sir:
+ mov %o1, %o4
+ mov HV_FAST_MACH_SIR, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_mach_sir, .-sun4v_mach_sir
+
+ /* %o0: channel
+ * %o1: ra
+ * %o2: num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_tx_qconf
+ .type sun4v_ldc_tx_qconf,#function
+sun4v_ldc_tx_qconf:
+ mov HV_FAST_LDC_TX_QCONF, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_tx_qconf, .-sun4v_ldc_tx_qconf
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long ra
+ * %o2: pointer to unsigned long num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_tx_qinfo
+ .type sun4v_ldc_tx_qinfo,#function
+sun4v_ldc_tx_qinfo:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov HV_FAST_LDC_TX_QINFO, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ .size sun4v_ldc_tx_qinfo, .-sun4v_ldc_tx_qinfo
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long head_off
+ * %o2: pointer to unsigned long tail_off
+ * %o2: pointer to unsigned long chan_state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_tx_get_state
+ .type sun4v_ldc_tx_get_state,#function
+sun4v_ldc_tx_get_state:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov %o3, %g3
+ mov HV_FAST_LDC_TX_GET_STATE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ stx %o3, [%g3]
+ retl
+ nop
+ .size sun4v_ldc_tx_get_state, .-sun4v_ldc_tx_get_state
+
+ /* %o0: channel
+ * %o1: tail_off
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_tx_set_qtail
+ .type sun4v_ldc_tx_set_qtail,#function
+sun4v_ldc_tx_set_qtail:
+ mov HV_FAST_LDC_TX_SET_QTAIL, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_tx_set_qtail, .-sun4v_ldc_tx_set_qtail
+
+ /* %o0: channel
+ * %o1: ra
+ * %o2: num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_rx_qconf
+ .type sun4v_ldc_rx_qconf,#function
+sun4v_ldc_rx_qconf:
+ mov HV_FAST_LDC_RX_QCONF, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_rx_qconf, .-sun4v_ldc_rx_qconf
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long ra
+ * %o2: pointer to unsigned long num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_rx_qinfo
+ .type sun4v_ldc_rx_qinfo,#function
+sun4v_ldc_rx_qinfo:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov HV_FAST_LDC_RX_QINFO, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ .size sun4v_ldc_rx_qinfo, .-sun4v_ldc_rx_qinfo
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long head_off
+ * %o2: pointer to unsigned long tail_off
+ * %o2: pointer to unsigned long chan_state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_rx_get_state
+ .type sun4v_ldc_rx_get_state,#function
+sun4v_ldc_rx_get_state:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov %o3, %g3
+ mov HV_FAST_LDC_RX_GET_STATE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ stx %o3, [%g3]
+ retl
+ nop
+ .size sun4v_ldc_rx_get_state, .-sun4v_ldc_rx_get_state
+
+ /* %o0: channel
+ * %o1: head_off
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_rx_set_qhead
+ .type sun4v_ldc_rx_set_qhead,#function
+sun4v_ldc_rx_set_qhead:
+ mov HV_FAST_LDC_RX_SET_QHEAD, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_rx_set_qhead, .-sun4v_ldc_rx_set_qhead
+
+ /* %o0: channel
+ * %o1: ra
+ * %o2: num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_set_map_table
+ .type sun4v_ldc_set_map_table,#function
+sun4v_ldc_set_map_table:
+ mov HV_FAST_LDC_SET_MAP_TABLE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_set_map_table, .-sun4v_ldc_set_map_table
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long ra
+ * %o2: pointer to unsigned long num_entries
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_get_map_table
+ .type sun4v_ldc_get_map_table,#function
+sun4v_ldc_get_map_table:
+ mov %o1, %g1
+ mov %o2, %g2
+ mov HV_FAST_LDC_GET_MAP_TABLE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ .size sun4v_ldc_get_map_table, .-sun4v_ldc_get_map_table
+
+ /* %o0: channel
+ * %o1: dir_code
+ * %o2: tgt_raddr
+ * %o3: lcl_raddr
+ * %o4: len
+ * %o5: pointer to unsigned long actual_len
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_copy
+ .type sun4v_ldc_copy,#function
+sun4v_ldc_copy:
+ mov %o5, %g1
+ mov HV_FAST_LDC_COPY, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_ldc_copy, .-sun4v_ldc_copy
+
+ /* %o0: channel
+ * %o1: cookie
+ * %o2: pointer to unsigned long ra
+ * %o3: pointer to unsigned long perm
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_mapin
+ .type sun4v_ldc_mapin,#function
+sun4v_ldc_mapin:
+ mov %o2, %g1
+ mov %o3, %g2
+ mov HV_FAST_LDC_MAPIN, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ .size sun4v_ldc_mapin, .-sun4v_ldc_mapin
+
+ /* %o0: ra
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_unmap
+ .type sun4v_ldc_unmap,#function
+sun4v_ldc_unmap:
+ mov HV_FAST_LDC_UNMAP, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_unmap, .-sun4v_ldc_unmap
+
+ /* %o0: channel
+ * %o1: cookie
+ * %o2: mte_cookie
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ldc_revoke
+ .type sun4v_ldc_revoke,#function
+sun4v_ldc_revoke:
+ mov HV_FAST_LDC_REVOKE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ldc_revoke, .-sun4v_ldc_revoke
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long cookie
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_get_cookie
+ .type sun4v_vintr_get_cookie,#function
+sun4v_vintr_get_cookie:
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_COOKIE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_vintr_get_cookie, .-sun4v_vintr_get_cookie
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: cookie
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_set_cookie
+ .type sun4v_vintr_set_cookie,#function
+sun4v_vintr_set_cookie:
+ mov HV_FAST_VINTR_SET_COOKIE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_vintr_set_cookie, .-sun4v_vintr_set_cookie
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long valid_state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_get_valid
+ .type sun4v_vintr_get_valid,#function
+sun4v_vintr_get_valid:
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_VALID, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_vintr_get_valid, .-sun4v_vintr_get_valid
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: valid_state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_set_valid
+ .type sun4v_vintr_set_valid,#function
+sun4v_vintr_set_valid:
+ mov HV_FAST_VINTR_SET_VALID, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_vintr_set_valid, .-sun4v_vintr_set_valid
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_get_state
+ .type sun4v_vintr_get_state,#function
+sun4v_vintr_get_state:
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_STATE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_vintr_get_state, .-sun4v_vintr_get_state
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: state
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_set_state
+ .type sun4v_vintr_set_state,#function
+sun4v_vintr_set_state:
+ mov HV_FAST_VINTR_SET_STATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_vintr_set_state, .-sun4v_vintr_set_state
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long cpuid
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_get_target
+ .type sun4v_vintr_get_target,#function
+sun4v_vintr_get_target:
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_TARGET, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ .size sun4v_vintr_get_target, .-sun4v_vintr_get_target
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: cpuid
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_vintr_set_target
+ .type sun4v_vintr_set_target,#function
+sun4v_vintr_set_target:
+ mov HV_FAST_VINTR_SET_TARGET, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_vintr_set_target, .-sun4v_vintr_set_target
+
+ /* %o0: NCS sub-function
+ * %o1: sub-function arg real-address
+ * %o2: sub-function arg size
+ *
+ * returns %o0: status
+ */
+ .globl sun4v_ncs_request
+ .type sun4v_ncs_request,#function
+sun4v_ncs_request:
+ mov HV_FAST_NCS_REQUEST, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_ncs_request, .-sun4v_ncs_request
+
+ .globl sun4v_svc_send
+ .type sun4v_svc_send,#function
+sun4v_svc_send:
+ save %sp, -192, %sp
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov HV_FAST_SVC_SEND, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%i3]
+ ret
+ restore
+ .size sun4v_svc_send, .-sun4v_svc_send
+
+ .globl sun4v_svc_recv
+ .type sun4v_svc_recv,#function
+sun4v_svc_recv:
+ save %sp, -192, %sp
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov HV_FAST_SVC_RECV, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%i3]
+ ret
+ restore
+ .size sun4v_svc_recv, .-sun4v_svc_recv
+
+ .globl sun4v_svc_getstatus
+ .type sun4v_svc_getstatus,#function
+sun4v_svc_getstatus:
+ mov HV_FAST_SVC_GETSTATUS, %o5
+ mov %o1, %o4
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_svc_getstatus, .-sun4v_svc_getstatus
+
+ .globl sun4v_svc_setstatus
+ .type sun4v_svc_setstatus,#function
+sun4v_svc_setstatus:
+ mov HV_FAST_SVC_SETSTATUS, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_svc_setstatus, .-sun4v_svc_setstatus
+
+ .globl sun4v_svc_clrstatus
+ .type sun4v_svc_clrstatus,#function
+sun4v_svc_clrstatus:
+ mov HV_FAST_SVC_CLRSTATUS, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_svc_clrstatus, .-sun4v_svc_clrstatus
+
+ .globl sun4v_mmustat_conf
+ .type sun4v_mmustat_conf,#function
+sun4v_mmustat_conf:
+ mov %o1, %o4
+ mov HV_FAST_MMUSTAT_CONF, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_mmustat_conf, .-sun4v_mmustat_conf
+
+ .globl sun4v_mmustat_info
+ .type sun4v_mmustat_info,#function
+sun4v_mmustat_info:
+ mov %o0, %o4
+ mov HV_FAST_MMUSTAT_INFO, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ .size sun4v_mmustat_info, .-sun4v_mmustat_info
+
+ .globl sun4v_mmu_demap_all
+ .type sun4v_mmu_demap_all,#function
+sun4v_mmu_demap_all:
+ clr %o0
+ clr %o1
+ mov HV_MMU_ALL, %o2
+ mov HV_FAST_MMU_DEMAP_ALL, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ .size sun4v_mmu_demap_all, .-sun4v_mmu_demap_all
diff --git a/arch/sparc64/kernel/ivec.S b/arch/sparc64/kernel/ivec.S
new file mode 100644
index 0000000..d29f92e
--- /dev/null
+++ b/arch/sparc64/kernel/ivec.S
@@ -0,0 +1,51 @@
+ /* The registers for cross calls will be:
+ *
+ * DATA 0: [low 32-bits] Address of function to call, jmp to this
+ * [high 32-bits] MMU Context Argument 0, place in %g5
+ * DATA 1: Address Argument 1, place in %g1
+ * DATA 2: Address Argument 2, place in %g7
+ *
+ * With this method we can do most of the cross-call tlb/cache
+ * flushing very quickly.
+ */
+ .align 32
+ .globl do_ivec
+ .type do_ivec,#function
+do_ivec:
+ mov 0x40, %g3
+ ldxa [%g3 + %g0] ASI_INTR_R, %g3
+ sethi %hi(KERNBASE), %g4
+ cmp %g3, %g4
+ bgeu,pn %xcc, do_ivec_xcall
+ srlx %g3, 32, %g5
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
+ membar #Sync
+
+ sethi %hi(ivector_table_pa), %g2
+ ldx [%g2 + %lo(ivector_table_pa)], %g2
+ sllx %g3, 4, %g3
+ add %g2, %g3, %g3
+
+ TRAP_LOAD_IRQ_WORK_PA(%g6, %g1)
+
+ ldx [%g6], %g5
+ stxa %g5, [%g3] ASI_PHYS_USE_EC
+ stx %g3, [%g6]
+ wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
+ retry
+do_ivec_xcall:
+ mov 0x50, %g1
+ ldxa [%g1 + %g0] ASI_INTR_R, %g1
+ srl %g3, 0, %g3
+
+ mov 0x60, %g7
+ ldxa [%g7 + %g0] ASI_INTR_R, %g7
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
+ membar #Sync
+ ba,pt %xcc, 1f
+ nop
+
+ .align 32
+1: jmpl %g3, %g0
+ nop
+ .size do_ivec,.-do_ivec
diff --git a/arch/sparc64/kernel/kgdb.c b/arch/sparc64/kernel/kgdb.c
new file mode 100644
index 0000000..fefbe6d
--- /dev/null
+++ b/arch/sparc64/kernel/kgdb.c
@@ -0,0 +1,186 @@
+/* kgdb.c: KGDB support for 64-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kgdb.h>
+#include <linux/kdebug.h>
+
+#include <asm/kdebug.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ struct reg_window *win;
+ int i;
+
+ gdb_regs[GDB_G0] = 0;
+ for (i = 0; i < 15; i++)
+ gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
+
+ win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_L0 + i] = win->locals[i];
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_I0 + i] = win->ins[i];
+
+ for (i = GDB_F0; i <= GDB_F62; i++)
+ gdb_regs[i] = 0;
+
+ gdb_regs[GDB_PC] = regs->tpc;
+ gdb_regs[GDB_NPC] = regs->tnpc;
+ gdb_regs[GDB_STATE] = regs->tstate;
+ gdb_regs[GDB_FSR] = 0;
+ gdb_regs[GDB_FPRS] = 0;
+ gdb_regs[GDB_Y] = regs->y;
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+ struct thread_info *t = task_thread_info(p);
+ extern unsigned int switch_to_pc;
+ extern unsigned int ret_from_syscall;
+ struct reg_window *win;
+ unsigned long pc, cwp;
+ int i;
+
+ for (i = GDB_G0; i < GDB_G6; i++)
+ gdb_regs[i] = 0;
+ gdb_regs[GDB_G6] = (unsigned long) t;
+ gdb_regs[GDB_G7] = (unsigned long) p;
+ for (i = GDB_O0; i < GDB_SP; i++)
+ gdb_regs[i] = 0;
+ gdb_regs[GDB_SP] = t->ksp;
+ gdb_regs[GDB_O7] = 0;
+
+ win = (struct reg_window *) (t->ksp + STACK_BIAS);
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_L0 + i] = win->locals[i];
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_I0 + i] = win->ins[i];
+
+ for (i = GDB_F0; i <= GDB_F62; i++)
+ gdb_regs[i] = 0;
+
+ if (t->new_child)
+ pc = (unsigned long) &ret_from_syscall;
+ else
+ pc = (unsigned long) &switch_to_pc;
+
+ gdb_regs[GDB_PC] = pc;
+ gdb_regs[GDB_NPC] = pc + 4;
+
+ cwp = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP];
+
+ gdb_regs[GDB_STATE] = (TSTATE_PRIV | TSTATE_IE | cwp);
+ gdb_regs[GDB_FSR] = 0;
+ gdb_regs[GDB_FPRS] = 0;
+ gdb_regs[GDB_Y] = 0;
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ struct reg_window *win;
+ int i;
+
+ for (i = 0; i < 15; i++)
+ regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
+
+ /* If the TSTATE register is changing, we have to preserve
+ * the CWP field, otherwise window save/restore explodes.
+ */
+ if (regs->tstate != gdb_regs[GDB_STATE]) {
+ unsigned long cwp = regs->tstate & TSTATE_CWP;
+
+ regs->tstate = (gdb_regs[GDB_STATE] & ~TSTATE_CWP) | cwp;
+ }
+
+ regs->tpc = gdb_regs[GDB_PC];
+ regs->tnpc = gdb_regs[GDB_NPC];
+ regs->y = gdb_regs[GDB_Y];
+
+ win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
+ for (i = 0; i < 8; i++)
+ win->locals[i] = gdb_regs[GDB_L0 + i];
+ for (i = 0; i < 8; i++)
+ win->ins[i] = gdb_regs[GDB_I0 + i];
+}
+
+#ifdef CONFIG_SMP
+void smp_kgdb_capture_client(struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate"
+ : "=r" (flags)
+ : "i" (PSTATE_IE));
+
+ flushw_all();
+
+ if (atomic_read(&kgdb_active) != -1)
+ kgdb_nmicallback(raw_smp_processor_id(), regs);
+
+ __asm__ __volatile__("wrpr %0, 0, %%pstate"
+ : : "r" (flags));
+}
+#endif
+
+int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
+ char *remcomInBuffer, char *remcomOutBuffer,
+ struct pt_regs *linux_regs)
+{
+ unsigned long addr;
+ char *ptr;
+
+ switch (remcomInBuffer[0]) {
+ case 'c':
+ /* try to read optional parameter, pc unchanged if no parm */
+ ptr = &remcomInBuffer[1];
+ if (kgdb_hex2long(&ptr, &addr)) {
+ linux_regs->tpc = addr;
+ linux_regs->tnpc = addr + 4;
+ }
+ /* fallthru */
+
+ case 'D':
+ case 'k':
+ if (linux_regs->tpc == (unsigned long) arch_kgdb_breakpoint) {
+ linux_regs->tpc = linux_regs->tnpc;
+ linux_regs->tnpc += 4;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ if (user_mode(regs)) {
+ bad_trap(regs, trap_level);
+ return;
+ }
+
+ flushw_all();
+
+ local_irq_save(flags);
+ kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
+ local_irq_restore(flags);
+}
+
+int kgdb_arch_init(void)
+{
+ return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+ /* Breakpoint instruction: ta 0x72 */
+ .gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x72 },
+};
diff --git a/arch/sparc64/kernel/misctrap.S b/arch/sparc64/kernel/misctrap.S
new file mode 100644
index 0000000..753b4f0
--- /dev/null
+++ b/arch/sparc64/kernel/misctrap.S
@@ -0,0 +1,97 @@
+#ifdef CONFIG_KGDB
+ .globl arch_kgdb_breakpoint
+ .type arch_kgdb_breakpoint,#function
+arch_kgdb_breakpoint:
+ ta 0x72
+ retl
+ nop
+ .size arch_kgdb_breakpoint,.-arch_kgdb_breakpoint
+#endif
+
+ .type __do_privact,#function
+__do_privact:
+ mov TLB_SFSR, %g3
+ stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit
+ membar #Sync
+ sethi %hi(109f), %g7
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ call do_privact
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size __do_privact,.-__do_privact
+
+ .type do_mna,#function
+do_mna:
+ rdpr %tl, %g3
+ cmp %g3, 1
+
+ /* Setup %g4/%g5 now as they are used in the
+ * winfixup code.
+ */
+ mov TLB_SFSR, %g3
+ mov DMMU_SFAR, %g4
+ ldxa [%g4] ASI_DMMU, %g4
+ ldxa [%g3] ASI_DMMU, %g5
+ stxa %g0, [%g3] ASI_DMMU ! Clear FaultValid bit
+ membar #Sync
+ bgu,pn %icc, winfix_mna
+ rdpr %tpc, %g3
+
+1: sethi %hi(109f), %g7
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call mem_address_unaligned
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size do_mna,.-do_mna
+
+ .type do_lddfmna,#function
+do_lddfmna:
+ sethi %hi(109f), %g7
+ mov TLB_SFSR, %g4
+ ldxa [%g4] ASI_DMMU, %g5
+ stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit
+ membar #Sync
+ mov DMMU_SFAR, %g4
+ ldxa [%g4] ASI_DMMU, %g4
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call handle_lddfmna
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size do_lddfmna,.-do_lddfmna
+
+ .type do_stdfmna,#function
+do_stdfmna:
+ sethi %hi(109f), %g7
+ mov TLB_SFSR, %g4
+ ldxa [%g4] ASI_DMMU, %g5
+ stxa %g0, [%g4] ASI_DMMU ! Clear FaultValid bit
+ membar #Sync
+ mov DMMU_SFAR, %g4
+ ldxa [%g4] ASI_DMMU, %g4
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call handle_stdfmna
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size do_stdfmna,.-do_stdfmna
+
+ .type breakpoint_trap,#function
+breakpoint_trap:
+ call sparc_breakpoint
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size breakpoint_trap,.-breakpoint_trap
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 409dd71..3aba476 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -38,7 +38,6 @@
#include <asm/pgtable.h>
#include <asm/oplib.h>
#include <asm/uaccess.h>
-#include <asm/timer.h>
#include <asm/starfire.h>
#include <asm/tlb.h>
#include <asm/sections.h>
@@ -910,6 +909,9 @@
extern unsigned long xcall_report_regs;
extern unsigned long xcall_receive_signal;
extern unsigned long xcall_new_mmu_context_version;
+#ifdef CONFIG_KGDB
+extern unsigned long xcall_kgdb_capture;
+#endif
#ifdef DCACHE_ALIASING_POSSIBLE
extern unsigned long xcall_flush_dcache_page_cheetah;
@@ -1079,6 +1081,13 @@
smp_cross_call(&xcall_new_mmu_context_version, 0, 0, 0);
}
+#ifdef CONFIG_KGDB
+void kgdb_roundup_cpus(unsigned long flags)
+{
+ smp_cross_call(&xcall_kgdb_capture, 0, 0, 0);
+}
+#endif
+
void smp_report_regs(void)
{
smp_cross_call(&xcall_report_regs, 0, 0, 0);
diff --git a/arch/sparc64/kernel/spiterrs.S b/arch/sparc64/kernel/spiterrs.S
new file mode 100644
index 0000000..ef902c6
--- /dev/null
+++ b/arch/sparc64/kernel/spiterrs.S
@@ -0,0 +1,245 @@
+ /* We need to carefully read the error status, ACK the errors,
+ * prevent recursive traps, and pass the information on to C
+ * code for logging.
+ *
+ * We pass the AFAR in as-is, and we encode the status
+ * information as described in asm-sparc64/sfafsr.h
+ */
+ .type __spitfire_access_error,#function
+__spitfire_access_error:
+ /* Disable ESTATE error reporting so that we do not take
+ * recursive traps and RED state the processor.
+ */
+ stxa %g0, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ mov UDBE_UE, %g1
+ ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR
+
+ /* __spitfire_cee_trap branches here with AFSR in %g4 and
+ * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the ESTATE
+ * Error Enable register.
+ */
+__spitfire_cee_trap_continue:
+ ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR
+
+ rdpr %tt, %g3
+ and %g3, 0x1ff, %g3 ! Paranoia
+ sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3
+ or %g4, %g3, %g4
+ rdpr %tl, %g3
+ cmp %g3, 1
+ mov 1, %g3
+ bleu %xcc, 1f
+ sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3
+
+ or %g4, %g3, %g4
+
+ /* Read in the UDB error register state, clearing the sticky
+ * error bits as-needed. We only clear them if the UE bit is
+ * set. Likewise, __spitfire_cee_trap below will only do so
+ * if the CE bit is set.
+ *
+ * NOTE: UltraSparc-I/II have high and low UDB error
+ * registers, corresponding to the two UDB units
+ * present on those chips. UltraSparc-IIi only
+ * has a single UDB, called "SDB" in the manual.
+ * For IIi the upper UDB register always reads
+ * as zero so for our purposes things will just
+ * work with the checks below.
+ */
+1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3
+ and %g3, 0x3ff, %g7 ! Paranoia
+ sllx %g7, SFSTAT_UDBH_SHIFT, %g7
+ or %g4, %g7, %g4
+ andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE
+ be,pn %xcc, 1f
+ nop
+ stxa %g3, [%g0] ASI_UDB_ERROR_W
+ membar #Sync
+
+1: mov 0x18, %g3
+ ldxa [%g3] ASI_UDBL_ERROR_R, %g3
+ and %g3, 0x3ff, %g7 ! Paranoia
+ sllx %g7, SFSTAT_UDBL_SHIFT, %g7
+ or %g4, %g7, %g4
+ andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE
+ be,pn %xcc, 1f
+ nop
+ mov 0x18, %g7
+ stxa %g3, [%g7] ASI_UDB_ERROR_W
+ membar #Sync
+
+1: /* Ok, now that we've latched the error state, clear the
+ * sticky bits in the AFSR.
+ */
+ stxa %g4, [%g0] ASI_AFSR
+ membar #Sync
+
+ rdpr %tl, %g2
+ cmp %g2, 1
+ rdpr %pil, %g2
+ bleu,pt %xcc, 1f
+ wrpr %g0, 15, %pil
+
+ ba,pt %xcc, etraptl1
+ rd %pc, %g7
+
+ ba,pt %xcc, 2f
+ nop
+
+1: ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+
+2:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov %l4, %o1
+ mov %l5, %o2
+ call spitfire_access_error
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size __spitfire_access_error,.-__spitfire_access_error
+
+ /* This is the trap handler entry point for ECC correctable
+ * errors. They are corrected, but we listen for the trap so
+ * that the event can be logged.
+ *
+ * Disrupting errors are either:
+ * 1) single-bit ECC errors during UDB reads to system
+ * memory
+ * 2) data parity errors during write-back events
+ *
+ * As far as I can make out from the manual, the CEE trap is
+ * only for correctable errors during memory read accesses by
+ * the front-end of the processor.
+ *
+ * The code below is only for trap level 1 CEE events, as it
+ * is the only situation where we can safely record and log.
+ * For trap level >1 we just clear the CE bit in the AFSR and
+ * return.
+ *
+ * This is just like __spiftire_access_error above, but it
+ * specifically handles correctable errors. If an
+ * uncorrectable error is indicated in the AFSR we will branch
+ * directly above to __spitfire_access_error to handle it
+ * instead. Uncorrectable therefore takes priority over
+ * correctable, and the error logging C code will notice this
+ * case by inspecting the trap type.
+ */
+ .type __spitfire_cee_trap,#function
+__spitfire_cee_trap:
+ ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR
+ mov 1, %g3
+ sllx %g3, SFAFSR_UE_SHIFT, %g3
+ andcc %g4, %g3, %g0 ! Check for UE
+ bne,pn %xcc, __spitfire_access_error
+ nop
+
+ /* Ok, in this case we only have a correctable error.
+ * Indicate we only wish to capture that state in register
+ * %g1, and we only disable CE error reporting unlike UE
+ * handling which disables all errors.
+ */
+ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3
+ andn %g3, ESTATE_ERR_CE, %g3
+ stxa %g3, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */
+ ba,pt %xcc, __spitfire_cee_trap_continue
+ mov UDBE_CE, %g1
+ .size __spitfire_cee_trap,.-__spitfire_cee_trap
+
+ .type __spitfire_data_access_exception_tl1,#function
+__spitfire_data_access_exception_tl1:
+ rdpr %pstate, %g4
+ wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
+ mov TLB_SFSR, %g3
+ mov DMMU_SFAR, %g5
+ ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR
+ ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
+ stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit
+ membar #Sync
+ rdpr %tt, %g3
+ cmp %g3, 0x80 ! first win spill/fill trap
+ blu,pn %xcc, 1f
+ cmp %g3, 0xff ! last win spill/fill trap
+ bgu,pn %xcc, 1f
+ nop
+ ba,pt %xcc, winfix_dax
+ rdpr %tpc, %g3
+1: sethi %hi(109f), %g7
+ ba,pt %xcc, etraptl1
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call spitfire_data_access_exception_tl1
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size __spitfire_data_access_exception_tl1,.-__spitfire_data_access_exception_tl1
+
+ .type __spitfire_data_access_exception,#function
+__spitfire_data_access_exception:
+ rdpr %pstate, %g4
+ wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
+ mov TLB_SFSR, %g3
+ mov DMMU_SFAR, %g5
+ ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR
+ ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR
+ stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit
+ membar #Sync
+ sethi %hi(109f), %g7
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call spitfire_data_access_exception
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size __spitfire_data_access_exception,.-__spitfire_data_access_exception
+
+ .type __spitfire_insn_access_exception_tl1,#function
+__spitfire_insn_access_exception_tl1:
+ rdpr %pstate, %g4
+ wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
+ mov TLB_SFSR, %g3
+ ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR
+ rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC
+ stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit
+ membar #Sync
+ sethi %hi(109f), %g7
+ ba,pt %xcc, etraptl1
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call spitfire_insn_access_exception_tl1
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size __spitfire_insn_access_exception_tl1,.-__spitfire_insn_access_exception_tl1
+
+ .type __spitfire_insn_access_exception,#function
+__spitfire_insn_access_exception:
+ rdpr %pstate, %g4
+ wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate
+ mov TLB_SFSR, %g3
+ ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR
+ rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC
+ stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit
+ membar #Sync
+ sethi %hi(109f), %g7
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ mov %l4, %o1
+ mov %l5, %o2
+ call spitfire_insn_access_exception
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size __spitfire_insn_access_exception,.-__spitfire_insn_access_exception
diff --git a/arch/sparc64/kernel/syscalls.S b/arch/sparc64/kernel/syscalls.S
new file mode 100644
index 0000000..db19ed6
--- /dev/null
+++ b/arch/sparc64/kernel/syscalls.S
@@ -0,0 +1,279 @@
+ /* SunOS's execv() call only specifies the argv argument, the
+ * environment settings are the same as the calling processes.
+ */
+sys_execve:
+ sethi %hi(sparc_execve), %g1
+ ba,pt %xcc, execve_merge
+ or %g1, %lo(sparc_execve), %g1
+
+#ifdef CONFIG_COMPAT
+sunos_execv:
+ stx %g0, [%sp + PTREGS_OFF + PT_V9_I2]
+sys32_execve:
+ sethi %hi(sparc32_execve), %g1
+ or %g1, %lo(sparc32_execve), %g1
+#endif
+
+execve_merge:
+ flushw
+ jmpl %g1, %g0
+ add %sp, PTREGS_OFF, %o0
+
+ .align 32
+sys_pipe:
+ ba,pt %xcc, sparc_pipe
+ add %sp, PTREGS_OFF, %o0
+sys_nis_syscall:
+ ba,pt %xcc, c_sys_nis_syscall
+ add %sp, PTREGS_OFF, %o0
+sys_memory_ordering:
+ ba,pt %xcc, sparc_memory_ordering
+ add %sp, PTREGS_OFF, %o1
+sys_sigaltstack:
+ ba,pt %xcc, do_sigaltstack
+ add %i6, STACK_BIAS, %o2
+#ifdef CONFIG_COMPAT
+sys32_sigstack:
+ ba,pt %xcc, do_sys32_sigstack
+ mov %i6, %o2
+sys32_sigaltstack:
+ ba,pt %xcc, do_sys32_sigaltstack
+ mov %i6, %o2
+#endif
+ .align 32
+#ifdef CONFIG_COMPAT
+sys32_sigreturn:
+ add %sp, PTREGS_OFF, %o0
+ call do_sigreturn32
+ add %o7, 1f-.-4, %o7
+ nop
+#endif
+sys_rt_sigreturn:
+ add %sp, PTREGS_OFF, %o0
+ call do_rt_sigreturn
+ add %o7, 1f-.-4, %o7
+ nop
+#ifdef CONFIG_COMPAT
+sys32_rt_sigreturn:
+ add %sp, PTREGS_OFF, %o0
+ call do_rt_sigreturn32
+ add %o7, 1f-.-4, %o7
+ nop
+#endif
+ .align 32
+1: ldx [%g6 + TI_FLAGS], %l5
+ andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
+ be,pt %icc, rtrap
+ nop
+ add %sp, PTREGS_OFF, %o0
+ call syscall_trace
+ mov 1, %o1
+ ba,pt %xcc, rtrap
+ nop
+
+ /* This is how fork() was meant to be done, 8 instruction entry.
+ *
+ * I questioned the following code briefly, let me clear things
+ * up so you must not reason on it like I did.
+ *
+ * Know the fork_kpsr etc. we use in the sparc32 port? We don't
+ * need it here because the only piece of window state we copy to
+ * the child is the CWP register. Even if the parent sleeps,
+ * we are safe because we stuck it into pt_regs of the parent
+ * so it will not change.
+ *
+ * XXX This raises the question, whether we can do the same on
+ * XXX sparc32 to get rid of fork_kpsr _and_ fork_kwim. The
+ * XXX answer is yes. We stick fork_kpsr in UREG_G0 and
+ * XXX fork_kwim in UREG_G1 (global registers are considered
+ * XXX volatile across a system call in the sparc ABI I think
+ * XXX if it isn't we can use regs->y instead, anyone who depends
+ * XXX upon the Y register being preserved across a fork deserves
+ * XXX to lose).
+ *
+ * In fact we should take advantage of that fact for other things
+ * during system calls...
+ */
+ .align 32
+sys_vfork: /* Under Linux, vfork and fork are just special cases of clone. */
+ sethi %hi(0x4000 | 0x0100 | SIGCHLD), %o0
+ or %o0, %lo(0x4000 | 0x0100 | SIGCHLD), %o0
+ ba,pt %xcc, sys_clone
+sys_fork:
+ clr %o1
+ mov SIGCHLD, %o0
+sys_clone:
+ flushw
+ movrz %o1, %fp, %o1
+ mov 0, %o3
+ ba,pt %xcc, sparc_do_fork
+ add %sp, PTREGS_OFF, %o2
+
+ .globl ret_from_syscall
+ret_from_syscall:
+ /* Clear current_thread_info()->new_child, and
+ * check performance counter stuff too.
+ */
+ stb %g0, [%g6 + TI_NEW_CHILD]
+ ldx [%g6 + TI_FLAGS], %l0
+ call schedule_tail
+ mov %g7, %o0
+ andcc %l0, _TIF_PERFCTR, %g0
+ be,pt %icc, 1f
+ nop
+ ldx [%g6 + TI_PCR], %o7
+ wr %g0, %o7, %pcr
+
+ /* Blackbird errata workaround. See commentary in
+ * smp.c:smp_percpu_timer_interrupt() for more
+ * information.
+ */
+ ba,pt %xcc, 99f
+ nop
+
+ .align 64
+99: wr %g0, %g0, %pic
+ rd %pic, %g0
+
+1: ba,pt %xcc, ret_sys_call
+ ldx [%sp + PTREGS_OFF + PT_V9_I0], %o0
+
+ .globl sparc_exit
+ .type sparc_exit,#function
+sparc_exit:
+ rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IE, %pstate
+ rdpr %otherwin, %g1
+ rdpr %cansave, %g3
+ add %g3, %g1, %g3
+ wrpr %g3, 0x0, %cansave
+ wrpr %g0, 0x0, %otherwin
+ wrpr %g2, 0x0, %pstate
+ ba,pt %xcc, sys_exit
+ stb %g0, [%g6 + TI_WSAVED]
+ .size sparc_exit,.-sparc_exit
+
+linux_sparc_ni_syscall:
+ sethi %hi(sys_ni_syscall), %l7
+ ba,pt %xcc, 4f
+ or %l7, %lo(sys_ni_syscall), %l7
+
+linux_syscall_trace32:
+ add %sp, PTREGS_OFF, %o0
+ call syscall_trace
+ clr %o1
+ srl %i0, 0, %o0
+ srl %i4, 0, %o4
+ srl %i1, 0, %o1
+ srl %i2, 0, %o2
+ ba,pt %xcc, 2f
+ srl %i3, 0, %o3
+
+linux_syscall_trace:
+ add %sp, PTREGS_OFF, %o0
+ call syscall_trace
+ clr %o1
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov %i3, %o3
+ b,pt %xcc, 2f
+ mov %i4, %o4
+
+
+ /* Linux 32-bit system calls enter here... */
+ .align 32
+ .globl linux_sparc_syscall32
+linux_sparc_syscall32:
+ /* Direct access to user regs, much faster. */
+ cmp %g1, NR_SYSCALLS ! IEU1 Group
+ bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
+ srl %i0, 0, %o0 ! IEU0
+ sll %g1, 2, %l4 ! IEU0 Group
+ srl %i4, 0, %o4 ! IEU1
+ lduw [%l7 + %l4], %l7 ! Load
+ srl %i1, 0, %o1 ! IEU0 Group
+ ldx [%g6 + TI_FLAGS], %l0 ! Load
+
+ srl %i5, 0, %o5 ! IEU1
+ srl %i2, 0, %o2 ! IEU0 Group
+ andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
+ bne,pn %icc, linux_syscall_trace32 ! CTI
+ mov %i0, %l5 ! IEU1
+ call %l7 ! CTI Group brk forced
+ srl %i3, 0, %o3 ! IEU0
+ ba,a,pt %xcc, 3f
+
+ /* Linux native system calls enter here... */
+ .align 32
+ .globl linux_sparc_syscall
+linux_sparc_syscall:
+ /* Direct access to user regs, much faster. */
+ cmp %g1, NR_SYSCALLS ! IEU1 Group
+ bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
+ mov %i0, %o0 ! IEU0
+ sll %g1, 2, %l4 ! IEU0 Group
+ mov %i1, %o1 ! IEU1
+ lduw [%l7 + %l4], %l7 ! Load
+4: mov %i2, %o2 ! IEU0 Group
+ ldx [%g6 + TI_FLAGS], %l0 ! Load
+
+ mov %i3, %o3 ! IEU1
+ mov %i4, %o4 ! IEU0 Group
+ andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
+ bne,pn %icc, linux_syscall_trace ! CTI Group
+ mov %i0, %l5 ! IEU0
+2: call %l7 ! CTI Group brk forced
+ mov %i5, %o5 ! IEU0
+ nop
+
+3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
+ret_sys_call:
+ ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
+ ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
+ sra %o0, 0, %o0
+ mov %ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
+ sllx %g2, 32, %g2
+
+ /* Check if force_successful_syscall_return()
+ * was invoked.
+ */
+ ldub [%g6 + TI_SYS_NOERROR], %l2
+ brnz,a,pn %l2, 80f
+ stb %g0, [%g6 + TI_SYS_NOERROR]
+
+ cmp %o0, -ERESTART_RESTARTBLOCK
+ bgeu,pn %xcc, 1f
+ andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6
+80:
+ /* System call success, clear Carry condition code. */
+ andn %g3, %g2, %g3
+ stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
+ bne,pn %icc, linux_syscall_trace2
+ add %l1, 0x4, %l2 ! npc = npc+4
+ stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
+ ba,pt %xcc, rtrap
+ stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
+
+1:
+ /* System call failure, set Carry condition code.
+ * Also, get abs(errno) to return to the process.
+ */
+ andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6
+ sub %g0, %o0, %o0
+ or %g3, %g2, %g3
+ stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
+ stx %g3, [%sp + PTREGS_OFF + PT_V9_TSTATE]
+ bne,pn %icc, linux_syscall_trace2
+ add %l1, 0x4, %l2 ! npc = npc+4
+ stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
+
+ b,pt %xcc, rtrap
+ stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
+linux_syscall_trace2:
+ add %sp, PTREGS_OFF, %o0
+ call syscall_trace
+ mov 1, %o1
+ stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
+ ba,pt %xcc, rtrap
+ stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
index b0de4c0..450053a 100644
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -153,7 +153,7 @@
tl0_resv169: BTRAP(0x169) BTRAP(0x16a) BTRAP(0x16b) BTRAP(0x16c)
tl0_linux64: LINUX_64BIT_SYSCALL_TRAP
tl0_gsctx: TRAP(sparc64_get_context) TRAP(sparc64_set_context)
-tl0_resv170: KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) BTRAP(0x172)
+tl0_resv170: KPROBES_TRAP(0x170) KPROBES_TRAP(0x171) KGDB_TRAP(0x172)
tl0_resv173: BTRAP(0x173) BTRAP(0x174) BTRAP(0x175) BTRAP(0x176) BTRAP(0x177)
tl0_resv178: BTRAP(0x178) BTRAP(0x179) BTRAP(0x17a) BTRAP(0x17b) BTRAP(0x17c)
tl0_resv17d: BTRAP(0x17d) BTRAP(0x17e) BTRAP(0x17f)
diff --git a/arch/sparc64/kernel/utrap.S b/arch/sparc64/kernel/utrap.S
new file mode 100644
index 0000000..b7f0f3f
--- /dev/null
+++ b/arch/sparc64/kernel/utrap.S
@@ -0,0 +1,29 @@
+ .globl utrap_trap
+ .type utrap_trap,#function
+utrap_trap: /* %g3=handler,%g4=level */
+ TRAP_LOAD_THREAD_REG(%g6, %g1)
+ ldx [%g6 + TI_UTRAPS], %g1
+ brnz,pt %g1, invoke_utrap
+ nop
+
+ ba,pt %xcc, etrap
+ rd %pc, %g7
+ mov %l4, %o1
+ call bad_trap
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+
+invoke_utrap:
+ sllx %g3, 3, %g3
+ ldx [%g1 + %g3], %g1
+ save %sp, -128, %sp
+ rdpr %tstate, %l6
+ rdpr %cwp, %l7
+ andn %l6, TSTATE_CWP, %l6
+ wrpr %l6, %l7, %tstate
+ rdpr %tpc, %l6
+ rdpr %tnpc, %l7
+ wrpr %g1, 0, %tnpc
+ done
+ .size utrap_trap,.-utrap_trap
diff --git a/arch/sparc64/lib/iomap.c b/arch/sparc64/lib/iomap.c
index ac556db..7120ebb 100644
--- a/arch/sparc64/lib/iomap.c
+++ b/arch/sparc64/lib/iomap.c
@@ -21,8 +21,8 @@
/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
- unsigned long start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t start = pci_resource_start(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 8c2b50e..4cad0b3 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -160,6 +160,7 @@
extern unsigned int sparc_ramdisk_size;
struct page *mem_map_zero __read_mostly;
+EXPORT_SYMBOL(mem_map_zero);
unsigned int sparc64_highest_unlocked_tlb_ent __read_mostly;
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index e686a67..796e005 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -676,6 +676,33 @@
wr %g0, (1 << PIL_SMP_CTX_NEW_VERSION), %set_softint
retry
+#ifdef CONFIG_KGDB
+ .globl xcall_kgdb_capture
+xcall_kgdb_capture:
+661: rdpr %pstate, %g2
+ wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
+ .section .sun4v_2insn_patch, "ax"
+ .word 661b
+ nop
+ nop
+ .previous
+
+ rdpr %pil, %g2
+ wrpr %g0, 15, %pil
+ sethi %hi(109f), %g7
+ ba,pt %xcc, etrap_irq
+109: or %g7, %lo(109b), %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ call smp_kgdb_capture_client
+ add %sp, PTREGS_OFF, %o0
+ /* Has to be a non-v9 branch due to the large distance. */
+ ba rtrap_xcall
+ ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
+#endif
+
#endif /* CONFIG_SMP */
diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
index 984f80e..6540d2c 100644
--- a/arch/um/kernel/exitcode.c
+++ b/arch/um/kernel/exitcode.c
@@ -59,7 +59,7 @@
{
struct proc_dir_entry *ent;
- ent = create_proc_entry("exitcode", 0600, &proc_root);
+ ent = create_proc_entry("exitcode", 0600, NULL);
if (ent == NULL) {
printk(KERN_WARNING "make_proc_exitcode : Failed to register "
"/proc/exitcode\n");
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index e8cb9ff..83603cf 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -364,7 +364,7 @@
if (!sysemu_supported)
return 0;
- ent = create_proc_entry("sysemu", 0600, &proc_root);
+ ent = create_proc_entry("sysemu", 0600, NULL);
if (ent == NULL)
{
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index e066e84..0d0cea2 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -4,6 +4,7 @@
*/
#include <linux/clockchips.h>
+#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/threads.h>
@@ -109,8 +110,6 @@
clockevents_register_device(&itimer_clockevent);
}
-extern void (*late_time_init)(void);
-
void __init time_init(void)
{
long long nsecs;
diff --git a/arch/v850/kernel/asm-offsets.c b/arch/v850/kernel/asm-offsets.c
index cee5c31..581e698 100644
--- a/arch/v850/kernel/asm-offsets.c
+++ b/arch/v850/kernel/asm-offsets.c
@@ -13,14 +13,11 @@
#include <linux/kernel_stat.h>
#include <linux/ptrace.h>
#include <linux/hardirq.h>
+#include <linux/kbuild.h>
+
#include <asm/irq.h>
#include <asm/errno.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
int main (void)
{
/* offsets into the task struct */
diff --git a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c
index 7165478..687e367 100644
--- a/arch/v850/kernel/rte_mb_a_pci.c
+++ b/arch/v850/kernel/rte_mb_a_pci.c
@@ -790,8 +790,8 @@
void __iomem *pci_iomap (struct pci_dev *dev, int bar, unsigned long max)
{
- unsigned long start = pci_resource_start (dev, bar);
- unsigned long len = pci_resource_len (dev, bar);
+ resource_size_t start = pci_resource_start (dev, bar);
+ resource_size_t len = pci_resource_len (dev, bar);
if (!start || len == 0)
return 0;
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index a12dbb2..c3f8809 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -25,6 +25,18 @@
select HAVE_KVM if ((X86_32 && !X86_VOYAGER && !X86_VISWS && !X86_NUMAQ) || X86_64)
select HAVE_ARCH_KGDB if !X86_VOYAGER
+config DEFCONFIG_LIST
+ string
+ depends on X86_32
+ option defconfig_list
+ default "arch/x86/configs/i386_defconfig"
+
+config DEFCONFIG_LIST
+ string
+ depends on X86_64
+ option defconfig_list
+ default "arch/x86/configs/x86_64_defconfig"
+
config GENERIC_LOCKBREAK
def_bool n
@@ -180,7 +192,7 @@
config X86_BIOS_REBOOT
bool
- depends on X86_32 && !(X86_VISWS || X86_VOYAGER)
+ depends on !X86_VISWS && !X86_VOYAGER
default y
config X86_TRAMPOLINE
@@ -537,9 +549,6 @@
Calgary anyway, pass 'iommu=calgary' on the kernel command line.
If unsure, say Y.
-config IOMMU_HELPER
- def_bool (CALGARY_IOMMU || GART_IOMMU)
-
# need this always selected by IOMMU for the VIA workaround
config SWIOTLB
bool
@@ -550,6 +559,8 @@
access 32-bits of memory can be used on systems with more than
3 GB of memory. If unsure, say Y.
+config IOMMU_HELPER
+ def_bool (CALGARY_IOMMU || GART_IOMMU || SWIOTLB)
config NR_CPUS
int "Maximum number of CPUs (2-255)"
@@ -1162,7 +1173,7 @@
config KEXEC
bool "kexec system call"
- depends on X86_64 || X86_BIOS_REBOOT
+ depends on X86_BIOS_REBOOT
help
kexec is a system call that implements the ability to shutdown your
current kernel, and to start another kernel. It is like a reboot
@@ -1505,6 +1516,10 @@
config PCI_GOANY
bool "Any"
+config PCI_GOOLPC
+ bool "OLPC"
+ depends on OLPC
+
endchoice
config PCI_BIOS
@@ -1514,12 +1529,17 @@
# x86-64 doesn't support PCI BIOS access from long mode so always go direct.
config PCI_DIRECT
def_bool y
- depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY) || X86_VISWS)
+ depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC) || X86_VISWS)
config PCI_MMCONFIG
def_bool y
depends on X86_32 && PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
+config PCI_OLPC
+ bool
+ depends on PCI && PCI_GOOLPC
+ default y
+
config PCI_DOMAINS
def_bool y
depends on PCI
@@ -1639,6 +1659,13 @@
MFGPTs have a better resolution and max interval than the
generic PIT, and are suitable for use as high-res timers.
+config OLPC
+ bool "One Laptop Per Child support"
+ default n
+ help
+ Add support for detecting the unique features of the OLPC
+ XO hardware.
+
endif # X86_32
config K8_NB
diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu
index 7ef18b0..2ad6301 100644
--- a/arch/x86/Kconfig.cpu
+++ b/arch/x86/Kconfig.cpu
@@ -278,11 +278,6 @@
endchoice
-config X86_CPU
- def_bool y
- select GENERIC_FIND_FIRST_BIT
- select GENERIC_FIND_NEXT_BIT
-
config X86_GENERIC
bool "Generic x86 support"
depends on X86_32
@@ -297,6 +292,11 @@
endif
+config X86_CPU
+ def_bool y
+ select GENERIC_FIND_FIRST_BIT
+ select GENERIC_FIND_NEXT_BIT
+
#
# Define implied options from the CPU selection here
config X86_L1_CACHE_BYTES
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 5b1979a..ac1e31b 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -118,7 +118,6 @@
config 4KSTACKS
bool "Use 4Kb for kernel stacks instead of 8Kb"
depends on X86_32
- 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
@@ -256,11 +255,9 @@
help
Do change_page_attr() self-tests every 30 seconds.
-endmenu
-
config OPTIMIZE_INLINING
bool "Allow gcc to uninline functions marked 'inline'"
- default y
+ depends on BROKEN
help
This option determines if the kernel forces gcc to inline the functions
developers have marked 'inline'. Doing so takes away freedom from gcc to
@@ -270,3 +267,6 @@
this algorithm is so good that allowing gcc4 to make the decision can
become the default in the future, until then this option is there to
test gcc for this.
+
+endmenu
+
diff --git a/arch/x86/boot/edd.c b/arch/x86/boot/edd.c
index d84a48e..03399d6 100644
--- a/arch/x86/boot/edd.c
+++ b/arch/x86/boot/edd.c
@@ -126,17 +126,25 @@
{
char eddarg[8];
int do_mbr = 1;
+#ifdef CONFIG_EDD_OFF
+ int do_edd = 0;
+#else
int do_edd = 1;
+#endif
int be_quiet;
int devno;
struct edd_info ei, *edp;
u32 *mbrptr;
if (cmdline_find_option("edd", eddarg, sizeof eddarg) > 0) {
- if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip"))
+ if (!strcmp(eddarg, "skipmbr") || !strcmp(eddarg, "skip")) {
+ do_edd = 1;
do_mbr = 0;
+ }
else if (!strcmp(eddarg, "off"))
do_edd = 0;
+ else if (!strcmp(eddarg, "on"))
+ do_edd = 1;
}
be_quiet = cmdline_find_option_bool("quiet");
diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index bbed3a2..cb3856a 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -128,7 +128,7 @@
current->state = TASK_INTERRUPTIBLE;
schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
return -ERESTARTNOHAND;
}
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index fa19c38..bbdacb3 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -40,7 +40,6 @@
obj-y += cpu/
obj-y += acpi/
obj-$(CONFIG_X86_BIOS_REBOOT) += reboot.o
-obj-$(CONFIG_X86_64) += reboot.o
obj-$(CONFIG_MCA) += mca_32.o
obj-$(CONFIG_X86_MSR) += msr.o
obj-$(CONFIG_X86_CPUID) += cpuid.o
@@ -91,6 +90,8 @@
obj-$(CONFIG_SCx200) += scx200.o
scx200-y += scx200_32.o
+obj-$(CONFIG_OLPC) += olpc.o
+
###
# 64 bit specific files
ifeq ($(CONFIG_X86_64),y)
@@ -101,4 +102,6 @@
obj-$(CONFIG_GART_IOMMU) += pci-gart_64.o aperture_64.o
obj-$(CONFIG_CALGARY_IOMMU) += pci-calgary_64.o tce_64.o
obj-$(CONFIG_SWIOTLB) += pci-swiotlb_64.o
+
+ obj-$(CONFIG_PCI_MMCONFIG) += mmconf-fam10h_64.o
endif
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 977ed5c..c49ebcc 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -771,6 +771,32 @@
boot_cpu_physical_apicid = GET_APIC_ID(read_apic_id());
}
+static int __init early_acpi_parse_madt_lapic_addr_ovr(void)
+{
+ int count;
+
+ if (!cpu_has_apic)
+ return -ENODEV;
+
+ /*
+ * Note that the LAPIC address is obtained from the MADT (32-bit value)
+ * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
+ */
+
+ count =
+ acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
+ acpi_parse_lapic_addr_ovr, 0);
+ if (count < 0) {
+ printk(KERN_ERR PREFIX
+ "Error parsing LAPIC address override entry\n");
+ return count;
+ }
+
+ acpi_register_lapic_address(acpi_lapic_addr);
+
+ return count;
+}
+
static int __init acpi_parse_madt_lapic_entries(void)
{
int count;
@@ -901,6 +927,33 @@
}
#endif /* !CONFIG_X86_IO_APIC */
+static void __init early_acpi_process_madt(void)
+{
+#ifdef CONFIG_X86_LOCAL_APIC
+ int error;
+
+ if (!acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt)) {
+
+ /*
+ * Parse MADT LAPIC entries
+ */
+ error = early_acpi_parse_madt_lapic_addr_ovr();
+ if (!error) {
+ acpi_lapic = 1;
+ smp_found_config = 1;
+ }
+ if (error == -EINVAL) {
+ /*
+ * Dell Precision Workstation 410, 610 come here.
+ */
+ printk(KERN_ERR PREFIX
+ "Invalid BIOS MADT, disabling ACPI\n");
+ disable_acpi();
+ }
+ }
+#endif
+}
+
static void __init acpi_process_madt(void)
{
#ifdef CONFIG_X86_LOCAL_APIC
@@ -1233,6 +1286,23 @@
return 0;
}
+int __init early_acpi_boot_init(void)
+{
+ /*
+ * If acpi_disabled, bail out
+ * One exception: acpi=ht continues far enough to enumerate LAPICs
+ */
+ if (acpi_disabled && !acpi_ht)
+ return 1;
+
+ /*
+ * Process the Multiple APIC Description Table (MADT), if present
+ */
+ early_acpi_process_madt();
+
+ return 0;
+}
+
int __init acpi_boot_init(void)
{
/*
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index e4ea362..bf9290e 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -1192,19 +1192,6 @@
int err;
struct apm_user *as;
- if (pm_send_all(PM_SUSPEND, (void *)3)) {
- /* Vetoed */
- if (vetoable) {
- if (apm_info.connection_version > 0x100)
- set_system_power_state(APM_STATE_REJECT);
- err = -EBUSY;
- ignore_sys_suspend = 0;
- printk(KERN_WARNING "apm: suspend was vetoed.\n");
- goto out;
- }
- printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n");
- }
-
device_suspend(PMSG_SUSPEND);
local_irq_disable();
device_power_down(PMSG_SUSPEND);
@@ -1227,9 +1214,7 @@
device_power_up();
local_irq_enable();
device_resume();
- pm_send_all(PM_RESUME, (void *)0);
queue_event(APM_NORMAL_RESUME, NULL);
- out:
spin_lock(&user_list_lock);
for (as = user_list; as != NULL; as = as->next) {
as->suspend_wait = 0;
@@ -1340,7 +1325,6 @@
if ((event != APM_NORMAL_RESUME)
|| (ignore_normal_resume == 0)) {
device_resume();
- pm_send_all(PM_RESUME, (void *)0);
queue_event(event, NULL);
}
ignore_normal_resume = 0;
diff --git a/arch/x86/kernel/asm-offsets_32.c b/arch/x86/kernel/asm-offsets_32.c
index 670c3c3..9258808 100644
--- a/arch/x86/kernel/asm-offsets_32.c
+++ b/arch/x86/kernel/asm-offsets_32.c
@@ -9,6 +9,7 @@
#include <linux/signal.h>
#include <linux/personality.h>
#include <linux/suspend.h>
+#include <linux/kbuild.h>
#include <asm/ucontext.h>
#include "sigframe.h"
#include <asm/pgtable.h>
@@ -23,14 +24,6 @@
#include <linux/lguest.h>
#include "../../../drivers/lguest/lg.h"
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
-#define OFFSET(sym, str, mem) \
- DEFINE(sym, offsetof(struct str, mem));
-
/* workaround for a warning with -Wmissing-prototypes */
void foo(void);
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index 494e1e0..f126c05 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -10,6 +10,7 @@
#include <linux/errno.h>
#include <linux/hardirq.h>
#include <linux/suspend.h>
+#include <linux/kbuild.h>
#include <asm/pda.h>
#include <asm/processor.h>
#include <asm/segment.h>
@@ -17,14 +18,6 @@
#include <asm/ia32.h>
#include <asm/bootparam.h>
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
-
-#define OFFSET(sym, str, mem) \
- DEFINE(sym, offsetof(struct str, mem))
-
#define __NO_STUBS 1
#undef __SYSCALL
#undef _ASM_X86_64_UNISTD_H_
diff --git a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
index 8db8f73..b0c8208 100644
--- a/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -601,6 +601,7 @@
policy->shared_type == CPUFREQ_SHARED_TYPE_ANY) {
policy->cpus = perf->shared_cpu_map;
}
+ policy->related_cpus = perf->shared_cpu_map;
#ifdef CONFIG_SMP
dmi_check_system(sw_any_bug_dmi_table);
diff --git a/arch/x86/kernel/cpu/mtrr/generic.c b/arch/x86/kernel/cpu/mtrr/generic.c
index 353efe4..5d241ce 100644
--- a/arch/x86/kernel/cpu/mtrr/generic.c
+++ b/arch/x86/kernel/cpu/mtrr/generic.c
@@ -90,7 +90,7 @@
* Look of multiple ranges matching this address and pick type
* as per MTRR precedence
*/
- if (!mtrr_state.enabled & 2) {
+ if (!(mtrr_state.enabled & 2)) {
return mtrr_state.def_type;
}
diff --git a/arch/x86/kernel/cpu/mtrr/if.c b/arch/x86/kernel/cpu/mtrr/if.c
index 1960f19..84c480b 100644
--- a/arch/x86/kernel/cpu/mtrr/if.c
+++ b/arch/x86/kernel/cpu/mtrr/if.c
@@ -424,7 +424,7 @@
return -ENODEV;
proc_root_mtrr =
- proc_create("mtrr", S_IWUSR | S_IRUGO, &proc_root, &mtrr_fops);
+ proc_create("mtrr", S_IWUSR | S_IRUGO, NULL, &mtrr_fops);
if (proc_root_mtrr)
proc_root_mtrr->owner = THIS_MODULE;
diff --git a/arch/x86/kernel/e820_64.c b/arch/x86/kernel/e820_64.c
index 645ee5e..124480c 100644
--- a/arch/x86/kernel/e820_64.c
+++ b/arch/x86/kernel/e820_64.c
@@ -100,7 +100,7 @@
for (j = i + 1; j < MAX_EARLY_RES && early_res[j].end; j++)
;
- memcpy(&early_res[i], &early_res[i + 1],
+ memmove(&early_res[i], &early_res[i + 1],
(j - 1 - i) * sizeof(struct early_res));
early_res[j - 1].end = 0;
diff --git a/arch/x86/kernel/genapic_64.c b/arch/x86/kernel/genapic_64.c
index 021624c..cbaaf69 100644
--- a/arch/x86/kernel/genapic_64.c
+++ b/arch/x86/kernel/genapic_64.c
@@ -83,7 +83,7 @@
{
unsigned int id;
- WARN_ON(preemptible());
+ WARN_ON(preemptible() && num_online_cpus() > 1);
id = apic_read(APIC_ID);
if (uv_system_type >= UV_X2APIC)
id |= __get_cpu_var(x2apic_extra_bits);
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index 90f038a..b2cc737 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -656,15 +656,16 @@
.asciz "Unknown interrupt or fault at EIP %p %p %p\n"
fault_msg:
- .asciz \
-/* fault info: */ "BUG: Int %d: CR2 %p\n" \
-/* pusha regs: */ " EDI %p ESI %p EBP %p ESP %p\n" \
- " EBX %p EDX %p ECX %p EAX %p\n" \
-/* fault frame: */ " err %p EIP %p CS %p flg %p\n" \
- \
- "Stack: %p %p %p %p %p %p %p %p\n" \
- " %p %p %p %p %p %p %p %p\n" \
- " %p %p %p %p %p %p %p %p\n"
+/* fault info: */
+ .ascii "BUG: Int %d: CR2 %p\n"
+/* pusha regs: */
+ .ascii " EDI %p ESI %p EBP %p ESP %p\n"
+ .ascii " EBX %p EDX %p ECX %p EAX %p\n"
+/* fault frame: */
+ .ascii " err %p EIP %p CS %p flg %p\n"
+ .ascii "Stack: %p %p %p %p %p %p %p %p\n"
+ .ascii " %p %p %p %p %p %p %p %p\n"
+ .asciz " %p %p %p %p %p %p %p %p\n"
#include "../../x86/xen/xen-head.S"
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c
index 9007f9e..9b5cfcd 100644
--- a/arch/x86/kernel/hpet.c
+++ b/arch/x86/kernel/hpet.c
@@ -137,9 +137,10 @@
hd.hd_irq[0] = HPET_LEGACY_8254;
hd.hd_irq[1] = HPET_LEGACY_RTC;
- for (i = 2; i < nrtimers; timer++, i++)
- hd.hd_irq[i] = (timer->hpet_config & Tn_INT_ROUTE_CNF_MASK) >>
+ for (i = 2; i < nrtimers; timer++, i++) {
+ hd.hd_irq[i] = (readl(&timer->hpet_config) & Tn_INT_ROUTE_CNF_MASK) >>
Tn_INT_ROUTE_CNF_SHIFT;
+ }
hpet_alloc(&hd);
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c
index 00bda7b..147352d 100644
--- a/arch/x86/kernel/irq_32.c
+++ b/arch/x86/kernel/irq_32.c
@@ -190,8 +190,6 @@
hardirq_ctx[cpu] = NULL;
}
-extern asmlinkage void __do_softirq(void);
-
asmlinkage void do_softirq(void)
{
unsigned long flags;
diff --git a/arch/x86/kernel/mmconf-fam10h_64.c b/arch/x86/kernel/mmconf-fam10h_64.c
new file mode 100644
index 0000000..edc5fbf
--- /dev/null
+++ b/arch/x86/kernel/mmconf-fam10h_64.c
@@ -0,0 +1,243 @@
+/*
+ * AMD Family 10h mmconfig enablement
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <asm/pci-direct.h>
+#include <linux/sort.h>
+#include <asm/io.h>
+#include <asm/msr.h>
+#include <asm/acpi.h>
+
+#include "../pci/pci.h"
+
+struct pci_hostbridge_probe {
+ u32 bus;
+ u32 slot;
+ u32 vendor;
+ u32 device;
+};
+
+static u64 __cpuinitdata fam10h_pci_mmconf_base;
+static int __cpuinitdata fam10h_pci_mmconf_base_status;
+
+static struct pci_hostbridge_probe pci_probes[] __cpuinitdata = {
+ { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
+ { 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 },
+};
+
+struct range {
+ u64 start;
+ u64 end;
+};
+
+static int __cpuinit cmp_range(const void *x1, const void *x2)
+{
+ const struct range *r1 = x1;
+ const struct range *r2 = x2;
+ int start1, start2;
+
+ start1 = r1->start >> 32;
+ start2 = r2->start >> 32;
+
+ return start1 - start2;
+}
+
+/*[47:0] */
+/* need to avoid (0xfd<<32) and (0xfe<<32), ht used space */
+#define FAM10H_PCI_MMCONF_BASE (0xfcULL<<32)
+#define BASE_VALID(b) ((b != (0xfdULL << 32)) && (b != (0xfeULL << 32)))
+static void __cpuinit get_fam10h_pci_mmconf_base(void)
+{
+ int i;
+ unsigned bus;
+ unsigned slot;
+ int found;
+
+ u64 val;
+ u32 address;
+ u64 tom2;
+ u64 base = FAM10H_PCI_MMCONF_BASE;
+
+ int hi_mmio_num;
+ struct range range[8];
+
+ /* only try to get setting from BSP */
+ /* -1 or 1 */
+ if (fam10h_pci_mmconf_base_status)
+ return;
+
+ if (!early_pci_allowed())
+ goto fail;
+
+ found = 0;
+ for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
+ u32 id;
+ u16 device;
+ u16 vendor;
+
+ bus = pci_probes[i].bus;
+ slot = pci_probes[i].slot;
+ id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
+
+ vendor = id & 0xffff;
+ device = (id>>16) & 0xffff;
+ if (pci_probes[i].vendor == vendor &&
+ pci_probes[i].device == device) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ goto fail;
+
+ /* SYS_CFG */
+ address = MSR_K8_SYSCFG;
+ rdmsrl(address, val);
+
+ /* TOP_MEM2 is not enabled? */
+ if (!(val & (1<<21))) {
+ tom2 = 0;
+ } else {
+ /* TOP_MEM2 */
+ address = MSR_K8_TOP_MEM2;
+ rdmsrl(address, val);
+ tom2 = val & (0xffffULL<<32);
+ }
+
+ if (base <= tom2)
+ base = tom2 + (1ULL<<32);
+
+ /*
+ * need to check if the range is in the high mmio range that is
+ * above 4G
+ */
+ hi_mmio_num = 0;
+ for (i = 0; i < 8; i++) {
+ u32 reg;
+ u64 start;
+ u64 end;
+ reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
+ if (!(reg & 3))
+ continue;
+
+ start = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
+ reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
+ end = (((u64)reg) << 8) & (0xffULL << 32); /* 39:16 on 31:8*/
+
+ if (!end)
+ continue;
+
+ range[hi_mmio_num].start = start;
+ range[hi_mmio_num].end = end;
+ hi_mmio_num++;
+ }
+
+ if (!hi_mmio_num)
+ goto out;
+
+ /* sort the range */
+ sort(range, hi_mmio_num, sizeof(struct range), cmp_range, NULL);
+
+ if (range[hi_mmio_num - 1].end < base)
+ goto out;
+ if (range[0].start > base)
+ goto out;
+
+ /* need to find one window */
+ base = range[0].start - (1ULL << 32);
+ if ((base > tom2) && BASE_VALID(base))
+ goto out;
+ base = range[hi_mmio_num - 1].end + (1ULL << 32);
+ if ((base > tom2) && BASE_VALID(base))
+ goto out;
+ /* need to find window between ranges */
+ if (hi_mmio_num > 1)
+ for (i = 0; i < hi_mmio_num - 1; i++) {
+ if (range[i + 1].start > (range[i].end + (1ULL << 32))) {
+ base = range[i].end + (1ULL << 32);
+ if ((base > tom2) && BASE_VALID(base))
+ goto out;
+ }
+ }
+
+fail:
+ fam10h_pci_mmconf_base_status = -1;
+ return;
+out:
+ fam10h_pci_mmconf_base = base;
+ fam10h_pci_mmconf_base_status = 1;
+}
+
+void __cpuinit fam10h_check_enable_mmcfg(void)
+{
+ u64 val;
+ u32 address;
+
+ if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
+ return;
+
+ address = MSR_FAM10H_MMIO_CONF_BASE;
+ rdmsrl(address, val);
+
+ /* try to make sure that AP's setting is identical to BSP setting */
+ if (val & FAM10H_MMIO_CONF_ENABLE) {
+ unsigned busnbits;
+ busnbits = (val >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
+ FAM10H_MMIO_CONF_BUSRANGE_MASK;
+
+ /* only trust the one handle 256 buses, if acpi=off */
+ if (!acpi_pci_disabled || busnbits >= 8) {
+ u64 base;
+ base = val & (0xffffULL << 32);
+ if (fam10h_pci_mmconf_base_status <= 0) {
+ fam10h_pci_mmconf_base = base;
+ fam10h_pci_mmconf_base_status = 1;
+ return;
+ } else if (fam10h_pci_mmconf_base == base)
+ return;
+ }
+ }
+
+ /*
+ * if it is not enabled, try to enable it and assume only one segment
+ * with 256 buses
+ */
+ get_fam10h_pci_mmconf_base();
+ if (fam10h_pci_mmconf_base_status <= 0)
+ return;
+
+ printk(KERN_INFO "Enable MMCONFIG on AMD Family 10h\n");
+ val &= ~((FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT) |
+ (FAM10H_MMIO_CONF_BUSRANGE_MASK<<FAM10H_MMIO_CONF_BUSRANGE_SHIFT));
+ val |= fam10h_pci_mmconf_base | (8 << FAM10H_MMIO_CONF_BUSRANGE_SHIFT) |
+ FAM10H_MMIO_CONF_ENABLE;
+ wrmsrl(address, val);
+}
+
+static int __devinit set_check_enable_amd_mmconf(const struct dmi_system_id *d)
+{
+ pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;
+ return 0;
+}
+
+static struct dmi_system_id __devinitdata mmconf_dmi_table[] = {
+ {
+ .callback = set_check_enable_amd_mmconf,
+ .ident = "Sun Microsystems Machine",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Sun Microsystems"),
+ },
+ },
+ {}
+};
+
+void __init check_enable_amd_mmconf_dmi(void)
+{
+ dmi_check_system(mmconf_dmi_table);
+}
diff --git a/arch/x86/kernel/olpc.c b/arch/x86/kernel/olpc.c
new file mode 100644
index 0000000..3e66722
--- /dev/null
+++ b/arch/x86/kernel/olpc.c
@@ -0,0 +1,260 @@
+/*
+ * Support for the OLPC DCON and OLPC EC access
+ *
+ * Copyright © 2006 Advanced Micro Devices, Inc.
+ * Copyright © 2007-2008 Andres Salomon <dilinger@debian.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <asm/geode.h>
+#include <asm/olpc.h>
+
+#ifdef CONFIG_OPEN_FIRMWARE
+#include <asm/ofw.h>
+#endif
+
+struct olpc_platform_t olpc_platform_info;
+EXPORT_SYMBOL_GPL(olpc_platform_info);
+
+static DEFINE_SPINLOCK(ec_lock);
+
+/* what the timeout *should* be (in ms) */
+#define EC_BASE_TIMEOUT 20
+
+/* the timeout that bugs in the EC might force us to actually use */
+static int ec_timeout = EC_BASE_TIMEOUT;
+
+static int __init olpc_ec_timeout_set(char *str)
+{
+ if (get_option(&str, &ec_timeout) != 1) {
+ ec_timeout = EC_BASE_TIMEOUT;
+ printk(KERN_ERR "olpc-ec: invalid argument to "
+ "'olpc_ec_timeout=', ignoring!\n");
+ }
+ printk(KERN_DEBUG "olpc-ec: using %d ms delay for EC commands.\n",
+ ec_timeout);
+ return 1;
+}
+__setup("olpc_ec_timeout=", olpc_ec_timeout_set);
+
+/*
+ * These {i,o}bf_status functions return whether the buffers are full or not.
+ */
+
+static inline unsigned int ibf_status(unsigned int port)
+{
+ return !!(inb(port) & 0x02);
+}
+
+static inline unsigned int obf_status(unsigned int port)
+{
+ return inb(port) & 0x01;
+}
+
+#define wait_on_ibf(p, d) __wait_on_ibf(__LINE__, (p), (d))
+static int __wait_on_ibf(unsigned int line, unsigned int port, int desired)
+{
+ unsigned int timeo;
+ int state = ibf_status(port);
+
+ for (timeo = ec_timeout; state != desired && timeo; timeo--) {
+ mdelay(1);
+ state = ibf_status(port);
+ }
+
+ if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
+ timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
+ printk(KERN_WARNING "olpc-ec: %d: waited %u ms for IBF!\n",
+ line, ec_timeout - timeo);
+ }
+
+ return !(state == desired);
+}
+
+#define wait_on_obf(p, d) __wait_on_obf(__LINE__, (p), (d))
+static int __wait_on_obf(unsigned int line, unsigned int port, int desired)
+{
+ unsigned int timeo;
+ int state = obf_status(port);
+
+ for (timeo = ec_timeout; state != desired && timeo; timeo--) {
+ mdelay(1);
+ state = obf_status(port);
+ }
+
+ if ((state == desired) && (ec_timeout > EC_BASE_TIMEOUT) &&
+ timeo < (ec_timeout - EC_BASE_TIMEOUT)) {
+ printk(KERN_WARNING "olpc-ec: %d: waited %u ms for OBF!\n",
+ line, ec_timeout - timeo);
+ }
+
+ return !(state == desired);
+}
+
+/*
+ * This allows the kernel to run Embedded Controller commands. The EC is
+ * documented at <http://wiki.laptop.org/go/Embedded_controller>, and the
+ * available EC commands are here:
+ * <http://wiki.laptop.org/go/Ec_specification>. Unfortunately, while
+ * OpenFirmware's source is available, the EC's is not.
+ */
+int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
+ unsigned char *outbuf, size_t outlen)
+{
+ unsigned long flags;
+ int ret = -EIO;
+ int i;
+
+ spin_lock_irqsave(&ec_lock, flags);
+
+ /* Clear OBF */
+ for (i = 0; i < 10 && (obf_status(0x6c) == 1); i++)
+ inb(0x68);
+ if (i == 10) {
+ printk(KERN_ERR "olpc-ec: timeout while attempting to "
+ "clear OBF flag!\n");
+ goto err;
+ }
+
+ if (wait_on_ibf(0x6c, 0)) {
+ printk(KERN_ERR "olpc-ec: timeout waiting for EC to "
+ "quiesce!\n");
+ goto err;
+ }
+
+restart:
+ /*
+ * Note that if we time out during any IBF checks, that's a failure;
+ * we have to return. There's no way for the kernel to clear that.
+ *
+ * If we time out during an OBF check, we can restart the command;
+ * reissuing it will clear the OBF flag, and we should be alright.
+ * The OBF flag will sometimes misbehave due to what we believe
+ * is a hardware quirk..
+ */
+ printk(KERN_DEBUG "olpc-ec: running cmd 0x%x\n", cmd);
+ outb(cmd, 0x6c);
+
+ if (wait_on_ibf(0x6c, 0)) {
+ printk(KERN_ERR "olpc-ec: timeout waiting for EC to read "
+ "command!\n");
+ goto err;
+ }
+
+ if (inbuf && inlen) {
+ /* write data to EC */
+ for (i = 0; i < inlen; i++) {
+ if (wait_on_ibf(0x6c, 0)) {
+ printk(KERN_ERR "olpc-ec: timeout waiting for"
+ " EC accept data!\n");
+ goto err;
+ }
+ printk(KERN_DEBUG "olpc-ec: sending cmd arg 0x%x\n",
+ inbuf[i]);
+ outb(inbuf[i], 0x68);
+ }
+ }
+ if (outbuf && outlen) {
+ /* read data from EC */
+ for (i = 0; i < outlen; i++) {
+ if (wait_on_obf(0x6c, 1)) {
+ printk(KERN_ERR "olpc-ec: timeout waiting for"
+ " EC to provide data!\n");
+ goto restart;
+ }
+ outbuf[i] = inb(0x68);
+ printk(KERN_DEBUG "olpc-ec: received 0x%x\n",
+ outbuf[i]);
+ }
+ }
+
+ ret = 0;
+err:
+ spin_unlock_irqrestore(&ec_lock, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(olpc_ec_cmd);
+
+#ifdef CONFIG_OPEN_FIRMWARE
+static void __init platform_detect(void)
+{
+ size_t propsize;
+ u32 rev;
+
+ if (ofw("getprop", 4, 1, NULL, "board-revision-int", &rev, 4,
+ &propsize) || propsize != 4) {
+ printk(KERN_ERR "ofw: getprop call failed!\n");
+ rev = 0;
+ }
+ olpc_platform_info.boardrev = be32_to_cpu(rev);
+}
+#else
+static void __init platform_detect(void)
+{
+ /* stopgap until OFW support is added to the kernel */
+ olpc_platform_info.boardrev = be32_to_cpu(0xc2);
+}
+#endif
+
+static int __init olpc_init(void)
+{
+ unsigned char *romsig;
+
+ /* The ioremap check is dangerous; limit what we run it on */
+ if (!is_geode() || geode_has_vsa2())
+ return 0;
+
+ spin_lock_init(&ec_lock);
+
+ romsig = ioremap(0xffffffc0, 16);
+ if (!romsig)
+ return 0;
+
+ if (strncmp(romsig, "CL1 Q", 7))
+ goto unmap;
+ if (strncmp(romsig+6, romsig+13, 3)) {
+ printk(KERN_INFO "OLPC BIOS signature looks invalid. "
+ "Assuming not OLPC\n");
+ goto unmap;
+ }
+
+ printk(KERN_INFO "OLPC board with OpenFirmware %.16s\n", romsig);
+ olpc_platform_info.flags |= OLPC_F_PRESENT;
+
+ /* get the platform revision */
+ platform_detect();
+
+ /* assume B1 and above models always have a DCON */
+ if (olpc_board_at_least(olpc_board(0xb1)))
+ olpc_platform_info.flags |= OLPC_F_DCON;
+
+ /* get the EC revision */
+ olpc_ec_cmd(EC_FIRMWARE_REV, NULL, 0,
+ (unsigned char *) &olpc_platform_info.ecver, 1);
+
+ /* check to see if the VSA exists */
+ if (geode_has_vsa2())
+ olpc_platform_info.flags |= OLPC_F_VSA;
+
+ printk(KERN_INFO "OLPC board revision %s%X (EC=%x)\n",
+ ((olpc_platform_info.boardrev & 0xf) < 8) ? "pre" : "",
+ olpc_platform_info.boardrev >> 4,
+ olpc_platform_info.ecver);
+
+unmap:
+ iounmap(romsig);
+ return 0;
+}
+
+postcore_initcall(olpc_init);
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index 388b113..0c37f16 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -14,7 +14,7 @@
const struct dma_mapping_ops *dma_ops;
EXPORT_SYMBOL(dma_ops);
-int iommu_sac_force __read_mostly = 0;
+static int iommu_sac_force __read_mostly;
#ifdef CONFIG_IOMMU_DEBUG
int panic_on_overflow __read_mostly = 1;
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c
index a4a8383..07c6d42 100644
--- a/arch/x86/kernel/reboot.c
+++ b/arch/x86/kernel/reboot.c
@@ -9,6 +9,7 @@
#include <asm/desc.h>
#include <asm/hpet.h>
#include <asm/pgtable.h>
+#include <asm/proto.h>
#include <asm/reboot_fixups.h>
#include <asm/reboot.h>
diff --git a/arch/x86/kernel/setup_64.c b/arch/x86/kernel/setup_64.c
index a94fb95..22c14e2 100644
--- a/arch/x86/kernel/setup_64.c
+++ b/arch/x86/kernel/setup_64.c
@@ -29,6 +29,7 @@
#include <linux/crash_dump.h>
#include <linux/root_dev.h>
#include <linux/pci.h>
+#include <asm/pci-direct.h>
#include <linux/efi.h>
#include <linux/acpi.h>
#include <linux/kallsyms.h>
@@ -40,6 +41,7 @@
#include <linux/dmi.h>
#include <linux/dma-mapping.h>
#include <linux/ctype.h>
+#include <linux/sort.h>
#include <linux/uaccess.h>
#include <linux/init_ohci1394_dma.h>
#include <linux/kvm_para.h>
@@ -288,6 +290,18 @@
}
}
+#ifdef CONFIG_PCI_MMCONFIG
+extern void __cpuinit fam10h_check_enable_mmcfg(void);
+extern void __init check_enable_amd_mmconf_dmi(void);
+#else
+void __cpuinit fam10h_check_enable_mmcfg(void)
+{
+}
+void __init check_enable_amd_mmconf_dmi(void)
+{
+}
+#endif
+
/*
* setup_arch - architecture-specific boot-time initializations
*
@@ -515,6 +529,9 @@
conswitchp = &dummy_con;
#endif
#endif
+
+ /* do this before identify_cpu for boot cpu */
+ check_enable_amd_mmconf_dmi();
}
static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
@@ -767,6 +784,9 @@
/* MFENCE stops RDTSC speculation */
set_cpu_cap(c, X86_FEATURE_MFENCE_RDTSC);
+ if (c->x86 == 0x10)
+ fam10h_check_enable_mmcfg();
+
if (amd_apic_timer_broken())
disable_apic_timer = 1;
diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c
index 8e05e7f..d923736 100644
--- a/arch/x86/kernel/signal_32.c
+++ b/arch/x86/kernel/signal_32.c
@@ -57,7 +57,7 @@
current->state = TASK_INTERRUPTIBLE;
schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
return -ERESTARTNOHAND;
}
@@ -593,7 +593,7 @@
if (!user_mode(regs))
return;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = ¤t->saved_sigmask;
else
oldset = ¤t->blocked;
@@ -612,13 +612,12 @@
/* Whee! Actually deliver the signal. */
if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
/*
- * a signal was successfully delivered; the saved
+ * A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
- * clear the TIF_RESTORE_SIGMASK flag
+ * clear the TS_RESTORE_SIGMASK flag.
*/
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
}
return;
}
@@ -645,8 +644,8 @@
* If there's no signal to deliver, we just put the saved sigmask
* back.
*/
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
}
}
@@ -665,7 +664,7 @@
}
/* deal with pending signal delivery */
- if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
if (thread_info_flags & _TIF_HRTICK_RESCHED)
diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c
index ccb2a45..e53b267 100644
--- a/arch/x86/kernel/signal_64.c
+++ b/arch/x86/kernel/signal_64.c
@@ -427,7 +427,7 @@
if (!user_mode(regs))
return;
- if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
oldset = ¤t->saved_sigmask;
else
oldset = ¤t->blocked;
@@ -444,11 +444,13 @@
/* Whee! Actually deliver the signal. */
if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
- /* a signal was successfully delivered; the saved
+ /*
+ * A signal was successfully delivered; the saved
* sigmask will have been stored in the signal frame,
* and will be restored by sigreturn, so we can simply
- * clear the TIF_RESTORE_SIGMASK flag */
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ * clear the TS_RESTORE_SIGMASK flag.
+ */
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
}
return;
}
@@ -476,8 +478,8 @@
* If there's no signal to deliver, we just put the saved sigmask
* back.
*/
- if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
- clear_thread_flag(TIF_RESTORE_SIGMASK);
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
+ current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL);
}
}
@@ -498,7 +500,7 @@
#endif /* CONFIG_X86_MCE */
/* deal with pending signal delivery */
- if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
if (thread_info_flags & _TIF_HRTICK_RESCHED)
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 04c662b..84241a2 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -1149,14 +1149,10 @@
"forcing use of dummy APIC emulation.\n");
smpboot_clear_io_apic();
#ifdef CONFIG_X86_32
- if (nmi_watchdog == NMI_LOCAL_APIC) {
- printk(KERN_INFO "activating minimal APIC for"
- "NMI watchdog use.\n");
- connect_bsp_APIC();
- setup_local_APIC();
- end_local_APIC_setup();
- }
+ connect_bsp_APIC();
#endif
+ setup_local_APIC();
+ end_local_APIC_setup();
return -1;
}
diff --git a/arch/x86/kernel/time_32.c b/arch/x86/kernel/time_32.c
index 1a89e93..2ff21f3 100644
--- a/arch/x86/kernel/time_32.c
+++ b/arch/x86/kernel/time_32.c
@@ -115,7 +115,6 @@
return IRQ_HANDLED;
}
-extern void (*late_time_init)(void);
/* Duplicate of time_init() below, with hpet_enable part added */
void __init hpet_time_init(void)
{
diff --git a/arch/x86/kernel/vsmp_64.c b/arch/x86/kernel/vsmp_64.c
index caf2a26..ba8c0b7 100644
--- a/arch/x86/kernel/vsmp_64.c
+++ b/arch/x86/kernel/vsmp_64.c
@@ -133,7 +133,7 @@
}
}
#else
-static int __init detect_vsmp_box(void)
+static void __init detect_vsmp_box(void)
{
}
int is_vsmp_box(void)
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 361e316..4c943ea 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -35,7 +35,7 @@
#include "i8254.h"
#ifndef CONFIG_X86_64
-#define mod_64(x, y) ((x) - (y) * div64_64(x, y))
+#define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
#else
#define mod_64(x, y) ((x) % (y))
#endif
@@ -60,8 +60,8 @@
rl = (u64)u.l.low * (u64)b;
rh = (u64)u.l.high * (u64)b;
rh += (rl >> 32);
- res.l.high = div64_64(rh, c);
- res.l.low = div64_64(((mod_64(rh, c) << 32) + (rl & 0xffffffff)), c);
+ res.l.high = div64_u64(rh, c);
+ res.l.low = div64_u64(((mod_64(rh, c) << 32) + (rl & 0xffffffff)), c);
return res.ll;
}
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 57ac4e4..36809d7 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -25,13 +25,13 @@
#include <linux/hrtimer.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/math64.h>
#include <asm/processor.h>
#include <asm/msr.h>
#include <asm/page.h>
#include <asm/current.h>
#include <asm/apicdef.h>
#include <asm/atomic.h>
-#include <asm/div64.h>
#include "irq.h"
#define PRId64 "d"
@@ -526,8 +526,8 @@
} else
passed = ktime_sub(now, apic->timer.last_update);
- counter_passed = div64_64(ktime_to_ns(passed),
- (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
+ counter_passed = div64_u64(ktime_to_ns(passed),
+ (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
if (counter_passed > tmcct) {
if (unlikely(!apic_lvtt_period(apic))) {
diff --git a/arch/x86/mach-voyager/voyager_cat.c b/arch/x86/mach-voyager/voyager_cat.c
index ecab9ff..2ad598c 100644
--- a/arch/x86/mach-voyager/voyager_cat.c
+++ b/arch/x86/mach-voyager/voyager_cat.c
@@ -877,7 +877,7 @@
request_resource(&iomem_resource, res);
}
- qic_addr = (unsigned long)ioremap(qic_addr, 0x400);
+ qic_addr = (unsigned long)ioremap_cache(qic_addr, 0x400);
for (j = 0; j < 4; j++) {
__u8 cpu;
diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index 9cf33d3..165c871 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -155,4 +155,3 @@
EXPORT_SYMBOL(kunmap);
EXPORT_SYMBOL(kmap_atomic);
EXPORT_SYMBOL(kunmap_atomic);
-EXPORT_SYMBOL(kmap_atomic_to_page);
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index 804de18..71bb315 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -149,7 +149,8 @@
* Don't allow anybody to remap normal RAM that we're using..
*/
for (pfn = phys_addr >> PAGE_SHIFT;
- (pfn << PAGE_SHIFT) < last_addr; pfn++) {
+ (pfn << PAGE_SHIFT) < (last_addr & PAGE_MASK);
+ pfn++) {
int is_ram = page_is_ram(pfn);
@@ -176,11 +177,11 @@
/*
* Do not fallback to certain memory types with certain
* requested type:
- * - request is uncached, return cannot be write-back
- * - request is uncached, return cannot be write-combine
+ * - request is uc-, return cannot be write-back
+ * - request is uc-, return cannot be write-combine
* - request is write-combine, return cannot be write-back
*/
- if ((prot_val == _PAGE_CACHE_UC &&
+ if ((prot_val == _PAGE_CACHE_UC_MINUS &&
(new_prot_val == _PAGE_CACHE_WB ||
new_prot_val == _PAGE_CACHE_WC)) ||
(prot_val == _PAGE_CACHE_WC &&
@@ -201,6 +202,9 @@
default:
prot = PAGE_KERNEL_NOCACHE;
break;
+ case _PAGE_CACHE_UC_MINUS:
+ prot = PAGE_KERNEL_UC_MINUS;
+ break;
case _PAGE_CACHE_WC:
prot = PAGE_KERNEL_WC;
break;
@@ -255,7 +259,16 @@
*/
void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
{
- return __ioremap_caller(phys_addr, size, _PAGE_CACHE_UC,
+ /*
+ * Ideally, this should be:
+ * pat_wc_enabled ? _PAGE_CACHE_UC : _PAGE_CACHE_UC_MINUS;
+ *
+ * Till we fix all X drivers to use ioremap_wc(), we will use
+ * UC MINUS.
+ */
+ unsigned long val = _PAGE_CACHE_UC_MINUS;
+
+ return __ioremap_caller(phys_addr, size, val,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_nocache);
diff --git a/arch/x86/mm/k8topology_64.c b/arch/x86/mm/k8topology_64.c
index 86808e6..1f476e4 100644
--- a/arch/x86/mm/k8topology_64.c
+++ b/arch/x86/mm/k8topology_64.c
@@ -13,12 +13,15 @@
#include <linux/nodemask.h>
#include <asm/io.h>
#include <linux/pci_ids.h>
+#include <linux/acpi.h>
#include <asm/types.h>
#include <asm/mmzone.h>
#include <asm/proto.h>
#include <asm/e820.h>
#include <asm/pci-direct.h>
#include <asm/numa.h>
+#include <asm/mpspec.h>
+#include <asm/apic.h>
static __init int find_northbridge(void)
{
@@ -44,6 +47,30 @@
return -1;
}
+static __init void early_get_boot_cpu_id(void)
+{
+ /*
+ * need to get boot_cpu_id so can use that to create apicid_to_node
+ * in k8_scan_nodes()
+ */
+ /*
+ * Find possible boot-time SMP configuration:
+ */
+ early_find_smp_config();
+#ifdef CONFIG_ACPI
+ /*
+ * Read APIC information from ACPI tables.
+ */
+ early_acpi_boot_init();
+#endif
+ /*
+ * get boot-time SMP configuration:
+ */
+ if (smp_found_config)
+ early_get_smp_config();
+ early_init_lapic_mapping();
+}
+
int __init k8_scan_nodes(unsigned long start, unsigned long end)
{
unsigned long prevbase;
@@ -56,6 +83,7 @@
unsigned cores;
unsigned bits;
int j;
+ unsigned apicid_base;
if (!early_pci_allowed())
return -1;
@@ -174,11 +202,19 @@
/* use the coreid bits from early_identify_cpu */
bits = boot_cpu_data.x86_coreid_bits;
cores = (1<<bits);
+ apicid_base = 0;
+ /* need to get boot_cpu_id early for system with apicid lifting */
+ early_get_boot_cpu_id();
+ if (boot_cpu_physical_apicid > 0) {
+ printk(KERN_INFO "BSP APIC ID: %02x\n",
+ boot_cpu_physical_apicid);
+ apicid_base = boot_cpu_physical_apicid;
+ }
for (i = 0; i < 8; i++) {
if (nodes[i].start != nodes[i].end) {
nodeid = nodeids[i];
- for (j = 0; j < cores; j++)
+ for (j = apicid_base; j < cores + apicid_base; j++)
apicid_to_node[(nodeid << bits) + j] = i;
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
}
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index bd5e05c..60bcb5b 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -777,14 +777,20 @@
int _set_memory_uc(unsigned long addr, int numpages)
{
+ /*
+ * for now UC MINUS. see comments in ioremap_nocache()
+ */
return change_page_attr_set(addr, numpages,
- __pgprot(_PAGE_CACHE_UC));
+ __pgprot(_PAGE_CACHE_UC_MINUS));
}
int set_memory_uc(unsigned long addr, int numpages)
{
+ /*
+ * for now UC MINUS. see comments in ioremap_nocache()
+ */
if (reserve_memtype(addr, addr + numpages * PAGE_SIZE,
- _PAGE_CACHE_UC, NULL))
+ _PAGE_CACHE_UC_MINUS, NULL))
return -EINVAL;
return _set_memory_uc(addr, numpages);
diff --git a/arch/x86/pci/Makefile_32 b/arch/x86/pci/Makefile_32
index cdd6828..7fa5198 100644
--- a/arch/x86/pci/Makefile_32
+++ b/arch/x86/pci/Makefile_32
@@ -3,12 +3,14 @@
obj-$(CONFIG_PCI_BIOS) += pcbios.o
obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_32.o direct.o mmconfig-shared.o
obj-$(CONFIG_PCI_DIRECT) += direct.o
+obj-$(CONFIG_PCI_OLPC) += olpc.o
pci-y := fixup.o
pci-$(CONFIG_ACPI) += acpi.o
pci-y += legacy.o irq.o
-pci-$(CONFIG_X86_VISWS) := visws.o fixup.o
-pci-$(CONFIG_X86_NUMAQ) := numa.o irq.o
+pci-$(CONFIG_X86_VISWS) += visws.o fixup.o
+pci-$(CONFIG_X86_NUMAQ) += numa.o irq.o
+pci-$(CONFIG_NUMA) += mp_bus_to_node.o
obj-y += $(pci-y) common.o early.o
diff --git a/arch/x86/pci/Makefile_64 b/arch/x86/pci/Makefile_64
index 7d8c467..8fbd198 100644
--- a/arch/x86/pci/Makefile_64
+++ b/arch/x86/pci/Makefile_64
@@ -13,5 +13,5 @@
# mmconfig has a 64bit special
obj-$(CONFIG_PCI_MMCONFIG) += mmconfig_64.o direct.o mmconfig-shared.o
-obj-$(CONFIG_NUMA) += k8-bus_64.o
+obj-y += k8-bus_64.o
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 2664cb3..1a9c0c6 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -191,7 +191,10 @@
{
struct pci_bus *bus;
struct pci_sysdata *sd;
+ int node;
+#ifdef CONFIG_ACPI_NUMA
int pxm;
+#endif
dmi_check_system(acpi_pciprobe_dmi_table);
@@ -201,6 +204,17 @@
return NULL;
}
+ node = -1;
+#ifdef CONFIG_ACPI_NUMA
+ pxm = acpi_get_pxm(device->handle);
+ if (pxm >= 0)
+ node = pxm_to_node(pxm);
+ if (node != -1)
+ set_mp_bus_to_node(busnum, node);
+ else
+ node = get_mp_bus_to_node(busnum);
+#endif
+
/* Allocate per-root-bus (not per bus) arch-specific data.
* TODO: leak; this memory is never freed.
* It's arguable whether it's worth the trouble to care.
@@ -212,13 +226,7 @@
}
sd->domain = domain;
- sd->node = -1;
-
- pxm = acpi_get_pxm(device->handle);
-#ifdef CONFIG_ACPI_NUMA
- if (pxm >= 0)
- sd->node = pxm_to_node(pxm);
-#endif
+ sd->node = node;
/*
* Maybe the desired pci bus has been already scanned. In such case
* it is unnecessary to scan the pci bus with the given domain,busnum.
@@ -238,9 +246,9 @@
kfree(sd);
#ifdef CONFIG_ACPI_NUMA
- if (bus != NULL) {
+ if (bus) {
if (pxm >= 0) {
- printk("bus %d -> pxm %d -> node %d\n",
+ printk(KERN_DEBUG "bus %02x -> pxm %d -> node %d\n",
busnum, pxm, pxm_to_node(pxm));
}
}
@@ -248,7 +256,6 @@
if (bus && (pci_probe & PCI_USE__CRS))
get_current_resources(device, busnum, domain, bus);
-
return bus;
}
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 75fcc29..2a4d751 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -342,9 +342,14 @@
return NULL;
}
- printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
+ sd->node = get_mp_bus_to_node(busnum);
- return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+ printk(KERN_DEBUG "PCI: Probing PCI hardware (bus %02x)\n", busnum);
+ bus = pci_scan_bus_parented(NULL, busnum, &pci_root_ops, sd);
+ if (!bus)
+ kfree(sd);
+
+ return bus;
}
extern u8 pci_cache_line_size;
@@ -420,6 +425,10 @@
pci_probe &= ~PCI_PROBE_MMCONF;
return NULL;
}
+ else if (!strcmp(str, "check_enable_amd_mmconf")) {
+ pci_probe |= PCI_CHECK_ENABLE_AMD_MMCONF;
+ return NULL;
+ }
#endif
else if (!strcmp(str, "noacpi")) {
acpi_noirq_set();
@@ -480,7 +489,7 @@
pcibios_disable_irq(dev);
}
-struct pci_bus *__devinit pci_scan_bus_with_sysdata(int busno)
+struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops, int node)
{
struct pci_bus *bus = NULL;
struct pci_sysdata *sd;
@@ -495,10 +504,15 @@
printk(KERN_ERR "PCI: OOM, skipping PCI bus %02x\n", busno);
return NULL;
}
- sd->node = -1;
- bus = pci_scan_bus(busno, &pci_root_ops, sd);
+ sd->node = node;
+ bus = pci_scan_bus(busno, ops, sd);
if (!bus)
kfree(sd);
return bus;
}
+
+struct pci_bus *pci_scan_bus_with_sysdata(int busno)
+{
+ return pci_scan_bus_on_node(busno, &pci_root_ops, -1);
+}
diff --git a/arch/x86/pci/direct.c b/arch/x86/pci/direct.c
index 42f3e4c..21d1e0e 100644
--- a/arch/x86/pci/direct.c
+++ b/arch/x86/pci/direct.c
@@ -258,7 +258,8 @@
{
if (type == 0)
return;
- printk(KERN_INFO "PCI: Using configuration type %d\n", type);
+ printk(KERN_INFO "PCI: Using configuration type %d for base access\n",
+ type);
if (type == 1)
raw_pci_ops = &pci_direct_conf1;
else
@@ -275,8 +276,10 @@
if (!region)
goto type2;
- if (pci_check_type1())
+ if (pci_check_type1()) {
+ raw_pci_ops = &pci_direct_conf1;
return 1;
+ }
release_resource(region);
type2:
@@ -290,7 +293,6 @@
goto fail2;
if (pci_check_type2()) {
- printk(KERN_INFO "PCI: Using configuration type 2\n");
raw_pci_ops = &pci_direct_conf2;
return 2;
}
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index a5ef5f5..b60b2ab 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -493,3 +493,20 @@
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015,
pci_siemens_interrupt_controller);
+
+/*
+ * Regular PCI devices have 256 bytes, but AMD Family 10h Opteron ext config
+ * have 4096 bytes. Even if the device is capable, that doesn't mean we can
+ * access it. Maybe we don't have a way to generate extended config space
+ * accesses. So check it
+ */
+static void fam10h_pci_cfg_space_size(struct pci_dev *dev)
+{
+ dev->cfg_size = pci_cfg_space_size_ext(dev, 0);
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1200, fam10h_pci_cfg_space_size);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, fam10h_pci_cfg_space_size);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, fam10h_pci_cfg_space_size);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, fam10h_pci_cfg_space_size);
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, fam10h_pci_cfg_space_size);
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 94f6c73..8af0f0b 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -301,6 +301,13 @@
prot = pgprot_val(vma->vm_page_prot);
if (pat_wc_enabled && write_combine)
prot |= _PAGE_CACHE_WC;
+ else if (pat_wc_enabled)
+ /*
+ * ioremap() and ioremap_nocache() defaults to UC MINUS for now.
+ * To avoid attribute conflicts, request UC MINUS here
+ * aswell.
+ */
+ prot |= _PAGE_CACHE_UC_MINUS;
else if (boot_cpu_data.x86 > 3)
prot |= _PAGE_CACHE_UC;
@@ -319,9 +326,8 @@
* - request is uncached, return cannot be write-combine
* - request is write-combine, return cannot be write-back
*/
- if ((flags == _PAGE_CACHE_UC &&
- (new_flags == _PAGE_CACHE_WB ||
- new_flags == _PAGE_CACHE_WC)) ||
+ if ((flags == _PAGE_CACHE_UC_MINUS &&
+ (new_flags == _PAGE_CACHE_WB)) ||
(flags == _PAGE_CACHE_WC &&
new_flags == _PAGE_CACHE_WB)) {
free_memtype(addr, addr+len);
diff --git a/arch/x86/pci/init.c b/arch/x86/pci/init.c
index 3de9f9b..dd30c60 100644
--- a/arch/x86/pci/init.c
+++ b/arch/x86/pci/init.c
@@ -6,16 +6,17 @@
in the right sequence from here. */
static __init int pci_access_init(void)
{
- int type __maybe_unused = 0;
-
#ifdef CONFIG_PCI_DIRECT
+ int type = 0;
+
type = pci_direct_probe();
#endif
-#ifdef CONFIG_PCI_MMCONFIG
- pci_mmcfg_init(type);
+
+ pci_mmcfg_early_init();
+
+#ifdef CONFIG_PCI_OLPC
+ pci_olpc_init();
#endif
- if (raw_pci_ops)
- return 0;
#ifdef CONFIG_PCI_BIOS
pci_pcbios_init();
#endif
@@ -28,7 +29,7 @@
#ifdef CONFIG_PCI_DIRECT
pci_direct_init(type);
#endif
- if (!raw_pci_ops)
+ if (!raw_pci_ops && !raw_pci_ext_ops)
printk(KERN_ERR
"PCI: Fatal: No config space access function found\n");
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c
index 579745c..0908fca 100644
--- a/arch/x86/pci/irq.c
+++ b/arch/x86/pci/irq.c
@@ -136,9 +136,11 @@
busmap[e->bus] = 1;
}
for(i = 1; i < 256; i++) {
+ int node;
if (!busmap[i] || pci_find_bus(0, i))
continue;
- if (pci_scan_bus_with_sysdata(i))
+ node = get_mp_bus_to_node(i);
+ if (pci_scan_bus_on_node(i, &pci_root_ops, node))
printk(KERN_INFO "PCI: Discovered primary peer "
"bus %02x [IRQ]\n", i);
}
diff --git a/arch/x86/pci/k8-bus_64.c b/arch/x86/pci/k8-bus_64.c
index 9cc813e..ab6d4b1 100644
--- a/arch/x86/pci/k8-bus_64.c
+++ b/arch/x86/pci/k8-bus_64.c
@@ -1,83 +1,536 @@
#include <linux/init.h>
#include <linux/pci.h>
+#include <asm/pci-direct.h>
#include <asm/mpspec.h>
#include <linux/cpumask.h>
+#include <linux/topology.h>
/*
* This discovers the pcibus <-> node mapping on AMD K8.
- *
- * RED-PEN need to call this again on PCI hotplug
- * RED-PEN empty cpus get reported wrong
+ * also get peer root bus resource for io,mmio
*/
-#define NODE_ID_REGISTER 0x60
-#define NODE_ID(dword) (dword & 0x07)
-#define LDT_BUS_NUMBER_REGISTER_0 0x94
-#define LDT_BUS_NUMBER_REGISTER_1 0xB4
-#define LDT_BUS_NUMBER_REGISTER_2 0xD4
-#define NR_LDT_BUS_NUMBER_REGISTERS 3
-#define SECONDARY_LDT_BUS_NUMBER(dword) ((dword >> 8) & 0xFF)
-#define SUBORDINATE_LDT_BUS_NUMBER(dword) ((dword >> 16) & 0xFF)
-#define PCI_DEVICE_ID_K8HTCONFIG 0x1100
+
+/*
+ * sub bus (transparent) will use entres from 3 to store extra from root,
+ * so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES?
+ */
+#define RES_NUM 16
+struct pci_root_info {
+ char name[12];
+ unsigned int res_num;
+ struct resource res[RES_NUM];
+ int bus_min;
+ int bus_max;
+ int node;
+ int link;
+};
+
+/* 4 at this time, it may become to 32 */
+#define PCI_ROOT_NR 4
+static int pci_root_num;
+static struct pci_root_info pci_root_info[PCI_ROOT_NR];
+
+#ifdef CONFIG_NUMA
+
+#define BUS_NR 256
+
+static int mp_bus_to_node[BUS_NR];
+
+void set_mp_bus_to_node(int busnum, int node)
+{
+ if (busnum >= 0 && busnum < BUS_NR)
+ mp_bus_to_node[busnum] = node;
+}
+
+int get_mp_bus_to_node(int busnum)
+{
+ int node = -1;
+
+ if (busnum < 0 || busnum > (BUS_NR - 1))
+ return node;
+
+ node = mp_bus_to_node[busnum];
+
+ /*
+ * let numa_node_id to decide it later in dma_alloc_pages
+ * if there is no ram on that node
+ */
+ if (node != -1 && !node_online(node))
+ node = -1;
+
+ return node;
+}
+#endif
+
+void set_pci_bus_resources_arch_default(struct pci_bus *b)
+{
+ int i;
+ int j;
+ struct pci_root_info *info;
+
+ /* if only one root bus, don't need to anything */
+ if (pci_root_num < 2)
+ return;
+
+ for (i = 0; i < pci_root_num; i++) {
+ if (pci_root_info[i].bus_min == b->number)
+ break;
+ }
+
+ if (i == pci_root_num)
+ return;
+
+ info = &pci_root_info[i];
+ for (j = 0; j < info->res_num; j++) {
+ struct resource *res;
+ struct resource *root;
+
+ res = &info->res[j];
+ b->resource[j] = res;
+ if (res->flags & IORESOURCE_IO)
+ root = &ioport_resource;
+ else
+ root = &iomem_resource;
+ insert_resource(root, res);
+ }
+}
+
+#define RANGE_NUM 16
+
+struct res_range {
+ size_t start;
+ size_t end;
+};
+
+static void __init update_range(struct res_range *range, size_t start,
+ size_t end)
+{
+ int i;
+ int j;
+
+ for (j = 0; j < RANGE_NUM; j++) {
+ if (!range[j].end)
+ continue;
+
+ if (start <= range[j].start && end >= range[j].end) {
+ range[j].start = 0;
+ range[j].end = 0;
+ continue;
+ }
+
+ if (start <= range[j].start && end < range[j].end && range[j].start < end + 1) {
+ range[j].start = end + 1;
+ continue;
+ }
+
+
+ if (start > range[j].start && end >= range[j].end && range[j].end > start - 1) {
+ range[j].end = start - 1;
+ continue;
+ }
+
+ if (start > range[j].start && end < range[j].end) {
+ /* find the new spare */
+ for (i = 0; i < RANGE_NUM; i++) {
+ if (range[i].end == 0)
+ break;
+ }
+ if (i < RANGE_NUM) {
+ range[i].end = range[j].end;
+ range[i].start = end + 1;
+ } else {
+ printk(KERN_ERR "run of slot in ranges\n");
+ }
+ range[j].end = start - 1;
+ continue;
+ }
+ }
+}
+
+static void __init update_res(struct pci_root_info *info, size_t start,
+ size_t end, unsigned long flags, int merge)
+{
+ int i;
+ struct resource *res;
+
+ if (!merge)
+ goto addit;
+
+ /* try to merge it with old one */
+ for (i = 0; i < info->res_num; i++) {
+ size_t final_start, final_end;
+ size_t common_start, common_end;
+
+ res = &info->res[i];
+ if (res->flags != flags)
+ continue;
+
+ common_start = max((size_t)res->start, start);
+ common_end = min((size_t)res->end, end);
+ if (common_start > common_end + 1)
+ continue;
+
+ final_start = min((size_t)res->start, start);
+ final_end = max((size_t)res->end, end);
+
+ res->start = final_start;
+ res->end = final_end;
+ return;
+ }
+
+addit:
+
+ /* need to add that */
+ if (info->res_num >= RES_NUM)
+ return;
+
+ res = &info->res[info->res_num];
+ res->name = info->name;
+ res->flags = flags;
+ res->start = start;
+ res->end = end;
+ res->child = NULL;
+ info->res_num++;
+}
+
+struct pci_hostbridge_probe {
+ u32 bus;
+ u32 slot;
+ u32 vendor;
+ u32 device;
+};
+
+static struct pci_hostbridge_probe pci_probes[] __initdata = {
+ { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1100 },
+ { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
+ { 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 },
+ { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 },
+};
+
+static u64 __initdata fam10h_mmconf_start;
+static u64 __initdata fam10h_mmconf_end;
+static void __init get_pci_mmcfg_amd_fam10h_range(void)
+{
+ u32 address;
+ u64 base, msr;
+ unsigned segn_busn_bits;
+
+ /* assume all cpus from fam10h have mmconf */
+ if (boot_cpu_data.x86 < 0x10)
+ return;
+
+ address = MSR_FAM10H_MMIO_CONF_BASE;
+ rdmsrl(address, msr);
+
+ /* mmconfig is not enable */
+ if (!(msr & FAM10H_MMIO_CONF_ENABLE))
+ return;
+
+ base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
+
+ segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
+ FAM10H_MMIO_CONF_BUSRANGE_MASK;
+
+ fam10h_mmconf_start = base;
+ fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1;
+}
/**
- * fill_mp_bus_to_cpumask()
+ * early_fill_mp_bus_to_node()
+ * called before pcibios_scan_root and pci_scan_bus
* fills the mp_bus_to_cpumask array based according to the LDT Bus Number
* Registers found in the K8 northbridge
*/
-__init static int
-fill_mp_bus_to_cpumask(void)
+static int __init early_fill_mp_bus_info(void)
{
- struct pci_dev *nb_dev = NULL;
- int i, j;
- u32 ldtbus, nid;
- static int lbnr[3] = {
- LDT_BUS_NUMBER_REGISTER_0,
- LDT_BUS_NUMBER_REGISTER_1,
- LDT_BUS_NUMBER_REGISTER_2
- };
+ int i;
+ int j;
+ unsigned bus;
+ unsigned slot;
+ int found;
+ int node;
+ int link;
+ int def_node;
+ int def_link;
+ struct pci_root_info *info;
+ u32 reg;
+ struct resource *res;
+ size_t start;
+ size_t end;
+ struct res_range range[RANGE_NUM];
+ u64 val;
+ u32 address;
- while ((nb_dev = pci_get_device(PCI_VENDOR_ID_AMD,
- PCI_DEVICE_ID_K8HTCONFIG, nb_dev))) {
- pci_read_config_dword(nb_dev, NODE_ID_REGISTER, &nid);
+#ifdef CONFIG_NUMA
+ for (i = 0; i < BUS_NR; i++)
+ mp_bus_to_node[i] = -1;
+#endif
- for (i = 0; i < NR_LDT_BUS_NUMBER_REGISTERS; i++) {
- pci_read_config_dword(nb_dev, lbnr[i], &ldtbus);
- /*
- * if there are no busses hanging off of the current
- * ldt link then both the secondary and subordinate
- * bus number fields are set to 0.
- *
- * RED-PEN
- * This is slightly broken because it assumes
- * HT node IDs == Linux node ids, which is not always
- * true. However it is probably mostly true.
- */
- if (!(SECONDARY_LDT_BUS_NUMBER(ldtbus) == 0
- && SUBORDINATE_LDT_BUS_NUMBER(ldtbus) == 0)) {
- for (j = SECONDARY_LDT_BUS_NUMBER(ldtbus);
- j <= SUBORDINATE_LDT_BUS_NUMBER(ldtbus);
- j++) {
- struct pci_bus *bus;
- struct pci_sysdata *sd;
+ if (!early_pci_allowed())
+ return -1;
- long node = NODE_ID(nid);
- /* Algorithm a bit dumb, but
- it shouldn't matter here */
- bus = pci_find_bus(0, j);
- if (!bus)
- continue;
- if (!node_online(node))
- node = 0;
+ found = 0;
+ for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
+ u32 id;
+ u16 device;
+ u16 vendor;
- sd = bus->sysdata;
- sd->node = node;
- }
+ bus = pci_probes[i].bus;
+ slot = pci_probes[i].slot;
+ id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
+
+ vendor = id & 0xffff;
+ device = (id>>16) & 0xffff;
+ if (pci_probes[i].vendor == vendor &&
+ pci_probes[i].device == device) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return 0;
+
+ pci_root_num = 0;
+ for (i = 0; i < 4; i++) {
+ int min_bus;
+ int max_bus;
+ reg = read_pci_config(bus, slot, 1, 0xe0 + (i << 2));
+
+ /* Check if that register is enabled for bus range */
+ if ((reg & 7) != 3)
+ continue;
+
+ min_bus = (reg >> 16) & 0xff;
+ max_bus = (reg >> 24) & 0xff;
+ node = (reg >> 4) & 0x07;
+#ifdef CONFIG_NUMA
+ for (j = min_bus; j <= max_bus; j++)
+ mp_bus_to_node[j] = (unsigned char) node;
+#endif
+ link = (reg >> 8) & 0x03;
+
+ info = &pci_root_info[pci_root_num];
+ info->bus_min = min_bus;
+ info->bus_max = max_bus;
+ info->node = node;
+ info->link = link;
+ sprintf(info->name, "PCI Bus #%02x", min_bus);
+ pci_root_num++;
+ }
+
+ /* get the default node and link for left over res */
+ reg = read_pci_config(bus, slot, 0, 0x60);
+ def_node = (reg >> 8) & 0x07;
+ reg = read_pci_config(bus, slot, 0, 0x64);
+ def_link = (reg >> 8) & 0x03;
+
+ memset(range, 0, sizeof(range));
+ range[0].end = 0xffff;
+ /* io port resource */
+ for (i = 0; i < 4; i++) {
+ reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3));
+ if (!(reg & 3))
+ continue;
+
+ start = reg & 0xfff000;
+ reg = read_pci_config(bus, slot, 1, 0xc4 + (i << 3));
+ node = reg & 0x07;
+ link = (reg >> 4) & 0x03;
+ end = (reg & 0xfff000) | 0xfff;
+
+ /* find the position */
+ for (j = 0; j < pci_root_num; j++) {
+ info = &pci_root_info[j];
+ if (info->node == node && info->link == link)
+ break;
+ }
+ if (j == pci_root_num)
+ continue; /* not found */
+
+ info = &pci_root_info[j];
+ printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n",
+ node, link, (u64)start, (u64)end);
+
+ /* kernel only handle 16 bit only */
+ if (end > 0xffff)
+ end = 0xffff;
+ update_res(info, start, end, IORESOURCE_IO, 1);
+ update_range(range, start, end);
+ }
+ /* add left over io port range to def node/link, [0, 0xffff] */
+ /* find the position */
+ for (j = 0; j < pci_root_num; j++) {
+ info = &pci_root_info[j];
+ if (info->node == def_node && info->link == def_link)
+ break;
+ }
+ if (j < pci_root_num) {
+ info = &pci_root_info[j];
+ for (i = 0; i < RANGE_NUM; i++) {
+ if (!range[i].end)
+ continue;
+
+ update_res(info, range[i].start, range[i].end,
+ IORESOURCE_IO, 1);
+ }
+ }
+
+ memset(range, 0, sizeof(range));
+ /* 0xfd00000000-0xffffffffff for HT */
+ range[0].end = (0xfdULL<<32) - 1;
+
+ /* need to take out [0, TOM) for RAM*/
+ address = MSR_K8_TOP_MEM1;
+ rdmsrl(address, val);
+ end = (val & 0xffffff8000000ULL);
+ printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20);
+ if (end < (1ULL<<32))
+ update_range(range, 0, end - 1);
+
+ /* get mmconfig */
+ get_pci_mmcfg_amd_fam10h_range();
+ /* need to take out mmconf range */
+ if (fam10h_mmconf_end) {
+ printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end);
+ update_range(range, fam10h_mmconf_start, fam10h_mmconf_end);
+ }
+
+ /* mmio resource */
+ for (i = 0; i < 8; i++) {
+ reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
+ if (!(reg & 3))
+ continue;
+
+ start = reg & 0xffffff00; /* 39:16 on 31:8*/
+ start <<= 8;
+ reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
+ node = reg & 0x07;
+ link = (reg >> 4) & 0x03;
+ end = (reg & 0xffffff00);
+ end <<= 8;
+ end |= 0xffff;
+
+ /* find the position */
+ for (j = 0; j < pci_root_num; j++) {
+ info = &pci_root_info[j];
+ if (info->node == node && info->link == link)
+ break;
+ }
+ if (j == pci_root_num)
+ continue; /* not found */
+
+ info = &pci_root_info[j];
+
+ printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]",
+ node, link, (u64)start, (u64)end);
+ /*
+ * some sick allocation would have range overlap with fam10h
+ * mmconf range, so need to update start and end.
+ */
+ if (fam10h_mmconf_end) {
+ int changed = 0;
+ u64 endx = 0;
+ if (start >= fam10h_mmconf_start &&
+ start <= fam10h_mmconf_end) {
+ start = fam10h_mmconf_end + 1;
+ changed = 1;
}
+
+ if (end >= fam10h_mmconf_start &&
+ end <= fam10h_mmconf_end) {
+ end = fam10h_mmconf_start - 1;
+ changed = 1;
+ }
+
+ if (start < fam10h_mmconf_start &&
+ end > fam10h_mmconf_end) {
+ /* we got a hole */
+ endx = fam10h_mmconf_start - 1;
+ update_res(info, start, endx, IORESOURCE_MEM, 0);
+ update_range(range, start, endx);
+ printk(KERN_CONT " ==> [%llx, %llx]", (u64)start, endx);
+ start = fam10h_mmconf_end + 1;
+ changed = 1;
+ }
+ if (changed) {
+ if (start <= end) {
+ printk(KERN_CONT " %s [%llx, %llx]", endx?"and":"==>", (u64)start, (u64)end);
+ } else {
+ printk(KERN_CONT "%s\n", endx?"":" ==> none");
+ continue;
+ }
+ }
+ }
+
+ update_res(info, start, end, IORESOURCE_MEM, 1);
+ update_range(range, start, end);
+ printk(KERN_CONT "\n");
+ }
+
+ /* need to take out [4G, TOM2) for RAM*/
+ /* SYS_CFG */
+ address = MSR_K8_SYSCFG;
+ rdmsrl(address, val);
+ /* TOP_MEM2 is enabled? */
+ if (val & (1<<21)) {
+ /* TOP_MEM2 */
+ address = MSR_K8_TOP_MEM2;
+ rdmsrl(address, val);
+ end = (val & 0xffffff8000000ULL);
+ printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20);
+ update_range(range, 1ULL<<32, end - 1);
+ }
+
+ /*
+ * add left over mmio range to def node/link ?
+ * that is tricky, just record range in from start_min to 4G
+ */
+ for (j = 0; j < pci_root_num; j++) {
+ info = &pci_root_info[j];
+ if (info->node == def_node && info->link == def_link)
+ break;
+ }
+ if (j < pci_root_num) {
+ info = &pci_root_info[j];
+
+ for (i = 0; i < RANGE_NUM; i++) {
+ if (!range[i].end)
+ continue;
+
+ update_res(info, range[i].start, range[i].end,
+ IORESOURCE_MEM, 1);
+ }
+ }
+
+#ifdef CONFIG_NUMA
+ for (i = 0; i < BUS_NR; i++) {
+ node = mp_bus_to_node[i];
+ if (node >= 0)
+ printk(KERN_DEBUG "bus: %02x to node: %02x\n", i, node);
+ }
+#endif
+
+ for (i = 0; i < pci_root_num; i++) {
+ int res_num;
+ int busnum;
+
+ info = &pci_root_info[i];
+ res_num = info->res_num;
+ busnum = info->bus_min;
+ printk(KERN_DEBUG "bus: [%02x,%02x] on node %x link %x\n",
+ info->bus_min, info->bus_max, info->node, info->link);
+ for (j = 0; j < res_num; j++) {
+ res = &info->res[j];
+ printk(KERN_DEBUG "bus: %02x index %x %s: [%llx, %llx]\n",
+ busnum, j,
+ (res->flags & IORESOURCE_IO)?"io port":"mmio",
+ res->start, res->end);
}
}
return 0;
}
-fs_initcall(fill_mp_bus_to_cpumask);
+postcore_initcall(early_fill_mp_bus_info);
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index e041ced..a67921c 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -12,6 +12,7 @@
static void __devinit pcibios_fixup_peer_bridges(void)
{
int n, devfn;
+ long node;
if (pcibios_last_bus <= 0 || pcibios_last_bus >= 0xff)
return;
@@ -21,12 +22,13 @@
u32 l;
if (pci_find_bus(0, n))
continue;
+ node = get_mp_bus_to_node(n);
for (devfn = 0; devfn < 256; devfn += 8) {
if (!raw_pci_read(0, n, devfn, PCI_VENDOR_ID, 2, &l) &&
l != 0x0000 && l != 0xffff) {
DBG("Found device at %02x:%02x [%04x]\n", n, devfn, l);
printk(KERN_INFO "PCI: Discovered peer bus %02x\n", n);
- pci_scan_bus_with_sysdata(n);
+ pci_scan_bus_on_node(n, &pci_root_ops, node);
break;
}
}
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 8d54df4..0cfebec 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -28,7 +28,7 @@
static const char __init *pci_mmcfg_e7520(void)
{
u32 win;
- pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0xce, 2, &win);
+ raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win);
win = win & 0xf000;
if(win == 0x0000 || win == 0xf000)
@@ -53,7 +53,7 @@
pci_mmcfg_config_num = 1;
- pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0x48, 4, &pciexbar);
+ raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar);
/* Enable bit */
if (!(pciexbar & 1))
@@ -100,33 +100,102 @@
return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
}
+static const char __init *pci_mmcfg_amd_fam10h(void)
+{
+ u32 low, high, address;
+ u64 base, msr;
+ int i;
+ unsigned segnbits = 0, busnbits;
+
+ if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF))
+ return NULL;
+
+ address = MSR_FAM10H_MMIO_CONF_BASE;
+ if (rdmsr_safe(address, &low, &high))
+ return NULL;
+
+ msr = high;
+ msr <<= 32;
+ msr |= low;
+
+ /* mmconfig is not enable */
+ if (!(msr & FAM10H_MMIO_CONF_ENABLE))
+ return NULL;
+
+ base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT);
+
+ busnbits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) &
+ FAM10H_MMIO_CONF_BUSRANGE_MASK;
+
+ /*
+ * only handle bus 0 ?
+ * need to skip it
+ */
+ if (!busnbits)
+ return NULL;
+
+ if (busnbits > 8) {
+ segnbits = busnbits - 8;
+ busnbits = 8;
+ }
+
+ pci_mmcfg_config_num = (1 << segnbits);
+ pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) *
+ pci_mmcfg_config_num, GFP_KERNEL);
+ if (!pci_mmcfg_config)
+ return NULL;
+
+ for (i = 0; i < (1 << segnbits); i++) {
+ pci_mmcfg_config[i].address = base + (1<<28) * i;
+ pci_mmcfg_config[i].pci_segment = i;
+ pci_mmcfg_config[i].start_bus_number = 0;
+ pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
+ }
+
+ return "AMD Family 10h NB";
+}
+
struct pci_mmcfg_hostbridge_probe {
+ u32 bus;
+ u32 devfn;
u32 vendor;
u32 device;
const char *(*probe)(void);
};
static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
+ { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
+ { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82945G_HB, pci_mmcfg_intel_945 },
+ { 0, PCI_DEVFN(0x18, 0), PCI_VENDOR_ID_AMD,
+ 0x1200, pci_mmcfg_amd_fam10h },
+ { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
+ 0x1200, pci_mmcfg_amd_fam10h },
};
static int __init pci_mmcfg_check_hostbridge(void)
{
u32 l;
+ u32 bus, devfn;
u16 vendor, device;
int i;
const char *name;
- pci_direct_conf1.read(0, 0, PCI_DEVFN(0,0), 0, 4, &l);
- vendor = l & 0xffff;
- device = (l >> 16) & 0xffff;
+ if (!raw_pci_ops)
+ return 0;
pci_mmcfg_config_num = 0;
pci_mmcfg_config = NULL;
name = NULL;
for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
+ bus = pci_mmcfg_probes[i].bus;
+ devfn = pci_mmcfg_probes[i].devfn;
+ raw_pci_ops->read(0, bus, devfn, 0, 4, &l);
+ vendor = l & 0xffff;
+ device = (l >> 16) & 0xffff;
+
if (pci_mmcfg_probes[i].vendor == vendor &&
pci_mmcfg_probes[i].device == device)
name = pci_mmcfg_probes[i].probe();
@@ -173,9 +242,78 @@
pci_mmcfg_resources_inserted = 1;
}
-static void __init pci_mmcfg_reject_broken(int type)
+static acpi_status __init check_mcfg_resource(struct acpi_resource *res,
+ void *data)
+{
+ struct resource *mcfg_res = data;
+ struct acpi_resource_address64 address;
+ acpi_status status;
+
+ if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
+ struct acpi_resource_fixed_memory32 *fixmem32 =
+ &res->data.fixed_memory32;
+ if (!fixmem32)
+ return AE_OK;
+ if ((mcfg_res->start >= fixmem32->address) &&
+ (mcfg_res->end < (fixmem32->address +
+ fixmem32->address_length))) {
+ mcfg_res->flags = 1;
+ return AE_CTRL_TERMINATE;
+ }
+ }
+ if ((res->type != ACPI_RESOURCE_TYPE_ADDRESS32) &&
+ (res->type != ACPI_RESOURCE_TYPE_ADDRESS64))
+ return AE_OK;
+
+ status = acpi_resource_to_address64(res, &address);
+ if (ACPI_FAILURE(status) ||
+ (address.address_length <= 0) ||
+ (address.resource_type != ACPI_MEMORY_RANGE))
+ return AE_OK;
+
+ if ((mcfg_res->start >= address.minimum) &&
+ (mcfg_res->end < (address.minimum + address.address_length))) {
+ mcfg_res->flags = 1;
+ return AE_CTRL_TERMINATE;
+ }
+ return AE_OK;
+}
+
+static acpi_status __init find_mboard_resource(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ struct resource *mcfg_res = context;
+
+ acpi_walk_resources(handle, METHOD_NAME__CRS,
+ check_mcfg_resource, context);
+
+ if (mcfg_res->flags)
+ return AE_CTRL_TERMINATE;
+
+ return AE_OK;
+}
+
+static int __init is_acpi_reserved(unsigned long start, unsigned long end)
+{
+ struct resource mcfg_res;
+
+ mcfg_res.start = start;
+ mcfg_res.end = end;
+ mcfg_res.flags = 0;
+
+ acpi_get_devices("PNP0C01", find_mboard_resource, &mcfg_res, NULL);
+
+ if (!mcfg_res.flags)
+ acpi_get_devices("PNP0C02", find_mboard_resource, &mcfg_res,
+ NULL);
+
+ return mcfg_res.flags;
+}
+
+static void __init pci_mmcfg_reject_broken(int early)
{
typeof(pci_mmcfg_config[0]) *cfg;
+ int i;
if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
@@ -184,51 +322,80 @@
cfg = &pci_mmcfg_config[0];
- /*
- * Handle more broken MCFG tables on Asus etc.
- * They only contain a single entry for bus 0-0.
- */
- if (pci_mmcfg_config_num == 1 &&
- cfg->pci_segment == 0 &&
- (cfg->start_bus_number | cfg->end_bus_number) == 0) {
- printk(KERN_ERR "PCI: start and end of bus number is 0. "
- "Rejected as broken MCFG.\n");
- goto reject;
+ for (i = 0; i < pci_mmcfg_config_num; i++) {
+ int valid = 0;
+ u32 size = (cfg->end_bus_number + 1) << 20;
+ cfg = &pci_mmcfg_config[i];
+ printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx "
+ "segment %hu buses %u - %u\n",
+ i, (unsigned long)cfg->address, cfg->pci_segment,
+ (unsigned int)cfg->start_bus_number,
+ (unsigned int)cfg->end_bus_number);
+
+ if (!early &&
+ is_acpi_reserved(cfg->address, cfg->address + size - 1)) {
+ printk(KERN_NOTICE "PCI: MCFG area at %Lx reserved "
+ "in ACPI motherboard resources\n",
+ cfg->address);
+ valid = 1;
+ }
+
+ if (valid)
+ continue;
+
+ if (!early)
+ printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
+ " reserved in ACPI motherboard resources\n",
+ cfg->address);
+ /* Don't try to do this check unless configuration
+ type 1 is available. how about type 2 ?*/
+ if (raw_pci_ops && e820_all_mapped(cfg->address,
+ cfg->address + size - 1,
+ E820_RESERVED)) {
+ printk(KERN_NOTICE
+ "PCI: MCFG area at %Lx reserved in E820\n",
+ cfg->address);
+ valid = 1;
+ }
+
+ if (!valid)
+ goto reject;
}
- /*
- * Only do this check when type 1 works. If it doesn't work
- * assume we run on a Mac and always use MCFG
- */
- if (type == 1 && !e820_all_mapped(cfg->address,
- cfg->address + MMCONFIG_APER_MIN,
- E820_RESERVED)) {
- printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not"
- " E820-reserved\n", cfg->address);
- goto reject;
- }
return;
reject:
printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
+ pci_mmcfg_arch_free();
kfree(pci_mmcfg_config);
pci_mmcfg_config = NULL;
pci_mmcfg_config_num = 0;
}
-void __init pci_mmcfg_init(int type)
-{
- int known_bridge = 0;
+static int __initdata known_bridge;
+void __init __pci_mmcfg_init(int early)
+{
+ /* MMCONFIG disabled */
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return;
- if (type == 1 && pci_mmcfg_check_hostbridge())
- known_bridge = 1;
+ /* MMCONFIG already enabled */
+ if (!early && !(pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF))
+ return;
+
+ /* for late to exit */
+ if (known_bridge)
+ return;
+
+ if (early) {
+ if (pci_mmcfg_check_hostbridge())
+ known_bridge = 1;
+ }
if (!known_bridge) {
acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
- pci_mmcfg_reject_broken(type);
+ pci_mmcfg_reject_broken(early);
}
if ((pci_mmcfg_config_num == 0) ||
@@ -249,6 +416,16 @@
}
}
+void __init pci_mmcfg_early_init(void)
+{
+ __pci_mmcfg_init(1);
+}
+
+void __init pci_mmcfg_late_init(void)
+{
+ __pci_mmcfg_init(0);
+}
+
static int __init pci_mmcfg_late_insert_resources(void)
{
/*
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 081816a..f3c761d 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -136,3 +136,7 @@
raw_pci_ext_ops = &pci_mmcfg;
return 1;
}
+
+void __init pci_mmcfg_arch_free(void)
+{
+}
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index 9207fd4..a199416 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -127,7 +127,7 @@
int __init pci_mmcfg_arch_init(void)
{
int i;
- pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) *
+ pci_mmcfg_virt = kzalloc(sizeof(*pci_mmcfg_virt) *
pci_mmcfg_config_num, GFP_KERNEL);
if (pci_mmcfg_virt == NULL) {
printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
@@ -141,9 +141,29 @@
printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
"segment %d\n",
pci_mmcfg_config[i].pci_segment);
+ pci_mmcfg_arch_free();
return 0;
}
}
raw_pci_ext_ops = &pci_mmcfg;
return 1;
}
+
+void __init pci_mmcfg_arch_free(void)
+{
+ int i;
+
+ if (pci_mmcfg_virt == NULL)
+ return;
+
+ for (i = 0; i < pci_mmcfg_config_num; ++i) {
+ if (pci_mmcfg_virt[i].virt) {
+ iounmap(pci_mmcfg_virt[i].virt);
+ pci_mmcfg_virt[i].virt = NULL;
+ pci_mmcfg_virt[i].cfg = NULL;
+ }
+ }
+
+ kfree(pci_mmcfg_virt);
+ pci_mmcfg_virt = NULL;
+}
diff --git a/arch/x86/pci/mp_bus_to_node.c b/arch/x86/pci/mp_bus_to_node.c
new file mode 100644
index 0000000..0229439
--- /dev/null
+++ b/arch/x86/pci/mp_bus_to_node.c
@@ -0,0 +1,23 @@
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/topology.h>
+
+#define BUS_NR 256
+
+static unsigned char mp_bus_to_node[BUS_NR];
+
+void set_mp_bus_to_node(int busnum, int node)
+{
+ if (busnum >= 0 && busnum < BUS_NR)
+ mp_bus_to_node[busnum] = (unsigned char) node;
+}
+
+int get_mp_bus_to_node(int busnum)
+{
+ int node;
+
+ if (busnum < 0 || busnum > (BUS_NR - 1))
+ return 0;
+ node = mp_bus_to_node[busnum];
+ return node;
+}
diff --git a/arch/x86/pci/olpc.c b/arch/x86/pci/olpc.c
new file mode 100644
index 0000000..5e76365
--- /dev/null
+++ b/arch/x86/pci/olpc.c
@@ -0,0 +1,313 @@
+/*
+ * Low-level PCI config space access for OLPC systems who lack the VSA
+ * PCI virtualization software.
+ *
+ * Copyright © 2006 Advanced Micro Devices, 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.
+ *
+ * The AMD Geode chipset (ie: GX2 processor, cs5536 I/O companion device)
+ * has some I/O functions (display, southbridge, sound, USB HCIs, etc)
+ * that more or less behave like PCI devices, but the hardware doesn't
+ * directly implement the PCI configuration space headers. AMD provides
+ * "VSA" (Virtual System Architecture) software that emulates PCI config
+ * space for these devices, by trapping I/O accesses to PCI config register
+ * (CF8/CFC) and running some code in System Management Mode interrupt state.
+ * On the OLPC platform, we don't want to use that VSA code because
+ * (a) it slows down suspend/resume, and (b) recompiling it requires special
+ * compilers that are hard to get. So instead of letting the complex VSA
+ * code simulate the PCI config registers for the on-chip devices, we
+ * just simulate them the easy way, by inserting the code into the
+ * pci_write_config and pci_read_config path. Most of the config registers
+ * are read-only anyway, so the bulk of the simulation is just table lookup.
+ */
+
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <asm/olpc.h>
+#include <asm/geode.h>
+#include "pci.h"
+
+/*
+ * In the tables below, the first two line (8 longwords) are the
+ * size masks that are used when the higher level PCI code determines
+ * the size of the region by writing ~0 to a base address register
+ * and reading back the result.
+ *
+ * The following lines are the values that are read during normal
+ * PCI config access cycles, i.e. not after just having written
+ * ~0 to a base address register.
+ */
+
+static const uint32_t lxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+
+ 0x281022, 0x2200005, 0x6000021, 0x80f808, /* AMD Vendor ID */
+ 0x0, 0x0, 0x0, 0x0, /* No virtual registers, hence no BAR */
+ 0x0, 0x0, 0x0, 0x28100b,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+};
+
+static const uint32_t gxnb_hdr[] = { /* dev 1 function 0 - devfn = 8 */
+ 0xfffffffd, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+
+ 0x28100b, 0x2200005, 0x6000021, 0x80f808, /* NSC Vendor ID */
+ 0xac1d, 0x0, 0x0, 0x0, /* I/O BAR - base of virtual registers */
+ 0x0, 0x0, 0x0, 0x28100b,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+};
+
+static const uint32_t lxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
+ 0xff000008, 0xffffc000, 0xffffc000, 0xffffc000,
+ 0xffffc000, 0x0, 0x0, 0x0,
+
+ 0x20811022, 0x2200003, 0x3000000, 0x0, /* AMD Vendor ID */
+ 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */
+ 0xfe00c000, 0x0, 0x0, 0x30100b, /* VIP */
+ 0x0, 0x0, 0x0, 0x10e, /* INTA, IRQ14 for graphics accel */
+ 0x0, 0x0, 0x0, 0x0,
+ 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */
+ 0x0, 0x0, 0x0, 0x0,
+};
+
+static const uint32_t gxfb_hdr[] = { /* dev 1 function 1 - devfn = 9 */
+ 0xff800008, 0xffffc000, 0xffffc000, 0xffffc000,
+ 0x0, 0x0, 0x0, 0x0,
+
+ 0x30100b, 0x2200003, 0x3000000, 0x0, /* NSC Vendor ID */
+ 0xfd000000, 0xfe000000, 0xfe004000, 0xfe008000, /* FB, GP, VG, DF */
+ 0x0, 0x0, 0x0, 0x30100b,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x3d0, 0x3c0, 0xa0000, 0x0, /* VG IO, VG IO, EGA FB, MONO FB */
+ 0x0, 0x0, 0x0, 0x0,
+};
+
+static const uint32_t aes_hdr[] = { /* dev 1 function 2 - devfn = 0xa */
+ 0xffffc000, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+
+ 0x20821022, 0x2a00006, 0x10100000, 0x8, /* NSC Vendor ID */
+ 0xfe010000, 0x0, 0x0, 0x0, /* AES registers */
+ 0x0, 0x0, 0x0, 0x20821022,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+};
+
+
+static const uint32_t isa_hdr[] = { /* dev f function 0 - devfn = 78 */
+ 0xfffffff9, 0xffffff01, 0xffffffc1, 0xffffffe1,
+ 0xffffff81, 0xffffffc1, 0x0, 0x0,
+
+ 0x20901022, 0x2a00049, 0x6010003, 0x802000,
+ 0x18b1, 0x1001, 0x1801, 0x1881, /* SMB-8 GPIO-256 MFGPT-64 IRQ-32 */
+ 0x1401, 0x1841, 0x0, 0x20901022, /* PMS-128 ACPI-64 */
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0xaa5b, /* IRQ steering */
+ 0x0, 0x0, 0x0, 0x0,
+};
+
+static const uint32_t ac97_hdr[] = { /* dev f function 3 - devfn = 7b */
+ 0xffffff81, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+
+ 0x20931022, 0x2a00041, 0x4010001, 0x0,
+ 0x1481, 0x0, 0x0, 0x0, /* I/O BAR-128 */
+ 0x0, 0x0, 0x0, 0x20931022,
+ 0x0, 0x0, 0x0, 0x205, /* IntB, IRQ5 */
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+};
+
+static const uint32_t ohci_hdr[] = { /* dev f function 4 - devfn = 7c */
+ 0xfffff000, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+
+ 0x20941022, 0x2300006, 0xc031002, 0x0,
+ 0xfe01a000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */
+ 0x0, 0x0, 0x0, 0x20941022,
+ 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */
+ 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O,
+ 44 is mask 8103 (power control) */
+ 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+};
+
+static const uint32_t ehci_hdr[] = { /* dev f function 4 - devfn = 7d */
+ 0xfffff000, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
+
+ 0x20951022, 0x2300006, 0xc032002, 0x0,
+ 0xfe01b000, 0x0, 0x0, 0x0, /* MEMBAR-1000 */
+ 0x0, 0x0, 0x0, 0x20951022,
+ 0x0, 0x40, 0x0, 0x40a, /* CapPtr INT-D, IRQA */
+ 0xc8020001, 0x0, 0x0, 0x0, /* Capabilities - 40 is R/O, 44 is
+ mask 8103 (power control) */
+#if 0
+ 0x1, 0x40080000, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */
+#endif
+ 0x01000001, 0x0, 0x0, 0x0, /* EECP - see EHCI spec section 2.1.7 */
+ 0x2020, 0x0, 0x0, 0x0, /* (EHCI page 8) 60 SBRN (R/O),
+ 61 FLADJ (R/W), PORTWAKECAP */
+};
+
+static uint32_t ff_loc = ~0;
+static uint32_t zero_loc;
+static int bar_probing; /* Set after a write of ~0 to a BAR */
+static int is_lx;
+
+#define NB_SLOT 0x1 /* Northbridge - GX chip - Device 1 */
+#define SB_SLOT 0xf /* Southbridge - CS5536 chip - Device F */
+
+static int is_simulated(unsigned int bus, unsigned int devfn)
+{
+ return (!bus && ((PCI_SLOT(devfn) == NB_SLOT) ||
+ (PCI_SLOT(devfn) == SB_SLOT)));
+}
+
+static uint32_t *hdr_addr(const uint32_t *hdr, int reg)
+{
+ uint32_t addr;
+
+ /*
+ * This is a little bit tricky. The header maps consist of
+ * 0x20 bytes of size masks, followed by 0x70 bytes of header data.
+ * In the normal case, when not probing a BAR's size, we want
+ * to access the header data, so we add 0x20 to the reg offset,
+ * thus skipping the size mask area.
+ * In the BAR probing case, we want to access the size mask for
+ * the BAR, so we subtract 0x10 (the config header offset for
+ * BAR0), and don't skip the size mask area.
+ */
+
+ addr = (uint32_t)hdr + reg + (bar_probing ? -0x10 : 0x20);
+
+ bar_probing = 0;
+ return (uint32_t *)addr;
+}
+
+static int pci_olpc_read(unsigned int seg, unsigned int bus,
+ unsigned int devfn, int reg, int len, uint32_t *value)
+{
+ uint32_t *addr;
+
+ /* Use the hardware mechanism for non-simulated devices */
+ if (!is_simulated(bus, devfn))
+ return pci_direct_conf1.read(seg, bus, devfn, reg, len, value);
+
+ /*
+ * No device has config registers past 0x70, so we save table space
+ * by not storing entries for the nonexistent registers
+ */
+ if (reg >= 0x70)
+ addr = &zero_loc;
+ else {
+ switch (devfn) {
+ case 0x8:
+ addr = hdr_addr(is_lx ? lxnb_hdr : gxnb_hdr, reg);
+ break;
+ case 0x9:
+ addr = hdr_addr(is_lx ? lxfb_hdr : gxfb_hdr, reg);
+ break;
+ case 0xa:
+ addr = is_lx ? hdr_addr(aes_hdr, reg) : &ff_loc;
+ break;
+ case 0x78:
+ addr = hdr_addr(isa_hdr, reg);
+ break;
+ case 0x7b:
+ addr = hdr_addr(ac97_hdr, reg);
+ break;
+ case 0x7c:
+ addr = hdr_addr(ohci_hdr, reg);
+ break;
+ case 0x7d:
+ addr = hdr_addr(ehci_hdr, reg);
+ break;
+ default:
+ addr = &ff_loc;
+ break;
+ }
+ }
+ switch (len) {
+ case 1:
+ *value = *(uint8_t *)addr;
+ break;
+ case 2:
+ *value = *(uint16_t *)addr;
+ break;
+ case 4:
+ *value = *addr;
+ break;
+ default:
+ BUG();
+ }
+
+ return 0;
+}
+
+static int pci_olpc_write(unsigned int seg, unsigned int bus,
+ unsigned int devfn, int reg, int len, uint32_t value)
+{
+ /* Use the hardware mechanism for non-simulated devices */
+ if (!is_simulated(bus, devfn))
+ return pci_direct_conf1.write(seg, bus, devfn, reg, len, value);
+
+ /* XXX we may want to extend this to simulate EHCI power management */
+
+ /*
+ * Mostly we just discard writes, but if the write is a size probe
+ * (i.e. writing ~0 to a BAR), we remember it and arrange to return
+ * the appropriate size mask on the next read. This is cheating
+ * to some extent, because it depends on the fact that the next
+ * access after such a write will always be a read to the same BAR.
+ */
+
+ if ((reg >= 0x10) && (reg < 0x2c)) {
+ /* write is to a BAR */
+ if (value == ~0)
+ bar_probing = 1;
+ } else {
+ /*
+ * No warning on writes to ROM BAR, CMD, LATENCY_TIMER,
+ * CACHE_LINE_SIZE, or PM registers.
+ */
+ if ((reg != PCI_ROM_ADDRESS) && (reg != PCI_COMMAND_MASTER) &&
+ (reg != PCI_LATENCY_TIMER) &&
+ (reg != PCI_CACHE_LINE_SIZE) && (reg != 0x44))
+ printk(KERN_WARNING "OLPC PCI: Config write to devfn"
+ " %x reg %x value %x\n", devfn, reg, value);
+ }
+
+ return 0;
+}
+
+static struct pci_raw_ops pci_olpc_conf = {
+ .read = pci_olpc_read,
+ .write = pci_olpc_write,
+};
+
+void __init pci_olpc_init(void)
+{
+ if (!machine_is_olpc() || olpc_has_vsa())
+ return;
+
+ printk(KERN_INFO "PCI: Using configuration type OLPC\n");
+ raw_pci_ops = &pci_olpc_conf;
+ is_lx = is_geode_lx();
+}
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h
index c4bddae..c58805a 100644
--- a/arch/x86/pci/pci.h
+++ b/arch/x86/pci/pci.h
@@ -26,6 +26,7 @@
#define PCI_ASSIGN_ALL_BUSSES 0x4000
#define PCI_CAN_SKIP_ISA_ALIGN 0x8000
#define PCI_USE__CRS 0x10000
+#define PCI_CHECK_ENABLE_AMD_MMCONF 0x20000
extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;
@@ -97,11 +98,12 @@
extern int pci_direct_probe(void);
extern void pci_direct_init(int type);
extern void pci_pcbios_init(void);
-extern void pci_mmcfg_init(int type);
+extern void pci_olpc_init(void);
/* pci-mmconfig.c */
extern int __init pci_mmcfg_arch_init(void);
+extern void __init pci_mmcfg_arch_free(void);
/*
* AMD Fam10h CPUs are buggy, and cannot access MMIO config space
diff --git a/arch/x86/vdso/vdso32-setup.c b/arch/x86/vdso/vdso32-setup.c
index e2af8ee..4dceeb1 100644
--- a/arch/x86/vdso/vdso32-setup.c
+++ b/arch/x86/vdso/vdso32-setup.c
@@ -303,8 +303,6 @@
#ifdef CONFIG_X86_32
gate_vma_init();
-
- printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
#endif
if (!vdso32_sysenter()) {
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
index ef63ada..070ff8a 100644
--- a/arch/xtensa/kernel/asm-offsets.c
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -19,12 +19,11 @@
#include <linux/thread_info.h>
#include <linux/ptrace.h>
#include <linux/mm.h>
+#include <linux/kbuild.h>
#include <asm/ptrace.h>
#include <asm/uaccess.h>
-#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
int main(void)
{
/* struct pt_regs */
diff --git a/block/blk-barrier.c b/block/blk-barrier.c
index 55c5f1f..a09ead1 100644
--- a/block/blk-barrier.c
+++ b/block/blk-barrier.c
@@ -26,8 +26,7 @@
{
if (ordered & (QUEUE_ORDERED_PREFLUSH | QUEUE_ORDERED_POSTFLUSH) &&
prepare_flush_fn == NULL) {
- printk(KERN_ERR "%s: prepare_flush_fn required\n",
- __FUNCTION__);
+ printk(KERN_ERR "%s: prepare_flush_fn required\n", __func__);
return -EINVAL;
}
@@ -53,7 +52,7 @@
/*
* Cache flushing for ordered writes handling
*/
-inline unsigned blk_ordered_cur_seq(struct request_queue *q)
+unsigned blk_ordered_cur_seq(struct request_queue *q)
{
if (!q->ordseq)
return 0;
@@ -143,10 +142,8 @@
end_io = post_flush_end_io;
}
+ blk_rq_init(q, rq);
rq->cmd_flags = REQ_HARDBARRIER;
- rq_init(q, rq);
- rq->elevator_private = NULL;
- rq->elevator_private2 = NULL;
rq->rq_disk = q->bar_rq.rq_disk;
rq->end_io = end_io;
q->prepare_flush_fn(q, rq);
@@ -167,14 +164,11 @@
blkdev_dequeue_request(rq);
q->orig_bar_rq = rq;
rq = &q->bar_rq;
- rq->cmd_flags = 0;
- rq_init(q, rq);
+ blk_rq_init(q, rq);
if (bio_data_dir(q->orig_bar_rq->bio) == WRITE)
rq->cmd_flags |= REQ_RW;
if (q->ordered & QUEUE_ORDERED_FUA)
rq->cmd_flags |= REQ_FUA;
- rq->elevator_private = NULL;
- rq->elevator_private2 = NULL;
init_request_from_bio(rq, q->orig_bar_rq->bio);
rq->end_io = bar_end_io;
diff --git a/block/blk-core.c b/block/blk-core.c
index 2a438a9..b754a4a 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -107,41 +107,21 @@
}
EXPORT_SYMBOL(blk_get_backing_dev_info);
-/*
- * We can't just memset() the structure, since the allocation path
- * already stored some information in the request.
- */
-void rq_init(struct request_queue *q, struct request *rq)
+void blk_rq_init(struct request_queue *q, struct request *rq)
{
+ memset(rq, 0, sizeof(*rq));
+
INIT_LIST_HEAD(&rq->queuelist);
INIT_LIST_HEAD(&rq->donelist);
rq->q = q;
rq->sector = rq->hard_sector = (sector_t) -1;
- rq->nr_sectors = rq->hard_nr_sectors = 0;
- rq->current_nr_sectors = rq->hard_cur_sectors = 0;
- rq->bio = rq->biotail = NULL;
INIT_HLIST_NODE(&rq->hash);
RB_CLEAR_NODE(&rq->rb_node);
- rq->rq_disk = NULL;
- rq->nr_phys_segments = 0;
- rq->nr_hw_segments = 0;
- rq->ioprio = 0;
- rq->special = NULL;
- rq->buffer = NULL;
+ rq->cmd = rq->__cmd;
rq->tag = -1;
- rq->errors = 0;
rq->ref_count = 1;
- rq->cmd_len = 0;
- memset(rq->cmd, 0, sizeof(rq->cmd));
- rq->data_len = 0;
- rq->extra_len = 0;
- rq->sense_len = 0;
- rq->data = NULL;
- rq->sense = NULL;
- rq->end_io = NULL;
- rq->end_io_data = NULL;
- rq->next_rq = NULL;
}
+EXPORT_SYMBOL(blk_rq_init);
static void req_bio_endio(struct request *rq, struct bio *bio,
unsigned int nbytes, int error)
@@ -156,7 +136,7 @@
if (unlikely(nbytes > bio->bi_size)) {
printk(KERN_ERR "%s: want %u bytes done, %u left\n",
- __FUNCTION__, nbytes, bio->bi_size);
+ __func__, nbytes, bio->bi_size);
nbytes = bio->bi_size;
}
@@ -194,7 +174,7 @@
if (blk_pc_request(rq)) {
printk(KERN_INFO " cdb: ");
- for (bit = 0; bit < sizeof(rq->cmd); bit++)
+ for (bit = 0; bit < BLK_MAX_CDB; bit++)
printk("%02x ", rq->cmd[bit]);
printk("\n");
}
@@ -220,7 +200,8 @@
if (blk_queue_stopped(q))
return;
- if (!test_and_set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) {
+ if (!test_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags)) {
+ __set_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags);
mod_timer(&q->unplug_timer, jiffies + q->unplug_delay);
blk_add_trace_generic(q, NULL, 0, BLK_TA_PLUG);
}
@@ -235,9 +216,10 @@
{
WARN_ON(!irqs_disabled());
- if (!test_and_clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
+ if (!test_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags))
return 0;
+ queue_flag_clear(QUEUE_FLAG_PLUGGED, q);
del_timer(&q->unplug_timer);
return 1;
}
@@ -333,15 +315,16 @@
{
WARN_ON(!irqs_disabled());
- clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags);
+ queue_flag_clear(QUEUE_FLAG_STOPPED, q);
/*
* one level of recursion is ok and is much faster than kicking
* the unplug handling
*/
- if (!test_and_set_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) {
+ if (!test_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) {
+ queue_flag_set(QUEUE_FLAG_REENTER, q);
q->request_fn(q);
- clear_bit(QUEUE_FLAG_REENTER, &q->queue_flags);
+ queue_flag_clear(QUEUE_FLAG_REENTER, q);
} else {
blk_plug_device(q);
kblockd_schedule_work(&q->unplug_work);
@@ -366,7 +349,7 @@
void blk_stop_queue(struct request_queue *q)
{
blk_remove_plug(q);
- set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags);
+ queue_flag_set(QUEUE_FLAG_STOPPED, q);
}
EXPORT_SYMBOL(blk_stop_queue);
@@ -395,11 +378,8 @@
* blk_run_queue - run a single device queue
* @q: The queue to run
*/
-void blk_run_queue(struct request_queue *q)
+void __blk_run_queue(struct request_queue *q)
{
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
blk_remove_plug(q);
/*
@@ -407,15 +387,28 @@
* handling reinvoke the handler shortly if we already got there.
*/
if (!elv_queue_empty(q)) {
- if (!test_and_set_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) {
+ if (!test_bit(QUEUE_FLAG_REENTER, &q->queue_flags)) {
+ queue_flag_set(QUEUE_FLAG_REENTER, q);
q->request_fn(q);
- clear_bit(QUEUE_FLAG_REENTER, &q->queue_flags);
+ queue_flag_clear(QUEUE_FLAG_REENTER, q);
} else {
blk_plug_device(q);
kblockd_schedule_work(&q->unplug_work);
}
}
+}
+EXPORT_SYMBOL(__blk_run_queue);
+/**
+ * blk_run_queue - run a single device queue
+ * @q: The queue to run
+ */
+void blk_run_queue(struct request_queue *q)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ __blk_run_queue(q);
spin_unlock_irqrestore(q->queue_lock, flags);
}
EXPORT_SYMBOL(blk_run_queue);
@@ -428,7 +421,7 @@
void blk_cleanup_queue(struct request_queue *q)
{
mutex_lock(&q->sysfs_lock);
- set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
+ queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
mutex_unlock(&q->sysfs_lock);
if (q->elevator)
@@ -607,6 +600,8 @@
if (!rq)
return NULL;
+ blk_rq_init(q, rq);
+
/*
* first three bits are identical in rq->cmd_flags and bio->bi_rw,
* see bio.h and blkdev.h
@@ -789,8 +784,6 @@
if (ioc_batching(q, ioc))
ioc->nr_batch_requests--;
- rq_init(q, rq);
-
blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);
out:
return rq;
@@ -1573,8 +1566,7 @@
if (unlikely(bio->bi_idx >= bio->bi_vcnt)) {
blk_dump_rq_flags(req, "__end_that");
printk(KERN_ERR "%s: bio idx %d >= vcnt %d\n",
- __FUNCTION__, bio->bi_idx,
- bio->bi_vcnt);
+ __func__, bio->bi_idx, bio->bi_vcnt);
break;
}
diff --git a/block/blk-map.c b/block/blk-map.c
index 3c942bd..0b1af5a 100644
--- a/block/blk-map.c
+++ b/block/blk-map.c
@@ -255,10 +255,18 @@
* @kbuf: the kernel buffer
* @len: length of user data
* @gfp_mask: memory allocation flags
+ *
+ * Description:
+ * Data will be mapped directly if possible. Otherwise a bounce
+ * buffer is used.
*/
int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
unsigned int len, gfp_t gfp_mask)
{
+ unsigned long kaddr;
+ unsigned int alignment;
+ int reading = rq_data_dir(rq) == READ;
+ int do_copy = 0;
struct bio *bio;
if (len > (q->max_hw_sectors << 9))
@@ -266,13 +274,24 @@
if (!len || !kbuf)
return -EINVAL;
- bio = bio_map_kern(q, kbuf, len, gfp_mask);
+ kaddr = (unsigned long)kbuf;
+ alignment = queue_dma_alignment(q) | q->dma_pad_mask;
+ do_copy = ((kaddr & alignment) || (len & alignment));
+
+ if (do_copy)
+ bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading);
+ else
+ 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);
+ if (do_copy)
+ rq->cmd_flags |= REQ_COPY_USER;
+
blk_rq_bio_prep(q, rq, bio);
blk_queue_bounce(q, &rq->bio);
rq->buffer = rq->data = NULL;
diff --git a/block/blk-merge.c b/block/blk-merge.c
index b5c5c4a..73b2356 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -55,7 +55,7 @@
if (!rq->bio)
return;
- cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER);
+ cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
hw_seg_size = seg_size = 0;
phys_size = hw_size = nr_phys_segs = nr_hw_segs = 0;
rq_for_each_segment(bv, rq, iter) {
@@ -128,7 +128,7 @@
static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
struct bio *nxt)
{
- if (!(q->queue_flags & (1 << QUEUE_FLAG_CLUSTER)))
+ if (!test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags))
return 0;
if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)))
@@ -175,7 +175,7 @@
int nsegs, cluster;
nsegs = 0;
- cluster = q->queue_flags & (1 << QUEUE_FLAG_CLUSTER);
+ cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
/*
* for each bio in rq
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 5713f7e..bb93d4c 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -14,7 +14,6 @@
EXPORT_SYMBOL(blk_max_low_pfn);
unsigned long blk_max_pfn;
-EXPORT_SYMBOL(blk_max_pfn);
/**
* blk_queue_prep_rq - set a prepare_request function for queue
@@ -169,8 +168,8 @@
{
if ((max_sectors << 9) < PAGE_CACHE_SIZE) {
max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
- printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
- max_sectors);
+ printk(KERN_INFO "%s: set to minimum %d\n",
+ __func__, max_sectors);
}
if (BLK_DEF_MAX_SECTORS > max_sectors)
@@ -197,8 +196,8 @@
{
if (!max_segments) {
max_segments = 1;
- printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
- max_segments);
+ printk(KERN_INFO "%s: set to minimum %d\n",
+ __func__, max_segments);
}
q->max_phys_segments = max_segments;
@@ -221,8 +220,8 @@
{
if (!max_segments) {
max_segments = 1;
- printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
- max_segments);
+ printk(KERN_INFO "%s: set to minimum %d\n",
+ __func__, max_segments);
}
q->max_hw_segments = max_segments;
@@ -242,8 +241,8 @@
{
if (max_size < PAGE_CACHE_SIZE) {
max_size = PAGE_CACHE_SIZE;
- printk(KERN_INFO "%s: set to minimum %d\n", __FUNCTION__,
- max_size);
+ printk(KERN_INFO "%s: set to minimum %d\n",
+ __func__, max_size);
}
q->max_segment_size = max_size;
@@ -288,7 +287,7 @@
t->max_segment_size = min(t->max_segment_size, b->max_segment_size);
t->hardsect_size = max(t->hardsect_size, b->hardsect_size);
if (!test_bit(QUEUE_FLAG_CLUSTER, &b->queue_flags))
- clear_bit(QUEUE_FLAG_CLUSTER, &t->queue_flags);
+ queue_flag_clear(QUEUE_FLAG_CLUSTER, t);
}
EXPORT_SYMBOL(blk_queue_stack_limits);
@@ -358,8 +357,8 @@
{
if (mask < PAGE_CACHE_SIZE - 1) {
mask = PAGE_CACHE_SIZE - 1;
- printk(KERN_INFO "%s: set to minimum %lx\n", __FUNCTION__,
- mask);
+ printk(KERN_INFO "%s: set to minimum %lx\n",
+ __func__, mask);
}
q->seg_boundary_mask = mask;
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index fc41d83..e85c401 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -135,6 +135,25 @@
return queue_var_show(max_hw_sectors_kb, (page));
}
+static ssize_t queue_nomerges_show(struct request_queue *q, char *page)
+{
+ return queue_var_show(blk_queue_nomerges(q), page);
+}
+
+static ssize_t queue_nomerges_store(struct request_queue *q, const char *page,
+ size_t count)
+{
+ unsigned long nm;
+ ssize_t ret = queue_var_store(&nm, page, count);
+
+ if (nm)
+ set_bit(QUEUE_FLAG_NOMERGES, &q->queue_flags);
+ else
+ clear_bit(QUEUE_FLAG_NOMERGES, &q->queue_flags);
+
+ return ret;
+}
+
static struct queue_sysfs_entry queue_requests_entry = {
.attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR },
@@ -170,6 +189,12 @@
.show = queue_hw_sector_size_show,
};
+static struct queue_sysfs_entry queue_nomerges_entry = {
+ .attr = {.name = "nomerges", .mode = S_IRUGO | S_IWUSR },
+ .show = queue_nomerges_show,
+ .store = queue_nomerges_store,
+};
+
static struct attribute *default_attrs[] = {
&queue_requests_entry.attr,
&queue_ra_entry.attr,
@@ -177,6 +202,7 @@
&queue_max_sectors_entry.attr,
&queue_iosched_entry.attr,
&queue_hw_sector_size_entry.attr,
+ &queue_nomerges_entry.attr,
NULL,
};
diff --git a/block/blk-tag.c b/block/blk-tag.c
index 4780a46..de64e04 100644
--- a/block/blk-tag.c
+++ b/block/blk-tag.c
@@ -70,7 +70,7 @@
__blk_free_tags(bqt);
q->queue_tags = NULL;
- q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED);
+ queue_flag_clear(QUEUE_FLAG_QUEUED, q);
}
/**
@@ -98,7 +98,7 @@
**/
void blk_queue_free_tags(struct request_queue *q)
{
- clear_bit(QUEUE_FLAG_QUEUED, &q->queue_flags);
+ queue_flag_clear(QUEUE_FLAG_QUEUED, q);
}
EXPORT_SYMBOL(blk_queue_free_tags);
@@ -112,7 +112,7 @@
if (q && depth > q->nr_requests * 2) {
depth = q->nr_requests * 2;
printk(KERN_ERR "%s: adjusted depth to %d\n",
- __FUNCTION__, depth);
+ __func__, depth);
}
tag_index = kzalloc(depth * sizeof(struct request *), GFP_ATOMIC);
@@ -188,7 +188,7 @@
rc = blk_queue_resize_tags(q, depth);
if (rc)
return rc;
- set_bit(QUEUE_FLAG_QUEUED, &q->queue_flags);
+ queue_flag_set(QUEUE_FLAG_QUEUED, q);
return 0;
} else
atomic_inc(&tags->refcnt);
@@ -197,7 +197,7 @@
* assign it, all done
*/
q->queue_tags = tags;
- q->queue_flags |= (1 << QUEUE_FLAG_QUEUED);
+ queue_flag_set(QUEUE_FLAG_QUEUED, q);
INIT_LIST_HEAD(&q->tag_busy_list);
return 0;
fail:
@@ -296,13 +296,13 @@
if (unlikely(bqt->tag_index[tag] == NULL))
printk(KERN_ERR "%s: tag %d is missing\n",
- __FUNCTION__, tag);
+ __func__, tag);
bqt->tag_index[tag] = NULL;
if (unlikely(!test_bit(tag, bqt->tag_map))) {
printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n",
- __FUNCTION__, tag);
+ __func__, tag);
return;
}
/*
@@ -340,7 +340,7 @@
if (unlikely((rq->cmd_flags & REQ_QUEUED))) {
printk(KERN_ERR
"%s: request %p for device [%s] already tagged %d",
- __FUNCTION__, rq,
+ __func__, rq,
rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->tag);
BUG();
}
diff --git a/block/blk.h b/block/blk.h
index ec9120f..59776ab 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -10,7 +10,6 @@
extern struct kmem_cache *blk_requestq_cachep;
extern struct kobj_type blk_queue_ktype;
-void rq_init(struct request_queue *q, struct request *rq);
void init_request_from_bio(struct request *req, struct bio *bio);
void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
struct bio *bio);
diff --git a/block/bsg.c b/block/bsg.c
index 23ea4fd..f0b7cd3 100644
--- a/block/bsg.c
+++ b/block/bsg.c
@@ -57,7 +57,7 @@
#undef BSG_DEBUG
#ifdef BSG_DEBUG
-#define dprintk(fmt, args...) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ##args)
+#define dprintk(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ##args)
#else
#define dprintk(fmt, args...)
#endif
@@ -174,7 +174,11 @@
static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq,
struct sg_io_v4 *hdr, int has_write_perm)
{
- memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
+ if (hdr->request_len > BLK_MAX_CDB) {
+ rq->cmd = kzalloc(hdr->request_len, GFP_KERNEL);
+ if (!rq->cmd)
+ return -ENOMEM;
+ }
if (copy_from_user(rq->cmd, (void *)(unsigned long)hdr->request,
hdr->request_len))
@@ -211,8 +215,6 @@
if (hdr->guard != 'Q')
return -EINVAL;
- if (hdr->request_len > BLK_MAX_CDB)
- return -EINVAL;
if (hdr->dout_xfer_len > (q->max_sectors << 9) ||
hdr->din_xfer_len > (q->max_sectors << 9))
return -EIO;
@@ -302,6 +304,8 @@
}
return rq;
out:
+ if (rq->cmd != rq->__cmd)
+ kfree(rq->cmd);
blk_put_request(rq);
if (next_rq) {
blk_rq_unmap_user(next_rq->bio);
@@ -455,6 +459,8 @@
ret = rq->errors;
blk_rq_unmap_user(bio);
+ if (rq->cmd != rq->__cmd)
+ kfree(rq->cmd);
blk_put_request(rq);
return ret;
diff --git a/block/elevator.c b/block/elevator.c
index 88318c3..980f8ae 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -69,7 +69,7 @@
/*
* can we safely merge with this request?
*/
-inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
+int elv_rq_merge_ok(struct request *rq, struct bio *bio)
{
if (!rq_mergeable(rq))
return 0;
@@ -488,6 +488,9 @@
}
}
+ if (blk_queue_nomerges(q))
+ return ELEVATOR_NO_MERGE;
+
/*
* See if our hash lookup can find a potential backmerge.
*/
@@ -647,7 +650,7 @@
default:
printk(KERN_ERR "%s: bad insertion point %d\n",
- __FUNCTION__, where);
+ __func__, where);
BUG();
}
@@ -805,8 +808,7 @@
rq->cmd_flags |= REQ_QUIET;
end_queued_request(rq, 0);
} else {
- printk(KERN_ERR "%s: bad return=%d\n", __FUNCTION__,
- ret);
+ printk(KERN_ERR "%s: bad return=%d\n", __func__, ret);
break;
}
}
@@ -1070,7 +1072,7 @@
*/
spin_lock_irq(q->queue_lock);
- set_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
+ queue_flag_set(QUEUE_FLAG_ELVSWITCH, q);
elv_drain_elevator(q);
@@ -1104,7 +1106,10 @@
* finally exit old elevator and turn off BYPASS.
*/
elevator_exit(old_elevator);
- clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
+ spin_lock_irq(q->queue_lock);
+ queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q);
+ spin_unlock_irq(q->queue_lock);
+
return 1;
fail_register:
@@ -1115,7 +1120,11 @@
elevator_exit(e);
q->elevator = old_elevator;
elv_register_queue(q);
- clear_bit(QUEUE_FLAG_ELVSWITCH, &q->queue_flags);
+
+ spin_lock_irq(q->queue_lock);
+ queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q);
+ spin_unlock_irq(q->queue_lock);
+
return 0;
}
diff --git a/block/genhd.c b/block/genhd.c
index 00da521..fda9c7a 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -182,11 +182,17 @@
*/
void add_disk(struct gendisk *disk)
{
+ struct backing_dev_info *bdi;
+
disk->flags |= GENHD_FL_UP;
blk_register_region(MKDEV(disk->major, disk->first_minor),
disk->minors, NULL, exact_match, exact_lock, disk);
register_disk(disk);
blk_register_queue(disk);
+
+ bdi = &disk->queue->backing_dev_info;
+ bdi_register_dev(bdi, MKDEV(disk->major, disk->first_minor));
+ sysfs_create_link(&disk->dev.kobj, &bdi->dev->kobj, "bdi");
}
EXPORT_SYMBOL(add_disk);
@@ -194,6 +200,8 @@
void unlink_gendisk(struct gendisk *disk)
{
+ sysfs_remove_link(&disk->dev.kobj, "bdi");
+ bdi_unregister(&disk->queue->backing_dev_info);
blk_unregister_queue(disk);
blk_unregister_region(MKDEV(disk->major, disk->first_minor),
disk->minors);
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index a2c3a93..78199c0 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -33,13 +33,12 @@
#include <scsi/scsi_cmnd.h>
/* Command group 3 is reserved and should never be used. */
-const unsigned char scsi_command_size[8] =
+const unsigned char scsi_command_size_tbl[8] =
{
6, 10, 10, 12,
16, 12, 10, 10
};
-
-EXPORT_SYMBOL(scsi_command_size);
+EXPORT_SYMBOL(scsi_command_size_tbl);
#include <scsi/sg.h>
@@ -217,8 +216,6 @@
static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq,
struct sg_io_hdr *hdr, int has_write_perm)
{
- memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */
-
if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len))
return -EFAULT;
if (blk_verify_command(rq->cmd, has_write_perm))
@@ -531,7 +528,6 @@
rq->data_len = 0;
rq->extra_len = 0;
rq->timeout = BLK_DEFAULT_SG_TIMEOUT;
- memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd[0] = cmd;
rq->cmd[4] = data;
rq->cmd_len = 6;
diff --git a/crypto/authenc.c b/crypto/authenc.c
index ed8ac5a..4b22676 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -217,9 +217,10 @@
int err)
{
if (!err) {
- struct aead_givcrypt_request *greq = req->data;
+ struct aead_request *areq = req->data;
+ struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
- err = crypto_authenc_genicv(&greq->areq, greq->giv, 0);
+ err = crypto_authenc_genicv(areq, greq->giv, 0);
}
aead_request_complete(req->data, err);
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index 2504252..b150de5 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -190,8 +190,10 @@
int err;
inst = kzalloc(sizeof(*inst) + sizeof(*ctx), GFP_KERNEL);
- if (IS_ERR(inst))
+ if (!inst) {
+ inst = ERR_PTR(-ENOMEM);
goto out;
+ }
err = -ENAMETOOLONG;
if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
diff --git a/crypto/eseqiv.c b/crypto/eseqiv.c
index b14f14e..881d309 100644
--- a/crypto/eseqiv.c
+++ b/crypto/eseqiv.c
@@ -136,7 +136,8 @@
}
ablkcipher_request_set_crypt(subreq, reqctx->src, dst,
- req->creq.nbytes, req->creq.info);
+ req->creq.nbytes + ivsize,
+ req->creq.info);
memcpy(req->creq.info, ctx->salt, ivsize);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 80f0ec9..59f33fa 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -84,6 +84,8 @@
source "drivers/leds/Kconfig"
+source "drivers/accessibility/Kconfig"
+
source "drivers/infiniband/Kconfig"
source "drivers/edac/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index e5e394a..f65deda 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -70,6 +70,7 @@
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
+obj-$(CONFIG_ACCESSIBILITY) += accessibility/
obj-$(CONFIG_ISDN) += isdn/
obj-$(CONFIG_EDAC) += edac/
obj-$(CONFIG_MCA) += mca/
diff --git a/drivers/accessibility/Kconfig b/drivers/accessibility/Kconfig
new file mode 100644
index 0000000..1264c4b
--- /dev/null
+++ b/drivers/accessibility/Kconfig
@@ -0,0 +1,23 @@
+menuconfig ACCESSIBILITY
+ bool "Accessibility support"
+ ---help---
+ Enable a submenu where accessibility items may be enabled.
+
+ If unsure, say N.
+
+if ACCESSIBILITY
+config A11Y_BRAILLE_CONSOLE
+ bool "Console on braille device"
+ depends on VT
+ depends on SERIAL_CORE_CONSOLE
+ ---help---
+ Enables console output on a braille device connected to a 8250
+ serial port. For now only the VisioBraille device is supported.
+
+ To actually enable it, you need to pass option
+ console=brl,ttyS0
+ to the kernel. Options are the same as for serial console.
+
+ If unsure, say N.
+
+endif # ACCESSIBILITY
diff --git a/drivers/accessibility/Makefile b/drivers/accessibility/Makefile
new file mode 100644
index 0000000..72b01a4
--- /dev/null
+++ b/drivers/accessibility/Makefile
@@ -0,0 +1 @@
+obj-y += braille/
diff --git a/drivers/accessibility/braille/Makefile b/drivers/accessibility/braille/Makefile
new file mode 100644
index 0000000..2e9f16c
--- /dev/null
+++ b/drivers/accessibility/braille/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille_console.o
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
new file mode 100644
index 0000000..0a5f6b2
--- /dev/null
+++ b/drivers/accessibility/braille/braille_console.c
@@ -0,0 +1,397 @@
+/*
+ * Minimalistic braille device kernel support.
+ *
+ * By default, shows console messages on the braille device.
+ * Pressing Insert switches to VC browsing.
+ *
+ * Copyright (C) Samuel Thibault <samuel.thibault@ens-lyon.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 the program ; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/console.h>
+#include <linux/notifier.h>
+
+#include <linux/selection.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+
+#include <linux/keyboard.h>
+#include <linux/kbd_kern.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("samuel.thibault@ens-lyon.org");
+MODULE_DESCRIPTION("braille device");
+MODULE_LICENSE("GPL");
+
+/*
+ * Braille device support part.
+ */
+
+/* Emit various sounds */
+static int sound;
+module_param(sound, bool, 0);
+MODULE_PARM_DESC(sound, "emit sounds");
+
+static void beep(unsigned int freq)
+{
+ if (sound)
+ kd_mksound(freq, HZ/10);
+}
+
+/* mini console */
+#define WIDTH 40
+#define BRAILLE_KEY KEY_INSERT
+static u16 console_buf[WIDTH];
+static int console_cursor;
+
+/* mini view of VC */
+static int vc_x, vc_y, lastvc_x, lastvc_y;
+
+/* show console ? (or show VC) */
+static int console_show = 1;
+/* pending newline ? */
+static int console_newline = 1;
+static int lastVC = -1;
+
+static struct console *braille_co;
+
+/* Very VisioBraille-specific */
+static void braille_write(u16 *buf)
+{
+ static u16 lastwrite[WIDTH];
+ unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
+ u16 out;
+ int i;
+
+ if (!braille_co)
+ return;
+
+ if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
+ return;
+ memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
+
+#define SOH 1
+#define STX 2
+#define ETX 2
+#define EOT 4
+#define ENQ 5
+ data[0] = STX;
+ data[1] = '>';
+ csum ^= '>';
+ c = &data[2];
+ for (i = 0; i < WIDTH; i++) {
+ out = buf[i];
+ if (out >= 0x100)
+ out = '?';
+ else if (out == 0x00)
+ out = ' ';
+ csum ^= out;
+ if (out <= 0x05) {
+ *c++ = SOH;
+ out |= 0x40;
+ }
+ *c++ = out;
+ }
+
+ if (csum <= 0x05) {
+ *c++ = SOH;
+ csum |= 0x40;
+ }
+ *c++ = csum;
+ *c++ = ETX;
+
+ braille_co->write(braille_co, data, c - data);
+}
+
+/* Follow the VC cursor*/
+static void vc_follow_cursor(struct vc_data *vc)
+{
+ vc_x = vc->vc_x - (vc->vc_x % WIDTH);
+ vc_y = vc->vc_y;
+ lastvc_x = vc->vc_x;
+ lastvc_y = vc->vc_y;
+}
+
+/* Maybe the VC cursor moved, if so follow it */
+static void vc_maybe_cursor_moved(struct vc_data *vc)
+{
+ if (vc->vc_x != lastvc_x || vc->vc_y != lastvc_y)
+ vc_follow_cursor(vc);
+}
+
+/* Show portion of VC at vc_x, vc_y */
+static void vc_refresh(struct vc_data *vc)
+{
+ u16 buf[WIDTH];
+ int i;
+
+ for (i = 0; i < WIDTH; i++) {
+ u16 glyph = screen_glyph(vc,
+ 2 * (vc_x + i) + vc_y * vc->vc_size_row);
+ buf[i] = inverse_translate(vc, glyph, 1);
+ }
+ braille_write(buf);
+}
+
+/*
+ * Link to keyboard
+ */
+
+static int keyboard_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct keyboard_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ int ret = NOTIFY_OK;
+
+ if (!param->down)
+ return ret;
+
+ switch (code) {
+ case KBD_KEYCODE:
+ if (console_show) {
+ if (param->value == BRAILLE_KEY) {
+ console_show = 0;
+ beep(880);
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ ret = NOTIFY_STOP;
+ }
+ } else {
+ ret = NOTIFY_STOP;
+ switch (param->value) {
+ case KEY_INSERT:
+ beep(440);
+ console_show = 1;
+ lastVC = -1;
+ braille_write(console_buf);
+ break;
+ case KEY_LEFT:
+ if (vc_x > 0) {
+ vc_x -= WIDTH;
+ if (vc_x < 0)
+ vc_x = 0;
+ } else if (vc_y >= 1) {
+ beep(880);
+ vc_y--;
+ vc_x = vc->vc_cols-WIDTH;
+ } else
+ beep(220);
+ break;
+ case KEY_RIGHT:
+ if (vc_x + WIDTH < vc->vc_cols) {
+ vc_x += WIDTH;
+ } else if (vc_y + 1 < vc->vc_rows) {
+ beep(880);
+ vc_y++;
+ vc_x = 0;
+ } else
+ beep(220);
+ break;
+ case KEY_DOWN:
+ if (vc_y + 1 < vc->vc_rows)
+ vc_y++;
+ else
+ beep(220);
+ break;
+ case KEY_UP:
+ if (vc_y >= 1)
+ vc_y--;
+ else
+ beep(220);
+ break;
+ case KEY_HOME:
+ vc_follow_cursor(vc);
+ break;
+ case KEY_PAGEUP:
+ vc_x = 0;
+ vc_y = 0;
+ break;
+ case KEY_PAGEDOWN:
+ vc_x = 0;
+ vc_y = vc->vc_rows-1;
+ break;
+ default:
+ ret = NOTIFY_OK;
+ break;
+ }
+ if (ret == NOTIFY_STOP)
+ vc_refresh(vc);
+ }
+ break;
+ case KBD_POST_KEYSYM:
+ {
+ unsigned char type = KTYP(param->value) - 0xf0;
+ if (type == KT_SPEC) {
+ unsigned char val = KVAL(param->value);
+ int on_off = -1;
+
+ switch (val) {
+ case KVAL(K_CAPS):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_CAPSLOCK);
+ break;
+ case KVAL(K_NUM):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_NUMLOCK);
+ break;
+ case KVAL(K_HOLD):
+ on_off = vc_kbd_led(kbd_table + fg_console,
+ VC_SCROLLOCK);
+ break;
+ }
+ if (on_off == 1)
+ beep(880);
+ else if (on_off == 0)
+ beep(440);
+ }
+ }
+ case KBD_UNBOUND_KEYCODE:
+ case KBD_UNICODE:
+ case KBD_KEYSYM:
+ /* Unused */
+ break;
+ }
+ return ret;
+}
+
+static struct notifier_block keyboard_notifier_block = {
+ .notifier_call = keyboard_notifier_call,
+};
+
+static int vt_notifier_call(struct notifier_block *blk,
+ unsigned long code, void *_param)
+{
+ struct vt_notifier_param *param = _param;
+ struct vc_data *vc = param->vc;
+ switch (code) {
+ case VT_ALLOCATE:
+ break;
+ case VT_DEALLOCATE:
+ break;
+ case VT_WRITE:
+ {
+ unsigned char c = param->c;
+ if (vc->vc_num != fg_console)
+ break;
+ switch (c) {
+ case '\b':
+ case 127:
+ if (console_cursor > 0) {
+ console_cursor--;
+ console_buf[console_cursor] = ' ';
+ }
+ break;
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ console_newline = 1;
+ break;
+ case '\t':
+ c = ' ';
+ /* Fallthrough */
+ default:
+ if (c < 32)
+ /* Ignore other control sequences */
+ break;
+ if (console_newline) {
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ console_newline = 0;
+ }
+ if (console_cursor == WIDTH)
+ memmove(console_buf, &console_buf[1],
+ (WIDTH-1) * sizeof(*console_buf));
+ else
+ console_cursor++;
+ console_buf[console_cursor-1] = c;
+ break;
+ }
+ if (console_show)
+ braille_write(console_buf);
+ else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ case VT_UPDATE:
+ /* Maybe a VT switch, flush */
+ if (console_show) {
+ if (vc->vc_num != lastVC) {
+ lastVC = vc->vc_num;
+ memset(console_buf, 0, sizeof(console_buf));
+ console_cursor = 0;
+ braille_write(console_buf);
+ }
+ } else {
+ vc_maybe_cursor_moved(vc);
+ vc_refresh(vc);
+ }
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block vt_notifier_block = {
+ .notifier_call = vt_notifier_call,
+};
+
+/*
+ * Called from printk.c when console=brl is given
+ */
+
+int braille_register_console(struct console *console, int index,
+ char *console_options, char *braille_options)
+{
+ int ret;
+ if (!console_options)
+ /* Only support VisioBraille for now */
+ console_options = "57600o8";
+ if (braille_co)
+ return -ENODEV;
+ if (console->setup) {
+ ret = console->setup(console, console_options);
+ if (ret != 0)
+ return ret;
+ }
+ console->flags |= CON_ENABLED;
+ console->index = index;
+ braille_co = console;
+ return 0;
+}
+
+int braille_unregister_console(struct console *console)
+{
+ if (braille_co != console)
+ return -EINVAL;
+ braille_co = NULL;
+ return 0;
+}
+
+static int __init braille_init(void)
+{
+ register_keyboard_notifier(&keyboard_notifier_block);
+ register_vt_notifier(&vt_notifier_block);
+ return 0;
+}
+
+console_initcall(braille_init);
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index b4f5e85..c52fca8 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -140,6 +140,7 @@
tristate "Video"
depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
depends on INPUT
+ select THERMAL
help
This driver implement the ACPI Extensions For Display Adapters
for integrated graphics devices on motherboard, as specified in
@@ -151,6 +152,7 @@
config ACPI_FAN
tristate "Fan"
+ select THERMAL
default y
help
This driver adds support for ACPI fan devices, allowing user-mode
@@ -172,6 +174,7 @@
config ACPI_PROCESSOR
tristate "Processor"
+ select THERMAL
default y
help
This driver installs ACPI as the idle handler for Linux, and uses
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index 43a95e5..5b73f6a 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -92,6 +92,7 @@
#ifdef CONFIG_ACPI_PROCFS_POWER
static const struct file_operations acpi_ac_fops = {
+ .owner = THIS_MODULE,
.open = acpi_ac_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -195,16 +196,11 @@
}
/* 'state' [R] */
- entry = create_proc_entry(ACPI_AC_FILE_STATE,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_AC_FILE_STATE,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_ac_fops, acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_ac_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index d5729d5..b1c723f 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -741,15 +741,13 @@
}
for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) {
- entry = create_proc_entry(acpi_battery_file[i].name,
- acpi_battery_file[i].mode, acpi_device_dir(device));
+ entry = proc_create_data(acpi_battery_file[i].name,
+ acpi_battery_file[i].mode,
+ acpi_device_dir(device),
+ &acpi_battery_file[i].ops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_battery_file[i].ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
}
return 0;
}
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
index 1fa8681..d2fc941 100644
--- a/drivers/acpi/bay.c
+++ b/drivers/acpi/bay.c
@@ -201,6 +201,7 @@
return 0;
}
+#if 0
/**
* eject_removable_drive - try to eject this drive
* @dev : the device structure of the drive
@@ -225,6 +226,7 @@
return 0;
}
EXPORT_SYMBOL_GPL(eject_removable_drive);
+#endif /* 0 */
static int acpi_bay_add_fs(struct bay *bay)
{
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 2d1955c..a6dbcf4 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -35,6 +35,7 @@
#ifdef CONFIG_X86
#include <asm/mpspec.h>
#endif
+#include <linux/pci.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -784,6 +785,7 @@
result = acpi_bus_init();
if (!result) {
+ pci_mmcfg_late_init();
if (!(pm_flags & PM_APM))
pm_flags |= PM_ACPI;
else {
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index 6c5da83..1dfec41 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -102,6 +102,7 @@
};
static const struct file_operations acpi_button_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_button_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -109,6 +110,7 @@
};
static const struct file_operations acpi_button_state_fops = {
+ .owner = THIS_MODULE,
.open = acpi_button_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -207,27 +209,21 @@
acpi_device_dir(device)->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_BUTTON_FILE_INFO,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_button_info_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_button_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* show lid state [R] */
if (button->type == ACPI_BUTTON_TYPE_LID) {
- entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_BUTTON_FILE_STATE,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_button_state_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_button_state_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
}
return 0;
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index f049639..c780783 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -89,12 +89,16 @@
ACPI_FUNCTION_TRACE(ds_create_buffer_field);
- /* Get the name_string argument */
-
+ /*
+ * Get the name_string argument (name of the new buffer_field)
+ */
if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
+
+ /* For create_field, name is the 4th argument */
+
arg = acpi_ps_get_arg(op, 3);
} else {
- /* Create Bit/Byte/Word/Dword field */
+ /* For all other create_xXXField operators, name is the 3rd argument */
arg = acpi_ps_get_arg(op, 2);
}
@@ -107,26 +111,30 @@
node = walk_state->deferred_node;
status = AE_OK;
} else {
- /*
- * During the load phase, we want to enter the name of the field into
- * the namespace. During the execute phase (when we evaluate the size
- * operand), we want to lookup the name
- */
- if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) {
- flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE;
- } else {
- flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
- ACPI_NS_ERROR_IF_FOUND;
+ /* Execute flag should always be set when this function is entered */
+
+ if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
+ return_ACPI_STATUS(AE_AML_INTERNAL);
}
- /*
- * Enter the name_string into the namespace
- */
+ /* Creating new namespace node, should not already exist */
+
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND;
+
+ /* Mark node temporary if we are executing a method */
+
+ if (walk_state->method_node) {
+ flags |= ACPI_NS_TEMPORARY;
+ }
+
+ /* Enter the name_string into the namespace */
+
status =
acpi_ns_lookup(walk_state->scope_info,
arg->common.value.string, ACPI_TYPE_ANY,
ACPI_IMODE_LOAD_PASS1, flags, walk_state,
- &(node));
+ &node);
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE(arg->common.value.string, status);
return_ACPI_STATUS(status);
@@ -136,13 +144,13 @@
/*
* We could put the returned object (Node) on the object stack for later,
* but for now, we will put it in the "op" object that the parser uses,
- * so we can get it again at the end of this scope
+ * so we can get it again at the end of this scope.
*/
op->common.node = node;
/*
* If there is no object attached to the node, this node was just created
- * and we need to create the field object. Otherwise, this was a lookup
+ * and we need to create the field object. Otherwise, this was a lookup
* of an existing node and we don't want to create the field object again.
*/
obj_desc = acpi_ns_get_attached_object(node);
@@ -164,9 +172,8 @@
}
/*
- * Remember location in AML stream of the field unit
- * opcode and operands -- since the buffer and index
- * operands must be evaluated.
+ * Remember location in AML stream of the field unit opcode and operands --
+ * since the buffer and index operands must be evaluated.
*/
second_desc = obj_desc->common.next_object;
second_desc->extra.aml_start = op->named.data;
@@ -261,7 +268,7 @@
case AML_INT_NAMEDFIELD_OP:
- /* Lookup the name */
+ /* Lookup the name, it should already exist */
status = acpi_ns_lookup(walk_state->scope_info,
(char *)&arg->named.name,
@@ -272,20 +279,23 @@
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
status);
- if (status != AE_ALREADY_EXISTS) {
- return_ACPI_STATUS(status);
- }
-
- /* Already exists, ignore error */
+ return_ACPI_STATUS(status);
} else {
arg->common.node = info->field_node;
info->field_bit_length = arg->common.value.size;
- /* Create and initialize an object for the new Field Node */
-
- status = acpi_ex_prep_field_value(info);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /*
+ * If there is no object attached to the node, this node was
+ * just created and we need to create the field object.
+ * Otherwise, this was a lookup of an existing node and we
+ * don't want to create the field object again.
+ */
+ if (!acpi_ns_get_attached_object
+ (info->field_node)) {
+ status = acpi_ex_prep_field_value(info);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
}
@@ -399,9 +409,27 @@
union acpi_parse_object *arg = NULL;
struct acpi_namespace_node *node;
u8 type = 0;
+ u32 flags;
ACPI_FUNCTION_TRACE_PTR(ds_init_field_objects, op);
+ /* Execute flag should always be set when this function is entered */
+
+ if (!(walk_state->parse_flags & ACPI_PARSE_EXECUTE)) {
+ if (walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP) {
+
+ /* bank_field Op is deferred, just return OK */
+
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
+ /*
+ * Get the field_list argument for this opcode. This is the start of the
+ * list of field elements.
+ */
switch (walk_state->opcode) {
case AML_FIELD_OP:
arg = acpi_ps_get_arg(op, 2);
@@ -422,20 +450,33 @@
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
+ if (!arg) {
+ return_ACPI_STATUS(AE_AML_NO_OPERAND);
+ }
+
+ /* Creating new namespace node(s), should not already exist */
+
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND;
+
+ /* Mark node(s) temporary if we are executing a method */
+
+ if (walk_state->method_node) {
+ flags |= ACPI_NS_TEMPORARY;
+ }
+
/*
* Walk the list of entries in the field_list
*/
while (arg) {
-
- /* Ignore OFFSET and ACCESSAS terms here */
-
+ /*
+ * Ignore OFFSET and ACCESSAS terms here; we are only interested in the
+ * field names in order to enter them into the namespace.
+ */
if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
status = acpi_ns_lookup(walk_state->scope_info,
- (char *)&arg->named.name,
- type, ACPI_IMODE_LOAD_PASS1,
- ACPI_NS_NO_UPSEARCH |
- ACPI_NS_DONT_OPEN_SCOPE |
- ACPI_NS_ERROR_IF_FOUND,
+ (char *)&arg->named.name, type,
+ ACPI_IMODE_LOAD_PASS1, flags,
walk_state, &node);
if (ACPI_FAILURE(status)) {
ACPI_ERROR_NAMESPACE((char *)&arg->named.name,
@@ -452,7 +493,7 @@
arg->common.node = node;
}
- /* Move to next field in the list */
+ /* Get the next field element in the list */
arg = arg->common.next;
}
@@ -466,7 +507,7 @@
*
* PARAMETERS: Op - Op containing the Field definition and args
* region_node - Object for the containing Operation Region
- * ` walk_state - Current method state
+ * walk_state - Current method state
*
* RETURN: Status
*
@@ -513,36 +554,13 @@
return_ACPI_STATUS(status);
}
- /* Third arg is the bank_value */
-
- /* TBD: This arg is a term_arg, not a constant, and must be evaluated */
-
+ /*
+ * Third arg is the bank_value
+ * This arg is a term_arg, not a constant
+ * It will be evaluated later, by acpi_ds_eval_bank_field_operands
+ */
arg = arg->common.next;
- /* Currently, only the following constants are supported */
-
- switch (arg->common.aml_opcode) {
- case AML_ZERO_OP:
- info.bank_value = 0;
- break;
-
- case AML_ONE_OP:
- info.bank_value = 1;
- break;
-
- case AML_BYTE_OP:
- case AML_WORD_OP:
- case AML_DWORD_OP:
- case AML_QWORD_OP:
- info.bank_value = (u32) arg->common.value.integer;
- break;
-
- default:
- info.bank_value = 0;
- ACPI_ERROR((AE_INFO,
- "Non-constant BankValue for BankField is not implemented"));
- }
-
/* Fourth arg is the field flags */
arg = arg->common.next;
@@ -553,8 +571,17 @@
info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD;
info.region_node = region_node;
- status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
+ /*
+ * Use Info.data_register_node to store bank_field Op
+ * It's safe because data_register_node will never be used when create bank field
+ * We store aml_start and aml_length in the bank_field Op for late evaluation
+ * Used in acpi_ex_prep_field_value(Info)
+ *
+ * TBD: Or, should we add a field in struct acpi_create_field_info, like "void *ParentOp"?
+ */
+ info.data_register_node = (struct acpi_namespace_node *)op;
+ status = acpi_ds_get_field_names(&info, walk_state, arg->common.next);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index af923c3..610b1ee 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index 1cbe619..e48a3ea 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,6 @@
*/
#include <acpi/acpi.h>
-#include <acpi/acparser.h>
#include <acpi/amlcode.h>
#include <acpi/acdispat.h>
#include <acpi/acinterp.h>
@@ -102,7 +101,7 @@
walk_state->opcode,
walk_state->aml_offset,
NULL);
- (void)acpi_ex_enter_interpreter();
+ acpi_ex_enter_interpreter();
}
#ifdef ACPI_DISASSEMBLER
if (ACPI_FAILURE(status)) {
@@ -232,9 +231,9 @@
* recursive call.
*/
if (!walk_state ||
- !obj_desc->method.mutex->mutex.owner_thread ||
- (walk_state->thread !=
- obj_desc->method.mutex->mutex.owner_thread)) {
+ !obj_desc->method.mutex->mutex.thread_id ||
+ (walk_state->thread->thread_id !=
+ obj_desc->method.mutex->mutex.thread_id)) {
/*
* Acquire the method mutex. This releases the interpreter if we
* block (and reacquires it before it returns)
@@ -254,8 +253,8 @@
original_sync_level =
walk_state->thread->current_sync_level;
- obj_desc->method.mutex->mutex.owner_thread =
- walk_state->thread;
+ obj_desc->method.mutex->mutex.thread_id =
+ walk_state->thread->thread_id;
walk_state->thread->current_sync_level =
obj_desc->method.sync_level;
} else {
@@ -535,8 +534,6 @@
acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
struct acpi_walk_state *walk_state)
{
- struct acpi_namespace_node *method_node;
- acpi_status status;
ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
@@ -551,34 +548,26 @@
/* Delete all arguments and locals */
acpi_ds_method_data_delete_all(walk_state);
- }
- /*
- * If method is serialized, release the mutex and restore the
- * current sync level for this thread
- */
- if (method_desc->method.mutex) {
-
- /* Acquisition Depth handles recursive calls */
-
- method_desc->method.mutex->mutex.acquisition_depth--;
- if (!method_desc->method.mutex->mutex.acquisition_depth) {
- walk_state->thread->current_sync_level =
- method_desc->method.mutex->mutex.
- original_sync_level;
-
- acpi_os_release_mutex(method_desc->method.mutex->mutex.
- os_mutex);
- method_desc->method.mutex->mutex.owner_thread = NULL;
- }
- }
-
- if (walk_state) {
/*
- * Delete any objects created by this method during execution.
- * The method Node is stored in the walk state
+ * If method is serialized, release the mutex and restore the
+ * current sync level for this thread
*/
- method_node = walk_state->method_node;
+ if (method_desc->method.mutex) {
+
+ /* Acquisition Depth handles recursive calls */
+
+ method_desc->method.mutex->mutex.acquisition_depth--;
+ if (!method_desc->method.mutex->mutex.acquisition_depth) {
+ walk_state->thread->current_sync_level =
+ method_desc->method.mutex->mutex.
+ original_sync_level;
+
+ acpi_os_release_mutex(method_desc->method.
+ mutex->mutex.os_mutex);
+ method_desc->method.mutex->mutex.thread_id = 0;
+ }
+ }
/*
* Delete any namespace objects created anywhere within
@@ -620,7 +609,7 @@
*/
if ((method_desc->method.method_flags & AML_METHOD_SERIALIZED)
&& (!method_desc->method.mutex)) {
- status = acpi_ds_create_method_mutex(method_desc);
+ (void)acpi_ds_create_method_mutex(method_desc);
}
/* No more threads, we can free the owner_id */
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index ba4626e..13c43ea 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index 954ac8c..1022e38 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -157,7 +157,9 @@
* will remain as named references. This behavior is not described
* in the ACPI spec, but it appears to be an oversight.
*/
- obj_desc = (union acpi_operand_object *)op->common.node;
+ obj_desc =
+ ACPI_CAST_PTR(union acpi_operand_object,
+ op->common.node);
status =
acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
@@ -172,7 +174,19 @@
switch (op->common.node->type) {
/*
* For these types, we need the actual node, not the subobject.
- * However, the subobject got an extra reference count above.
+ * However, the subobject did not get an extra reference count above.
+ *
+ * TBD: should ex_resolve_node_to_value be changed to fix this?
+ */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_THERMAL:
+
+ acpi_ut_add_reference(op->common.node->object);
+
+ /*lint -fallthrough */
+ /*
+ * For these types, we need the actual node, not the subobject.
+ * The subobject got an extra reference count in ex_resolve_node_to_value.
*/
case ACPI_TYPE_MUTEX:
case ACPI_TYPE_METHOD:
@@ -180,25 +194,15 @@
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_EVENT:
case ACPI_TYPE_REGION:
- case ACPI_TYPE_DEVICE:
- case ACPI_TYPE_THERMAL:
- obj_desc =
- (union acpi_operand_object *)op->common.
- node;
+ /* We will create a reference object for these types below */
break;
default:
- break;
- }
-
- /*
- * If above resolved to an operand object, we are done. Otherwise,
- * we have a NS node, we must create the package entry as a named
- * reference.
- */
- if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) !=
- ACPI_DESC_TYPE_NAMED) {
+ /*
+ * All other types - the node was resolved to an actual
+ * object, we are done.
+ */
goto exit;
}
}
@@ -223,7 +227,7 @@
exit:
*obj_desc_ptr = obj_desc;
- return_ACPI_STATUS(AE_OK);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -369,7 +373,9 @@
union acpi_parse_object *parent;
union acpi_operand_object *obj_desc = NULL;
acpi_status status = AE_OK;
- acpi_native_uint i;
+ unsigned i;
+ u16 index;
+ u16 reference_count;
ACPI_FUNCTION_TRACE(ds_build_internal_package_obj);
@@ -447,13 +453,60 @@
package.
elements[i]);
}
+
+ if (*obj_desc_ptr) {
+
+ /* Existing package, get existing reference count */
+
+ reference_count =
+ (*obj_desc_ptr)->common.reference_count;
+ if (reference_count > 1) {
+
+ /* Make new element ref count match original ref count */
+
+ for (index = 0; index < (reference_count - 1);
+ index++) {
+ acpi_ut_add_reference((obj_desc->
+ package.
+ elements[i]));
+ }
+ }
+ }
+
arg = arg->common.next;
}
- if (!arg) {
+ /* Check for match between num_elements and actual length of package_list */
+
+ if (arg) {
+ /*
+ * num_elements was exhausted, but there are remaining elements in the
+ * package_list.
+ *
+ * Note: technically, this is an error, from ACPI spec: "It is an error
+ * for NumElements to be less than the number of elements in the
+ * PackageList". However, for now, we just print an error message and
+ * no exception is returned.
+ */
+ while (arg) {
+
+ /* Find out how many elements there really are */
+
+ i++;
+ arg = arg->common.next;
+ }
+
+ ACPI_ERROR((AE_INFO,
+ "Package List length (%X) larger than NumElements count (%X), truncated\n",
+ i, element_count));
+ } else if (i < element_count) {
+ /*
+ * Arg list (elements) was exhausted, but we did not reach num_elements count.
+ * Note: this is not an error, the package is padded out with NULLs.
+ */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Package List length larger than NumElements count (%X), truncated\n",
- element_count));
+ "Package List length (%X) smaller than NumElements count (%X), padded with null elements\n",
+ i, element_count));
}
obj_desc->package.flags |= AOPOBJ_DATA_VALID;
@@ -721,6 +774,8 @@
/* Node was saved in Op */
obj_desc->reference.node = op->common.node;
+ obj_desc->reference.object =
+ op->common.node->object;
}
obj_desc->reference.opcode = opcode;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index f501e08..a818e0d 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,7 @@
#include <acpi/acinterp.h>
#include <acpi/acnamesp.h>
#include <acpi/acevents.h>
+#include <acpi/actables.h>
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dsopcode")
@@ -219,6 +220,50 @@
/*******************************************************************************
*
+ * FUNCTION: acpi_ds_get_bank_field_arguments
+ *
+ * PARAMETERS: obj_desc - A valid bank_field object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get bank_field bank_value. This implements the late
+ * evaluation of these field attributes.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc)
+{
+ union acpi_operand_object *extra_desc;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_get_bank_field_arguments, obj_desc);
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Get the AML pointer (method object) and bank_field node */
+
+ extra_desc = acpi_ns_get_secondary_object(obj_desc);
+ node = obj_desc->bank_field.node;
+
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname
+ (ACPI_TYPE_LOCAL_BANK_FIELD, node, NULL));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "[%4.4s] BankField Arg Init\n",
+ acpi_ut_get_node_name(node)));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments(node, acpi_ns_get_parent_node(node),
+ extra_desc->extra.aml_length,
+ extra_desc->extra.aml_start);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ds_get_buffer_arguments
*
* PARAMETERS: obj_desc - A valid Buffer object
@@ -770,7 +815,109 @@
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
obj_desc,
- ACPI_FORMAT_UINT64(obj_desc->region.address),
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address),
+ obj_desc->region.length));
+
+ /* Now the address and length are valid for this opregion */
+
+ obj_desc->region.flags |= AOPOBJ_DATA_VALID;
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_table_region_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get region address and length
+ * Called from acpi_ds_exec_end_op during data_table_region parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object **operand;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+ acpi_native_uint table_index;
+ struct acpi_table_header *table;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op);
+
+ /*
+ * This is where we evaluate the signature_string and oem_iDString
+ * and oem_table_iDString of the data_table_region declaration
+ */
+ node = op->common.node;
+
+ /* next_op points to signature_string op */
+
+ next_op = op->common.value.arg;
+
+ /*
+ * Evaluate/create the signature_string and oem_iDString
+ * and oem_table_iDString operands
+ */
+ status = acpi_ds_create_operands(walk_state, next_op);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Resolve the signature_string and oem_iDString
+ * and oem_table_iDString operands
+ */
+ status = acpi_ex_resolve_operands(op->common.aml_opcode,
+ ACPI_WALK_OPERANDS, walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ 1, "after AcpiExResolveOperands");
+
+ operand = &walk_state->operands[0];
+
+ /* Find the ACPI table */
+
+ status = acpi_tb_find_table(operand[0]->string.pointer,
+ operand[1]->string.pointer,
+ operand[2]->string.pointer, &table_index);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ut_remove_reference(operand[0]);
+ acpi_ut_remove_reference(operand[1]);
+ acpi_ut_remove_reference(operand[2]);
+
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ obj_desc->region.address =
+ (acpi_physical_address) ACPI_TO_INTEGER(table);
+ obj_desc->region.length = table->length;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "RgnObj %p Addr %8.8X%8.8X Len %X\n",
+ obj_desc,
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.address),
obj_desc->region.length));
/* Now the address and length are valid for this opregion */
@@ -808,6 +955,12 @@
/* The first operand (for all of these data objects) is the length */
+ /*
+ * Set proper index into operand stack for acpi_ds_obj_stack_push
+ * invoked inside acpi_ds_create_operand.
+ */
+ walk_state->operand_index = walk_state->num_operands;
+
status = acpi_ds_create_operand(walk_state, op->common.value.arg, 1);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -878,6 +1031,106 @@
/*******************************************************************************
*
+ * FUNCTION: acpi_ds_eval_bank_field_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid bank_field Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get bank_field bank_value
+ * Called from acpi_ds_exec_end_op during bank_field parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *operand_desc;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+ union acpi_parse_object *arg;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_eval_bank_field_operands, op);
+
+ /*
+ * This is where we evaluate the bank_value field of the
+ * bank_field declaration
+ */
+
+ /* next_op points to the op that holds the Region */
+
+ next_op = op->common.value.arg;
+
+ /* next_op points to the op that holds the Bank Register */
+
+ next_op = next_op->common.next;
+
+ /* next_op points to the op that holds the Bank Value */
+
+ next_op = next_op->common.next;
+
+ /*
+ * Set proper index into operand stack for acpi_ds_obj_stack_push
+ * invoked inside acpi_ds_create_operand.
+ *
+ * We use walk_state->Operands[0] to store the evaluated bank_value
+ */
+ walk_state->operand_index = 0;
+
+ status = acpi_ds_create_operand(walk_state, next_op, 0);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ status = acpi_ex_resolve_to_value(&walk_state->operands[0], walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ ACPI_DUMP_OPERANDS(ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
+ acpi_ps_get_opcode_name(op->common.aml_opcode),
+ 1, "after AcpiExResolveOperands");
+
+ /*
+ * Get the bank_value operand and save it
+ * (at Top of stack)
+ */
+ operand_desc = walk_state->operands[0];
+
+ /* Arg points to the start Bank Field */
+
+ arg = acpi_ps_get_arg(op, 4);
+ while (arg) {
+
+ /* Ignore OFFSET and ACCESSAS terms here */
+
+ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
+ node = arg->common.node;
+
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ obj_desc->bank_field.value =
+ (u32) operand_desc->integer.value;
+ }
+
+ /* Move to next field in the list */
+
+ arg = arg->common.next;
+ }
+
+ acpi_ut_remove_reference(operand_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ds_exec_begin_control_op
*
* PARAMETERS: walk_list - The list that owns the walk stack
@@ -1070,8 +1323,7 @@
* is set to anything other than zero!
*/
walk_state->return_desc = walk_state->operands[0];
- } else if ((walk_state->results) &&
- (walk_state->results->results.num_results > 0)) {
+ } else if (walk_state->result_count) {
/* Since we have a real Return(), delete any implicit return */
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index 71503c0..b398982 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -278,7 +278,9 @@
AML_VAR_PACKAGE_OP)
|| (op->common.parent->common.aml_opcode == AML_BUFFER_OP)
|| (op->common.parent->common.aml_opcode ==
- AML_INT_EVAL_SUBTREE_OP)) {
+ AML_INT_EVAL_SUBTREE_OP)
+ || (op->common.parent->common.aml_opcode ==
+ AML_BANK_FIELD_OP)) {
/*
* These opcodes allow term_arg(s) as operands and therefore
* the operands can be method calls. The result is used.
@@ -472,7 +474,8 @@
/* A valid name must be looked up in the namespace */
if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
- (arg->common.value.string)) {
+ (arg->common.value.string) &&
+ !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n",
arg));
@@ -595,7 +598,8 @@
} else {
/* Check for null name case */
- if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
+ !(arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
/*
* If the name is null, this means that this is an
* optional result parameter that was not specified
@@ -617,7 +621,8 @@
return_ACPI_STATUS(AE_NOT_IMPLEMENTED);
}
- if (op_info->flags & AML_HAS_RETVAL) {
+ if ((op_info->flags & AML_HAS_RETVAL)
+ || (arg->common.flags & ACPI_PARSEOP_IN_STACK)) {
ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
"Argument previously created, already stacked\n"));
@@ -630,9 +635,7 @@
* Use value that was already previously returned
* by the evaluation of this argument
*/
- status =
- acpi_ds_result_pop_from_bottom(&obj_desc,
- walk_state);
+ status = acpi_ds_result_pop(&obj_desc, walk_state);
if (ACPI_FAILURE(status)) {
/*
* Only error is underflow, and this indicates
@@ -698,27 +701,52 @@
{
acpi_status status = AE_OK;
union acpi_parse_object *arg;
+ union acpi_parse_object *arguments[ACPI_OBJ_NUM_OPERANDS];
u32 arg_count = 0;
+ u32 index = walk_state->num_operands;
+ u32 i;
ACPI_FUNCTION_TRACE_PTR(ds_create_operands, first_arg);
- /* For all arguments in the list... */
+ /* Get all arguments in the list */
arg = first_arg;
while (arg) {
- status = acpi_ds_create_operand(walk_state, arg, arg_count);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
+ if (index >= ACPI_OBJ_NUM_OPERANDS) {
+ return_ACPI_STATUS(AE_BAD_DATA);
}
- ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
- "Arg #%d (%p) done, Arg1=%p\n", arg_count,
- arg, first_arg));
+ arguments[index] = arg;
+ walk_state->operands[index] = NULL;
/* Move on to next argument, if any */
arg = arg->common.next;
arg_count++;
+ index++;
+ }
+
+ index--;
+
+ /* It is the appropriate order to get objects from the Result stack */
+
+ for (i = 0; i < arg_count; i++) {
+ arg = arguments[index];
+
+ /* Force the filling of the operand stack in inverse order */
+
+ walk_state->operand_index = (u8) index;
+
+ status = acpi_ds_create_operand(walk_state, arg, index);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
+ index--;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "Arg #%d (%p) done, Arg1=%p\n", index, arg,
+ first_arg));
}
return_ACPI_STATUS(status);
@@ -729,9 +757,112 @@
* pop everything off of the operand stack and delete those
* objects
*/
- (void)acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
+ acpi_ds_obj_stack_pop_and_delete(arg_count, walk_state);
- ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d",
- (arg_count + 1)));
+ ACPI_EXCEPTION((AE_INFO, status, "While creating Arg %d", index));
+ return_ACPI_STATUS(status);
+}
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_evaluate_name_path
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk,
+ * the opcode of current operation should be
+ * AML_INT_NAMEPATH_OP
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate the -name_path- parse tree object to the equivalent
+ * interpreter object, convert it to value, if needed, duplicate
+ * it, if needed, and push it onto the current result stack.
+ *
+ ****************************************************************************/
+
+acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op = walk_state->op;
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *new_obj_desc;
+ u8 type;
+
+ ACPI_FUNCTION_TRACE_PTR(ds_evaluate_name_path, walk_state);
+
+ if (!op->common.parent) {
+
+ /* This happens after certain exception processing */
+
+ goto exit;
+ }
+
+ if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_REF_OF_OP)) {
+
+ /* TBD: Should we specify this feature as a bit of op_info->Flags of these opcodes? */
+
+ goto exit;
+ }
+
+ status = acpi_ds_create_operand(walk_state, op, 0);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ if (op->common.flags & ACPI_PARSEOP_TARGET) {
+ new_obj_desc = *operand;
+ goto push_result;
+ }
+
+ type = ACPI_GET_OBJECT_TYPE(*operand);
+
+ status = acpi_ex_resolve_to_value(operand, walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+
+ if (type == ACPI_TYPE_INTEGER) {
+
+ /* It was incremented by acpi_ex_resolve_to_value */
+
+ acpi_ut_remove_reference(*operand);
+
+ status =
+ acpi_ut_copy_iobject_to_iobject(*operand, &new_obj_desc,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
+ }
+ } else {
+ /*
+ * The object either was anew created or is
+ * a Namespace node - don't decrement it.
+ */
+ new_obj_desc = *operand;
+ }
+
+ /* Cleanup for name-path operand */
+
+ status = acpi_ds_obj_stack_pop(1, walk_state);
+ if (ACPI_FAILURE(status)) {
+ walk_state->result_obj = new_obj_desc;
+ goto exit;
+ }
+
+ push_result:
+
+ walk_state->result_obj = new_obj_desc;
+
+ status = acpi_ds_result_push(walk_state->result_obj, walk_state);
+ if (ACPI_SUCCESS(status)) {
+
+ /* Force to take it from stack */
+
+ op->common.flags |= ACPI_PARSEOP_IN_STACK;
+ }
+
+ exit:
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index 69693fa..b246b96 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -285,11 +285,6 @@
switch (opcode_class) {
case AML_CLASS_CONTROL:
- status = acpi_ds_result_stack_push(walk_state);
- if (ACPI_FAILURE(status)) {
- goto error_exit;
- }
-
status = acpi_ds_exec_begin_control_op(walk_state, op);
break;
@@ -305,20 +300,11 @@
status = acpi_ds_load2_begin_op(walk_state, NULL);
}
- if (op->common.aml_opcode == AML_REGION_OP) {
- status = acpi_ds_result_stack_push(walk_state);
- }
break;
case AML_CLASS_EXECUTE:
case AML_CLASS_CREATE:
- /*
- * Most operators with arguments (except create_xxx_field operators)
- * Start a new result/operand state
- */
- if (walk_state->op_info->object_type != ACPI_TYPE_BUFFER_FIELD) {
- status = acpi_ds_result_stack_push(walk_state);
- }
+
break;
default:
@@ -374,6 +360,7 @@
/* Init the walk state */
walk_state->num_operands = 0;
+ walk_state->operand_index = 0;
walk_state->return_desc = NULL;
walk_state->result_obj = NULL;
@@ -388,10 +375,17 @@
/* Decode the Opcode Class */
switch (op_class) {
- case AML_CLASS_ARGUMENT: /* constants, literals, etc. - do nothing */
+ case AML_CLASS_ARGUMENT: /* Constants, literals, etc. */
+
+ if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
+ status = acpi_ds_evaluate_name_path(walk_state);
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+ }
break;
- case AML_CLASS_EXECUTE: /* most operators with arguments */
+ case AML_CLASS_EXECUTE: /* Most operators with arguments */
/* Build resolved operand stack */
@@ -400,13 +394,6 @@
goto cleanup;
}
- /* Done with this result state (Now that operand stack is built) */
-
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
/*
* All opcodes require operand resolution, with the only exceptions
* being the object_type and size_of operators.
@@ -487,16 +474,6 @@
status = acpi_ds_exec_end_control_op(walk_state, op);
- /* Make sure to properly pop the result stack */
-
- if (ACPI_SUCCESS(status)) {
- status = acpi_ds_result_stack_pop(walk_state);
- } else if (status == AE_CTRL_PENDING) {
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_PENDING;
- }
- }
break;
case AML_TYPE_METHOD_CALL:
@@ -516,7 +493,7 @@
op->common.node =
(struct acpi_namespace_node *)op->asl.value.
- arg->asl.node->object;
+ arg->asl.node;
acpi_ut_add_reference(op->asl.value.arg->asl.
node->object);
return_ACPI_STATUS(AE_OK);
@@ -632,13 +609,6 @@
break;
}
- /* Done with result state (Now that operand stack is built) */
-
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
/*
* If a result object was returned from above, push it on the
* current result stack
@@ -671,8 +641,28 @@
if (ACPI_FAILURE(status)) {
break;
}
+ } else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing DataTableRegion Strings Op=%p\n",
+ op));
- status = acpi_ds_result_stack_pop(walk_state);
+ status =
+ acpi_ds_eval_table_region_operands
+ (walk_state, op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
+ } else if (op->common.aml_opcode == AML_BANK_FIELD_OP) {
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Executing BankField Op=%p\n",
+ op));
+
+ status =
+ acpi_ds_eval_bank_field_operands(walk_state,
+ op);
+ if (ACPI_FAILURE(status)) {
+ break;
+ }
}
break;
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index 8ab9d1b..dff7a3e 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -443,6 +443,15 @@
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
+ } else if (op->common.aml_opcode == AML_DATA_REGION_OP) {
+ status =
+ acpi_ex_create_region(op->named.data,
+ op->named.length,
+ REGION_DATA_TABLE,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
}
#endif
@@ -767,6 +776,12 @@
acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
object_type, ACPI_IMODE_LOAD_PASS2, flags,
walk_state, &node);
+
+ if (ACPI_SUCCESS(status) && (flags & ACPI_NS_TEMPORARY)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
+ "***New Node [%4.4s] %p is temporary\n",
+ acpi_ut_get_node_name(node), node));
+ }
break;
}
@@ -823,6 +838,7 @@
struct acpi_namespace_node *new_node;
#ifndef ACPI_NO_METHOD_EXECUTION
u32 i;
+ u8 region_space;
#endif
ACPI_FUNCTION_TRACE(ds_load2_end_op);
@@ -1003,11 +1019,6 @@
status = acpi_ex_create_event(walk_state);
break;
- case AML_DATA_REGION_OP:
-
- status = acpi_ex_create_table_region(walk_state);
- break;
-
case AML_ALIAS_OP:
status = acpi_ex_create_alias(walk_state);
@@ -1035,6 +1046,15 @@
switch (op->common.aml_opcode) {
#ifndef ACPI_NO_METHOD_EXECUTION
case AML_REGION_OP:
+ case AML_DATA_REGION_OP:
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ region_space = (acpi_adr_space_type)
+ ((op->common.value.arg)->common.value.
+ integer);
+ } else {
+ region_space = REGION_DATA_TABLE;
+ }
/*
* If we are executing a method, initialize the region
@@ -1043,10 +1063,7 @@
status =
acpi_ex_create_region(op->named.data,
op->named.length,
- (acpi_adr_space_type)
- ((op->common.value.
- arg)->common.value.
- integer),
+ region_space,
walk_state);
if (ACPI_FAILURE(status)) {
return (status);
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
index 3927c49..9e60732 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index 5afcdd9..1386ced 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,85 +49,9 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME("dswstate")
-/* Local prototypes */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-acpi_status
-acpi_ds_result_insert(void *object,
- u32 index, struct acpi_walk_state *walk_state);
-
-acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state *walk_state);
-
-acpi_status
-acpi_ds_obj_stack_pop_object(union acpi_operand_object **object,
- struct acpi_walk_state *walk_state);
-
-void *acpi_ds_obj_stack_get_value(u32 index,
- struct acpi_walk_state *walk_state);
-#endif
-
-#ifdef ACPI_FUTURE_USAGE
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_remove
- *
- * PARAMETERS: Object - Where to return the popped object
- * Index - Where to extract the object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
- * other words, this is a FIFO.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_result_remove(union acpi_operand_object **object,
- u32 index, struct acpi_walk_state *walk_state)
-{
- union acpi_generic_state *state;
-
- ACPI_FUNCTION_NAME(ds_result_remove);
-
- state = walk_state->results;
- if (!state) {
- ACPI_ERROR((AE_INFO, "No result object pushed! State=%p",
- walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (index >= ACPI_OBJ_MAX_OPERAND) {
- ACPI_ERROR((AE_INFO,
- "Index out of range: %X State=%p Num=%X",
- index, walk_state, state->results.num_results));
- }
-
- /* Check for a valid result object */
-
- if (!state->results.obj_desc[index]) {
- ACPI_ERROR((AE_INFO,
- "Null operand! State=%p #Ops=%X, Index=%X",
- walk_state, state->results.num_results, index));
- return (AE_AML_NO_RETURN_VALUE);
- }
-
- /* Remove the object */
-
- state->results.num_results--;
-
- *object = state->results.obj_desc[index];
- state->results.obj_desc[index] = NULL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj=%p [%s] Index=%X State=%p Num=%X\n",
- *object,
- (*object) ? acpi_ut_get_object_type_name(*object) :
- "NULL", index, walk_state,
- state->results.num_results));
-
- return (AE_OK);
-}
-#endif /* ACPI_FUTURE_USAGE */
+ /* Local prototypes */
+static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *ws);
+static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *ws);
/*******************************************************************************
*
@@ -138,122 +62,67 @@
*
* RETURN: Status
*
- * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
- * other words, this is a FIFO.
+ * DESCRIPTION: Pop an object off the top of this walk's result stack
*
******************************************************************************/
acpi_status
-acpi_ds_result_pop(union acpi_operand_object ** object,
- struct acpi_walk_state * walk_state)
+acpi_ds_result_pop(union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state)
{
acpi_native_uint index;
union acpi_generic_state *state;
+ acpi_status status;
ACPI_FUNCTION_NAME(ds_result_pop);
state = walk_state->results;
- if (!state) {
- return (AE_OK);
+
+ /* Incorrect state of result stack */
+
+ if (state && !walk_state->result_count) {
+ ACPI_ERROR((AE_INFO, "No results on result stack"));
+ return (AE_AML_INTERNAL);
}
- if (!state->results.num_results) {
+ if (!state && walk_state->result_count) {
+ ACPI_ERROR((AE_INFO, "No result state for result stack"));
+ return (AE_AML_INTERNAL);
+ }
+
+ /* Empty result stack */
+
+ if (!state) {
ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p",
walk_state));
return (AE_AML_NO_RETURN_VALUE);
}
- /* Remove top element */
+ /* Return object of the top element and clean that top element result stack */
- state->results.num_results--;
+ walk_state->result_count--;
+ index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
- for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) {
-
- /* Check for a valid result object */
-
- if (state->results.obj_desc[index - 1]) {
- *object = state->results.obj_desc[index - 1];
- state->results.obj_desc[index - 1] = NULL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj=%p [%s] Index=%X State=%p Num=%X\n",
- *object,
- (*object) ?
- acpi_ut_get_object_type_name(*object)
- : "NULL", (u32) index - 1, walk_state,
- state->results.num_results));
-
- return (AE_OK);
- }
- }
-
- ACPI_ERROR((AE_INFO, "No result objects! State=%p", walk_state));
- return (AE_AML_NO_RETURN_VALUE);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_pop_from_bottom
- *
- * PARAMETERS: Object - Where to return the popped object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
- * other words, this is a FIFO.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_result_pop_from_bottom(union acpi_operand_object ** object,
- struct acpi_walk_state * walk_state)
-{
- acpi_native_uint index;
- union acpi_generic_state *state;
-
- ACPI_FUNCTION_NAME(ds_result_pop_from_bottom);
-
- state = walk_state->results;
- if (!state) {
+ *object = state->results.obj_desc[index];
+ if (!*object) {
ACPI_ERROR((AE_INFO,
- "No result object pushed! State=%p", walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (!state->results.num_results) {
- ACPI_ERROR((AE_INFO, "No result objects! State=%p",
+ "No result objects on result stack, State=%p",
walk_state));
return (AE_AML_NO_RETURN_VALUE);
}
- /* Remove Bottom element */
-
- *object = state->results.obj_desc[0];
-
- /* Push entire stack down one element */
-
- for (index = 0; index < state->results.num_results; index++) {
- state->results.obj_desc[index] =
- state->results.obj_desc[index + 1];
+ state->results.obj_desc[index] = NULL;
+ if (index == 0) {
+ status = acpi_ds_result_stack_pop(walk_state);
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
}
- state->results.num_results--;
-
- /* Check for a valid result object */
-
- if (!*object) {
- ACPI_ERROR((AE_INFO,
- "Null operand! State=%p #Ops=%X Index=%X",
- walk_state, state->results.num_results,
- (u32) index));
- return (AE_AML_NO_RETURN_VALUE);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] Results=%p State=%p\n",
- *object,
- (*object) ? acpi_ut_get_object_type_name(*object) :
- "NULL", state, walk_state));
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Obj=%p [%s] Index=%X State=%p Num=%X\n", *object,
+ acpi_ut_get_object_type_name(*object),
+ (u32) index, walk_state, walk_state->result_count));
return (AE_OK);
}
@@ -276,39 +145,56 @@
struct acpi_walk_state * walk_state)
{
union acpi_generic_state *state;
+ acpi_status status;
+ acpi_native_uint index;
ACPI_FUNCTION_NAME(ds_result_push);
+ if (walk_state->result_count > walk_state->result_size) {
+ ACPI_ERROR((AE_INFO, "Result stack is full"));
+ return (AE_AML_INTERNAL);
+ } else if (walk_state->result_count == walk_state->result_size) {
+
+ /* Extend the result stack */
+
+ status = acpi_ds_result_stack_push(walk_state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO,
+ "Failed to extend the result stack"));
+ return (status);
+ }
+ }
+
+ if (!(walk_state->result_count < walk_state->result_size)) {
+ ACPI_ERROR((AE_INFO, "No free elements in result stack"));
+ return (AE_AML_INTERNAL);
+ }
+
state = walk_state->results;
if (!state) {
ACPI_ERROR((AE_INFO, "No result stack frame during push"));
return (AE_AML_INTERNAL);
}
- if (state->results.num_results == ACPI_OBJ_NUM_OPERANDS) {
- ACPI_ERROR((AE_INFO,
- "Result stack overflow: Obj=%p State=%p Num=%X",
- object, walk_state, state->results.num_results));
- return (AE_STACK_OVERFLOW);
- }
-
if (!object) {
ACPI_ERROR((AE_INFO,
"Null Object! Obj=%p State=%p Num=%X",
- object, walk_state, state->results.num_results));
+ object, walk_state, walk_state->result_count));
return (AE_BAD_PARAMETER);
}
- state->results.obj_desc[state->results.num_results] = object;
- state->results.num_results++;
+ /* Assign the address of object to the top free element of result stack */
+
+ index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM;
+ state->results.obj_desc[index] = object;
+ walk_state->result_count++;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
object,
- object ?
acpi_ut_get_object_type_name((union
acpi_operand_object *)
- object) : "NULL",
- walk_state, state->results.num_results,
+ object), walk_state,
+ walk_state->result_count,
walk_state->current_result));
return (AE_OK);
@@ -322,16 +208,25 @@
*
* RETURN: Status
*
- * DESCRIPTION: Push an object onto the walk_state result stack.
+ * DESCRIPTION: Push an object onto the walk_state result stack
*
******************************************************************************/
-acpi_status acpi_ds_result_stack_push(struct acpi_walk_state * walk_state)
+static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state)
{
union acpi_generic_state *state;
ACPI_FUNCTION_NAME(ds_result_stack_push);
+ /* Check for stack overflow */
+
+ if (((u32) walk_state->result_size + ACPI_RESULTS_FRAME_OBJ_NUM) >
+ ACPI_RESULTS_OBJ_NUM_MAX) {
+ ACPI_ERROR((AE_INFO, "Result stack overflow: State=%p Num=%X",
+ walk_state, walk_state->result_size));
+ return (AE_STACK_OVERFLOW);
+ }
+
state = acpi_ut_create_generic_state();
if (!state) {
return (AE_NO_MEMORY);
@@ -340,6 +235,10 @@
state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT;
acpi_ut_push_generic_state(&walk_state->results, state);
+ /* Increase the length of the result stack by the length of frame */
+
+ walk_state->result_size += ACPI_RESULTS_FRAME_OBJ_NUM;
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n",
state, walk_state));
@@ -354,11 +253,11 @@
*
* RETURN: Status
*
- * DESCRIPTION: Pop an object off of the walk_state result stack.
+ * DESCRIPTION: Pop an object off of the walk_state result stack
*
******************************************************************************/
-acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state * walk_state)
+static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state)
{
union acpi_generic_state *state;
@@ -367,18 +266,27 @@
/* Check for stack underflow */
if (walk_state->results == NULL) {
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Underflow - State=%p\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+ "Result stack underflow - State=%p\n",
walk_state));
return (AE_AML_NO_OPERAND);
}
+ if (walk_state->result_size < ACPI_RESULTS_FRAME_OBJ_NUM) {
+ ACPI_ERROR((AE_INFO, "Insufficient result stack size"));
+ return (AE_AML_INTERNAL);
+ }
+
state = acpi_ut_pop_generic_state(&walk_state->results);
+ acpi_ut_delete_generic_state(state);
+
+ /* Decrease the length of result stack by the length of frame */
+
+ walk_state->result_size -= ACPI_RESULTS_FRAME_OBJ_NUM;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Result=%p RemainingResults=%X State=%p\n",
- state, state->results.num_results, walk_state));
-
- acpi_ut_delete_generic_state(state);
+ state, walk_state->result_count, walk_state));
return (AE_OK);
}
@@ -412,9 +320,13 @@
/* Put the object onto the stack */
- walk_state->operands[walk_state->num_operands] = object;
+ walk_state->operands[walk_state->operand_index] = object;
walk_state->num_operands++;
+ /* For the usual order of filling the operand stack */
+
+ walk_state->operand_index++;
+
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
object,
acpi_ut_get_object_type_name((union
@@ -484,43 +396,36 @@
*
******************************************************************************/
-acpi_status
+void
acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
- struct acpi_walk_state * walk_state)
+ struct acpi_walk_state *walk_state)
{
- u32 i;
+ acpi_native_int i;
union acpi_operand_object *obj_desc;
ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete);
- for (i = 0; i < pop_count; i++) {
+ if (pop_count == 0) {
+ return;
+ }
- /* Check for stack underflow */
-
+ for (i = (acpi_native_int) (pop_count - 1); i >= 0; i--) {
if (walk_state->num_operands == 0) {
- ACPI_ERROR((AE_INFO,
- "Object stack underflow! Count=%X State=%p #Ops=%X",
- pop_count, walk_state,
- walk_state->num_operands));
- return (AE_STACK_UNDERFLOW);
+ return;
}
/* Pop the stack and delete an object if present in this stack entry */
walk_state->num_operands--;
- obj_desc = walk_state->operands[walk_state->num_operands];
+ obj_desc = walk_state->operands[i];
if (obj_desc) {
- acpi_ut_remove_reference(walk_state->
- operands[walk_state->
- num_operands]);
- walk_state->operands[walk_state->num_operands] = NULL;
+ acpi_ut_remove_reference(walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
}
}
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n",
pop_count, walk_state, walk_state->num_operands));
-
- return (AE_OK);
}
/*******************************************************************************
@@ -560,7 +465,7 @@
*
* RETURN: None
*
- * DESCRIPTION: Place the Thread state at the head of the state list.
+ * DESCRIPTION: Place the Thread state at the head of the state list
*
******************************************************************************/
@@ -636,7 +541,6 @@
*thread)
{
struct acpi_walk_state *walk_state;
- acpi_status status;
ACPI_FUNCTION_TRACE(ds_create_walk_state);
@@ -659,14 +563,6 @@
acpi_ds_method_data_init(walk_state);
#endif
- /* Create an initial result stack entry */
-
- status = acpi_ds_result_stack_push(walk_state);
- if (ACPI_FAILURE(status)) {
- ACPI_FREE(walk_state);
- return_PTR(NULL);
- }
-
/* Put the new state at the head of the walk list */
if (thread) {
@@ -860,190 +756,3 @@
ACPI_FREE(walk_state);
return_VOID;
}
-
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_insert
- *
- * PARAMETERS: Object - Object to push
- * Index - Where to insert the object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Insert an object onto this walk's result stack
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_result_insert(void *object,
- u32 index, struct acpi_walk_state *walk_state)
-{
- union acpi_generic_state *state;
-
- ACPI_FUNCTION_NAME(ds_result_insert);
-
- state = walk_state->results;
- if (!state) {
- ACPI_ERROR((AE_INFO, "No result object pushed! State=%p",
- walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (index >= ACPI_OBJ_NUM_OPERANDS) {
- ACPI_ERROR((AE_INFO,
- "Index out of range: %X Obj=%p State=%p Num=%X",
- index, object, walk_state,
- state->results.num_results));
- return (AE_BAD_PARAMETER);
- }
-
- if (!object) {
- ACPI_ERROR((AE_INFO,
- "Null Object! Index=%X Obj=%p State=%p Num=%X",
- index, object, walk_state,
- state->results.num_results));
- return (AE_BAD_PARAMETER);
- }
-
- state->results.obj_desc[index] = object;
- state->results.num_results++;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
- "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
- object,
- object ?
- acpi_ut_get_object_type_name((union
- acpi_operand_object *)
- object) : "NULL",
- walk_state, state->results.num_results,
- walk_state->current_result));
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_delete_all
- *
- * PARAMETERS: walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Clear the object stack by deleting all objects that are on it.
- * Should be used with great care, if at all!
- *
- ******************************************************************************/
-
-acpi_status acpi_ds_obj_stack_delete_all(struct acpi_walk_state * walk_state)
-{
- u32 i;
-
- ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_delete_all, walk_state);
-
- /* The stack size is configurable, but fixed */
-
- for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) {
- if (walk_state->operands[i]) {
- acpi_ut_remove_reference(walk_state->operands[i]);
- walk_state->operands[i] = NULL;
- }
- }
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_pop_object
- *
- * PARAMETERS: Object - Where to return the popped object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
- * deleted by this routine.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_obj_stack_pop_object(union acpi_operand_object **object,
- struct acpi_walk_state *walk_state)
-{
- ACPI_FUNCTION_NAME(ds_obj_stack_pop_object);
-
- /* Check for stack underflow */
-
- if (walk_state->num_operands == 0) {
- ACPI_ERROR((AE_INFO,
- "Missing operand/stack empty! State=%p #Ops=%X",
- walk_state, walk_state->num_operands));
- *object = NULL;
- return (AE_AML_NO_OPERAND);
- }
-
- /* Pop the stack */
-
- walk_state->num_operands--;
-
- /* Check for a valid operand */
-
- if (!walk_state->operands[walk_state->num_operands]) {
- ACPI_ERROR((AE_INFO,
- "Null operand! State=%p #Ops=%X",
- walk_state, walk_state->num_operands));
- *object = NULL;
- return (AE_AML_NO_OPERAND);
- }
-
- /* Get operand and set stack entry to null */
-
- *object = walk_state->operands[walk_state->num_operands];
- walk_state->operands[walk_state->num_operands] = NULL;
-
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
- *object, acpi_ut_get_object_type_name(*object),
- walk_state, walk_state->num_operands));
-
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_get_value
- *
- * PARAMETERS: Index - Stack index whose value is desired. Based
- * on the top of the stack (index=0 == top)
- * walk_state - Current Walk state
- *
- * RETURN: Pointer to the requested operand
- *
- * DESCRIPTION: Retrieve an object from this walk's operand stack. Index must
- * be within the range of the current stack pointer.
- *
- ******************************************************************************/
-
-void *acpi_ds_obj_stack_get_value(u32 index, struct acpi_walk_state *walk_state)
-{
-
- ACPI_FUNCTION_TRACE_PTR(ds_obj_stack_get_value, walk_state);
-
- /* Can't do it if the stack is empty */
-
- if (walk_state->num_operands == 0) {
- return_PTR(NULL);
- }
-
- /* or if the index is past the top of the stack */
-
- if (index > (walk_state->num_operands - (u32) 1)) {
- return_PTR(NULL);
- }
-
- return_PTR(walk_state->
- operands[(acpi_native_uint) (walk_state->num_operands - 1) -
- index]);
-}
-#endif
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 7222a18..0924992 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -73,38 +73,14 @@
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
+#define ACPI_EC_UDELAY 100 /* Wait 100us before polling EC again */
enum {
EC_FLAGS_WAIT_GPE = 0, /* Don't check status until GPE arrives */
EC_FLAGS_QUERY_PENDING, /* Query is pending */
EC_FLAGS_GPE_MODE, /* Expect GPE to be sent for status change */
- EC_FLAGS_NO_ADDRESS_GPE, /* Expect GPE only for non-address event */
- EC_FLAGS_ADDRESS, /* Address is being written */
- EC_FLAGS_NO_WDATA_GPE, /* Don't expect WDATA GPE event */
- EC_FLAGS_WDATA, /* Data is being written */
- EC_FLAGS_NO_OBF1_GPE, /* Don't expect GPE before read */
-};
-
-static int acpi_ec_remove(struct acpi_device *device, int type);
-static int acpi_ec_start(struct acpi_device *device);
-static int acpi_ec_stop(struct acpi_device *device, int type);
-static int acpi_ec_add(struct acpi_device *device);
-
-static const struct acpi_device_id ec_device_ids[] = {
- {"PNP0C09", 0},
- {"", 0},
-};
-
-static struct acpi_driver acpi_ec_driver = {
- .name = "ec",
- .class = ACPI_EC_CLASS,
- .ids = ec_device_ids,
- .ops = {
- .add = acpi_ec_add,
- .remove = acpi_ec_remove,
- .start = acpi_ec_start,
- .stop = acpi_ec_stop,
- },
+ EC_FLAGS_NO_GPE, /* Don't use GPE mode */
+ EC_FLAGS_RESCHEDULE_POLL /* Re-schedule poll */
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -129,6 +105,8 @@
struct mutex lock;
wait_queue_head_t wait;
struct list_head list;
+ struct delayed_work work;
+ atomic_t irq_count;
u8 handlers_installed;
} *boot_ec, *first_ec;
@@ -177,65 +155,52 @@
return 0;
}
+static void ec_schedule_ec_poll(struct acpi_ec *ec)
+{
+ if (test_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags))
+ schedule_delayed_work(&ec->work,
+ msecs_to_jiffies(ACPI_EC_DELAY));
+}
+
+static void ec_switch_to_poll_mode(struct acpi_ec *ec)
+{
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ set_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
+}
+
static int acpi_ec_wait(struct acpi_ec *ec, enum ec_event event, int force_poll)
{
- int ret = 0;
-
- if (unlikely(event == ACPI_EC_EVENT_OBF_1 &&
- test_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags)))
- force_poll = 1;
- if (unlikely(test_bit(EC_FLAGS_ADDRESS, &ec->flags) &&
- test_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags)))
- force_poll = 1;
- if (unlikely(test_bit(EC_FLAGS_WDATA, &ec->flags) &&
- test_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags)))
- force_poll = 1;
+ atomic_set(&ec->irq_count, 0);
if (likely(test_bit(EC_FLAGS_GPE_MODE, &ec->flags)) &&
likely(!force_poll)) {
if (wait_event_timeout(ec->wait, acpi_ec_check_status(ec, event),
msecs_to_jiffies(ACPI_EC_DELAY)))
- goto end;
+ return 0;
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (acpi_ec_check_status(ec, event)) {
- if (event == ACPI_EC_EVENT_OBF_1) {
- /* miss OBF_1 GPE, don't expect it */
- pr_info(PREFIX "missing OBF confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_OBF1_GPE, &ec->flags);
- } else if (test_bit(EC_FLAGS_ADDRESS, &ec->flags)) {
- /* miss address GPE, don't expect it anymore */
- pr_info(PREFIX "missing address confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_ADDRESS_GPE, &ec->flags);
- } else if (test_bit(EC_FLAGS_WDATA, &ec->flags)) {
- /* miss write data GPE, don't expect it */
- pr_info(PREFIX "missing write data confirmation, "
- "don't expect it any longer.\n");
- set_bit(EC_FLAGS_NO_WDATA_GPE, &ec->flags);
- } else {
- /* missing GPEs, switch back to poll mode */
- if (printk_ratelimit())
- pr_info(PREFIX "missing confirmations, "
+ /* missing GPEs, switch back to poll mode */
+ if (printk_ratelimit())
+ pr_info(PREFIX "missing confirmations, "
"switch off interrupt mode.\n");
- clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
- }
- goto end;
+ ec_switch_to_poll_mode(ec);
+ ec_schedule_ec_poll(ec);
+ return 0;
}
} else {
unsigned long delay = jiffies + msecs_to_jiffies(ACPI_EC_DELAY);
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
while (time_before(jiffies, delay)) {
if (acpi_ec_check_status(ec, event))
- goto end;
+ return 0;
+ udelay(ACPI_EC_UDELAY);
}
}
- pr_err(PREFIX "acpi_ec_wait timeout,"
- " status = %d, expect_event = %d\n",
- acpi_ec_read_status(ec), event);
- ret = -ETIME;
- end:
- clear_bit(EC_FLAGS_ADDRESS, &ec->flags);
- return ret;
+ pr_err(PREFIX "acpi_ec_wait timeout, status = 0x%2.2x, event = %s\n",
+ acpi_ec_read_status(ec),
+ (event == ACPI_EC_EVENT_OBF_1) ? "\"b0=1\"" : "\"b1=0\"");
+ return -ETIME;
}
static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
@@ -245,8 +210,8 @@
{
int result = 0;
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
- acpi_ec_write_cmd(ec, command);
pr_debug(PREFIX "transaction start\n");
+ acpi_ec_write_cmd(ec, command);
for (; wdata_len > 0; --wdata_len) {
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
@@ -254,15 +219,11 @@
"write_cmd timeout, command = %d\n", command);
goto end;
}
- /* mark the address byte written to EC */
- if (rdata_len + wdata_len > 1)
- set_bit(EC_FLAGS_ADDRESS, &ec->flags);
set_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
acpi_ec_write_data(ec, *(wdata++));
}
if (!rdata_len) {
- set_bit(EC_FLAGS_WDATA, &ec->flags);
result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, force_poll);
if (result) {
pr_err(PREFIX
@@ -527,47 +488,51 @@
{
acpi_status status = AE_OK;
struct acpi_ec *ec = data;
+ u8 state = acpi_ec_read_status(ec);
pr_debug(PREFIX "~~~> interrupt\n");
+ atomic_inc(&ec->irq_count);
+ if (atomic_read(&ec->irq_count) > 5) {
+ pr_err(PREFIX "GPE storm detected, disabling EC GPE\n");
+ ec_switch_to_poll_mode(ec);
+ goto end;
+ }
clear_bit(EC_FLAGS_WAIT_GPE, &ec->flags);
if (test_bit(EC_FLAGS_GPE_MODE, &ec->flags))
wake_up(&ec->wait);
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI) {
+ if (state & ACPI_EC_FLAG_SCI) {
if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
status = acpi_os_execute(OSL_EC_BURST_HANDLER,
acpi_ec_gpe_query, ec);
- } else if (unlikely(!test_bit(EC_FLAGS_GPE_MODE, &ec->flags))) {
+ } else if (!test_bit(EC_FLAGS_GPE_MODE, &ec->flags) &&
+ !test_bit(EC_FLAGS_NO_GPE, &ec->flags) &&
+ in_interrupt()) {
/* this is non-query, must be confirmation */
if (printk_ratelimit())
pr_info(PREFIX "non-query interrupt received,"
" switching to interrupt mode\n");
set_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
}
-
+end:
+ ec_schedule_ec_poll(ec);
return ACPI_SUCCESS(status) ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
+static void do_ec_poll(struct work_struct *work)
+{
+ struct acpi_ec *ec = container_of(work, struct acpi_ec, work.work);
+ atomic_set(&ec->irq_count, 0);
+ (void)acpi_ec_gpe_handler(ec);
+}
+
/* --------------------------------------------------------------------------
Address Space Management
-------------------------------------------------------------------------- */
static acpi_status
-acpi_ec_space_setup(acpi_handle region_handle,
- u32 function, void *handler_context, void **return_context)
-{
- /*
- * The EC object is in the handler context and is needed
- * when calling the acpi_ec_space_handler.
- */
- *return_context = (function != ACPI_REGION_DEACTIVATE) ?
- handler_context : NULL;
-
- return AE_OK;
-}
-
-static acpi_status
acpi_ec_space_handler(u32 function, acpi_physical_address address,
u32 bits, acpi_integer *value,
void *handler_context, void *region_context)
@@ -669,16 +634,11 @@
return -ENODEV;
}
- entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_EC_FILE_INFO, S_IRUGO,
+ acpi_device_dir(device),
+ &acpi_ec_info_ops, acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_ec_info_ops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
@@ -709,6 +669,8 @@
mutex_init(&ec->lock);
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
+ INIT_DELAYED_WORK_DEFERRABLE(&ec->work, do_ec_poll);
+ atomic_set(&ec->irq_count, 0);
return ec;
}
@@ -741,17 +703,21 @@
status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
if (ACPI_FAILURE(status))
return status;
- /* Find and register all query methods */
- acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
- acpi_ec_register_query_methods, ec, NULL);
/* Use the global lock for all EC transactions? */
acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
ec->handle = handle;
return AE_CTRL_TERMINATE;
}
+static void ec_poll_stop(struct acpi_ec *ec)
+{
+ clear_bit(EC_FLAGS_RESCHEDULE_POLL, &ec->flags);
+ cancel_delayed_work(&ec->work);
+}
+
static void ec_remove_handlers(struct acpi_ec *ec)
{
+ ec_poll_stop(ec);
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
pr_err(PREFIX "failed to remove space handler\n");
@@ -771,31 +737,28 @@
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
/* Check for boot EC */
- if (boot_ec) {
- if (boot_ec->handle == device->handle) {
- /* Pre-loaded EC from DSDT, just move pointer */
- ec = boot_ec;
- boot_ec = NULL;
- goto end;
- } else if (boot_ec->handle == ACPI_ROOT_OBJECT) {
- /* ECDT-based EC, time to shut it down */
- ec_remove_handlers(boot_ec);
- kfree(boot_ec);
- first_ec = boot_ec = NULL;
+ if (boot_ec &&
+ (boot_ec->handle == device->handle ||
+ boot_ec->handle == ACPI_ROOT_OBJECT)) {
+ ec = boot_ec;
+ boot_ec = NULL;
+ } else {
+ ec = make_acpi_ec();
+ if (!ec)
+ return -ENOMEM;
+ if (ec_parse_device(device->handle, 0, ec, NULL) !=
+ AE_CTRL_TERMINATE) {
+ kfree(ec);
+ return -EINVAL;
}
}
- ec = make_acpi_ec();
- if (!ec)
- return -ENOMEM;
-
- if (ec_parse_device(device->handle, 0, ec, NULL) !=
- AE_CTRL_TERMINATE) {
- kfree(ec);
- return -EINVAL;
- }
ec->handle = device->handle;
- end:
+
+ /* Find and register all query methods */
+ acpi_walk_namespace(ACPI_TYPE_METHOD, ec->handle, 1,
+ acpi_ec_register_query_methods, ec, NULL);
+
if (!first_ec)
first_ec = ec;
acpi_driver_data(device) = ec;
@@ -870,7 +833,7 @@
status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
- &acpi_ec_space_setup, ec);
+ NULL, ec);
if (ACPI_FAILURE(status)) {
acpi_remove_gpe_handler(NULL, ec->gpe, &acpi_ec_gpe_handler);
return -ENODEV;
@@ -897,6 +860,7 @@
/* EC is fully operational, allow queries */
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+ ec_schedule_ec_poll(ec);
return ret;
}
@@ -924,6 +888,11 @@
return -EFAULT;
}
+static const struct acpi_device_id ec_device_ids[] = {
+ {"PNP0C09", 0},
+ {"", 0},
+};
+
int __init acpi_ec_ecdt_probe(void)
{
int ret;
@@ -944,6 +913,7 @@
boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe;
boot_ec->handle = ACPI_ROOT_OBJECT;
+ acpi_get_handle(ACPI_ROOT_OBJECT, ecdt_ptr->id, &boot_ec->handle);
} else {
/* This workaround is needed only on some broken machines,
* which require early EC, but fail to provide ECDT */
@@ -973,6 +943,39 @@
return -ENODEV;
}
+static int acpi_ec_suspend(struct acpi_device *device, pm_message_t state)
+{
+ struct acpi_ec *ec = acpi_driver_data(device);
+ /* Stop using GPE */
+ set_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
+ acpi_disable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ return 0;
+}
+
+static int acpi_ec_resume(struct acpi_device *device)
+{
+ struct acpi_ec *ec = acpi_driver_data(device);
+ /* Enable use of GPE back */
+ clear_bit(EC_FLAGS_NO_GPE, &ec->flags);
+ acpi_enable_gpe(NULL, ec->gpe, ACPI_NOT_ISR);
+ return 0;
+}
+
+static struct acpi_driver acpi_ec_driver = {
+ .name = "ec",
+ .class = ACPI_EC_CLASS,
+ .ids = ec_device_ids,
+ .ops = {
+ .add = acpi_ec_add,
+ .remove = acpi_ec_remove,
+ .start = acpi_ec_start,
+ .stop = acpi_ec_stop,
+ .suspend = acpi_ec_suspend,
+ .resume = acpi_ec_resume,
+ },
+};
+
static int __init acpi_ec_init(void)
{
int result = 0;
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index abec1ca..0c24bd4 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -102,6 +102,7 @@
}
static const struct file_operations acpi_system_event_ops = {
+ .owner = THIS_MODULE,
.open = acpi_system_open_event,
.read = acpi_system_read_event,
.release = acpi_system_close_event,
@@ -294,10 +295,9 @@
#ifdef CONFIG_ACPI_PROC_EVENT
/* 'event' [R] */
- entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_event_ops;
- else
+ entry = proc_create("event", S_IRUSR, acpi_root_dir,
+ &acpi_system_event_ops);
+ if (!entry)
return -ENODEV;
#endif
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index 3048801..5d30e5b 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index 0dadd2a..5354be4 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -248,10 +248,6 @@
ACPI_FUNCTION_TRACE(ev_disable_gpe);
- if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) {
- return_ACPI_STATUS(AE_OK);
- }
-
/* Make sure HW enable masks are updated */
status =
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 361ebe6..e6c4d4c 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index 21cb749..2113e58 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,22 +49,7 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evmisc")
-/* Names for Notify() values, used for debug output */
-#ifdef ACPI_DEBUG_OUTPUT
-static const char *acpi_notify_value_names[] = {
- "Bus Check",
- "Device Check",
- "Device Wake",
- "Eject Request",
- "Device Check Light",
- "Frequency Mismatch",
- "Bus Mode Mismatch",
- "Power Fault"
-};
-#endif
-
/* Pointer to FACS needed for the Global Lock */
-
static struct acpi_table_facs *facs = NULL;
/* Local prototypes */
@@ -94,7 +79,6 @@
switch (node->type) {
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_PROCESSOR:
- case ACPI_TYPE_POWER:
case ACPI_TYPE_THERMAL:
/*
* These are the ONLY objects that can receive ACPI notifications
@@ -139,17 +123,9 @@
* initiate soft-off or sleep operation?
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Dispatching Notify(%X) on node %p\n", notify_value,
- node));
-
- if (notify_value <= 7) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Notify value: %s\n",
- acpi_notify_value_names[notify_value]));
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Notify value: 0x%2.2X **Device Specific**\n",
- notify_value));
- }
+ "Dispatching Notify on [%4.4s] Node %p Value 0x%2.2X (%s)\n",
+ acpi_ut_get_node_name(node), node, notify_value,
+ acpi_ut_get_notify_name(notify_value)));
/* Get the notify object attached to the NS Node */
@@ -159,10 +135,12 @@
/* We have the notify object, Get the right handler */
switch (node->type) {
+
+ /* Notify allowed only on these types */
+
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_PROCESSOR:
- case ACPI_TYPE_POWER:
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_obj =
@@ -179,8 +157,13 @@
}
}
- /* If there is any handler to run, schedule the dispatcher */
-
+ /*
+ * If there is any handler to run, schedule the dispatcher.
+ * Check for:
+ * 1) Global system notify handler
+ * 2) Global device notify handler
+ * 3) Per-device notify handler
+ */
if ((acpi_gbl_system_notify.handler
&& (notify_value <= ACPI_MAX_SYS_NOTIFY))
|| (acpi_gbl_device_notify.handler
@@ -190,6 +173,13 @@
return (AE_NO_MEMORY);
}
+ if (!handler_obj) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Executing system notify handler for Notify (%4.4s, %X) node %p\n",
+ acpi_ut_get_node_name(node),
+ notify_value, node));
+ }
+
notify_info->common.descriptor_type =
ACPI_DESC_TYPE_STATE_NOTIFY;
notify_info->notify.node = node;
@@ -202,15 +192,12 @@
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(notify_info);
}
- }
-
- if (!handler_obj) {
+ } else {
/*
- * There is no per-device notify handler for this device.
- * This may or may not be a problem.
+ * There is no notify handler (per-device or system) for this device.
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "No notify handler for Notify(%4.4s, %X) node %p\n",
+ "No notify handler for Notify (%4.4s, %X) node %p\n",
acpi_ut_get_node_name(node), notify_value,
node));
}
@@ -349,9 +336,10 @@
ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
- status =
- acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- (struct acpi_table_header **)&facs);
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &facs));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -439,7 +427,8 @@
* Only one thread can acquire the GL at a time, the global_lock_mutex
* enforces this. This interface releases the interpreter if we must wait.
*/
- status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, 0);
+ status = acpi_ex_system_wait_mutex(
+ acpi_gbl_global_lock_mutex->mutex.os_mutex, 0);
if (status == AE_TIME) {
if (acpi_ev_global_lock_thread_id == acpi_os_get_thread_id()) {
acpi_ev_global_lock_acquired++;
@@ -448,9 +437,9 @@
}
if (ACPI_FAILURE(status)) {
- status =
- acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex,
- timeout);
+ status = acpi_ex_system_wait_mutex(
+ acpi_gbl_global_lock_mutex->mutex.os_mutex,
+ timeout);
}
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -460,6 +449,19 @@
acpi_ev_global_lock_acquired++;
/*
+ * Update the global lock handle and check for wraparound. The handle is
+ * only used for the external global lock interfaces, but it is updated
+ * here to properly handle the case where a single thread may acquire the
+ * lock via both the AML and the acpi_acquire_global_lock interfaces. The
+ * handle is therefore updated on the first acquire from a given thread
+ * regardless of where the acquisition request originated.
+ */
+ acpi_gbl_global_lock_handle++;
+ if (acpi_gbl_global_lock_handle == 0) {
+ acpi_gbl_global_lock_handle = 1;
+ }
+
+ /*
* Make sure that a global lock actually exists. If not, just treat
* the lock as a standard mutex.
*/
@@ -555,7 +557,7 @@
/* Release the local GL mutex */
acpi_ev_global_lock_thread_id = NULL;
acpi_ev_global_lock_acquired = 0;
- acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
+ acpi_os_release_mutex(acpi_gbl_global_lock_mutex->mutex.os_mutex);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 58ad097..1628f59 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -394,7 +394,7 @@
ACPI_DEBUG_PRINT((ACPI_DB_OPREGION,
"Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
®ion_obj->region.handler->address_space, handler,
- ACPI_FORMAT_UINT64(address),
+ ACPI_FORMAT_NATIVE_UINT(address),
acpi_ut_get_region_name(region_obj->region.
space_id)));
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index b1aaa0e..2e3d2c5 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
index 7e5d15c..2a8b778 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/events/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 6d866a0..94a6efe 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -758,6 +758,12 @@
*
* DESCRIPTION: Acquire the ACPI Global Lock
*
+ * Note: Allows callers with the same thread ID to acquire the global lock
+ * multiple times. In other words, externally, the behavior of the global lock
+ * is identical to an AML mutex. On the first acquire, a new handle is
+ * returned. On any subsequent calls to acquire by the same thread, the same
+ * handle is returned.
+ *
******************************************************************************/
acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
{
@@ -770,14 +776,19 @@
/* Must lock interpreter to prevent race conditions */
acpi_ex_enter_interpreter();
- status = acpi_ev_acquire_global_lock(timeout);
- acpi_ex_exit_interpreter();
+
+ status = acpi_ex_acquire_mutex_object(timeout,
+ acpi_gbl_global_lock_mutex,
+ acpi_os_get_thread_id());
if (ACPI_SUCCESS(status)) {
- acpi_gbl_global_lock_handle++;
+
+ /* Return the global lock handle (updated in acpi_ev_acquire_global_lock) */
+
*handle = acpi_gbl_global_lock_handle;
}
+ acpi_ex_exit_interpreter();
return (status);
}
@@ -798,11 +809,11 @@
{
acpi_status status;
- if (handle != acpi_gbl_global_lock_handle) {
+ if (!handle || (handle != acpi_gbl_global_lock_handle)) {
return (AE_NOT_ACQUIRED);
}
- status = acpi_ev_release_global_lock();
+ status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
return (status);
}
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index 9cbd341..99a7502 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
index 7bf09c5..e875080 100644
--- a/drivers/acpi/events/evxfregn.c
+++ b/drivers/acpi/events/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index 25802f3..24da921 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -45,7 +45,6 @@
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
-#include <acpi/acevents.h>
#include <acpi/actables.h>
#include <acpi/acdispat.h>
@@ -138,6 +137,14 @@
ACPI_FUNCTION_TRACE(ex_load_table_op);
+ /* Validate lengths for the signature_string, OEMIDString, OEMtable_iD */
+
+ if ((operand[0]->string.length > ACPI_NAME_SIZE) ||
+ (operand[1]->string.length > ACPI_OEM_ID_SIZE) ||
+ (operand[2]->string.length > ACPI_OEM_TABLE_ID_SIZE)) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
/* Find the ACPI table in the RSDT/XSDT */
status = acpi_tb_find_table(operand[0]->string.pointer,
@@ -229,11 +236,18 @@
status = acpi_get_table_by_index(table_index, &table);
if (ACPI_SUCCESS(status)) {
ACPI_INFO((AE_INFO,
- "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
+ "Dynamic OEM Table Load - [%.4s] OemId [%.6s] OemTableId [%.8s]",
table->signature, table->oem_id,
table->oem_table_id));
}
+ /* Invoke table handler if present */
+
+ if (acpi_gbl_table_handler) {
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
+ acpi_gbl_table_handler_context);
+ }
+
*return_desc = ddb_handle;
return_ACPI_STATUS(status);
}
@@ -268,6 +282,7 @@
struct acpi_table_desc table_desc;
acpi_native_uint table_index;
acpi_status status;
+ u32 length;
ACPI_FUNCTION_TRACE(ex_load_op);
@@ -278,16 +293,16 @@
switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
case ACPI_TYPE_REGION:
+ ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
+ obj_desc,
+ acpi_ut_get_object_type_name(obj_desc)));
+
/* Region must be system_memory (from ACPI spec) */
if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
- obj_desc,
- acpi_ut_get_object_type_name(obj_desc)));
-
/*
* If the Region Address and Length have not been previously evaluated,
* evaluate them now and save the results.
@@ -299,6 +314,11 @@
}
}
+ /*
+ * We will simply map the memory region for the table. However, the
+ * memory region is technically not guaranteed to remain stable and
+ * we may eventually have to copy the table to a local buffer.
+ */
table_desc.address = obj_desc->region.address;
table_desc.length = obj_desc->region.length;
table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
@@ -306,18 +326,41 @@
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
- /* Simply extract the buffer from the buffer object */
-
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Load from Buffer or Field %p %s\n", obj_desc,
acpi_ut_get_object_type_name(obj_desc)));
- table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header,
- obj_desc->buffer.pointer);
- table_desc.length = table_desc.pointer->length;
- table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
+ length = obj_desc->buffer.length;
- obj_desc->buffer.pointer = NULL;
+ /* Must have at least an ACPI table header */
+
+ if (length < sizeof(struct acpi_table_header)) {
+ return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+ }
+
+ /* Validate checksum here. It won't get validated in tb_add_table */
+
+ status =
+ acpi_tb_verify_checksum(ACPI_CAST_PTR
+ (struct acpi_table_header,
+ obj_desc->buffer.pointer), length);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * We need to copy the buffer since the original buffer could be
+ * changed or deleted in the future
+ */
+ table_desc.pointer = ACPI_ALLOCATE(length);
+ if (!table_desc.pointer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ ACPI_MEMCPY(table_desc.pointer, obj_desc->buffer.pointer,
+ length);
+ table_desc.length = length;
+ table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
break;
default:
@@ -333,7 +376,8 @@
}
status =
- acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
+ acpi_ex_add_table(table_index, walk_state->scope_info->scope.node,
+ &ddb_handle);
if (ACPI_FAILURE(status)) {
/* On error, table_ptr was deallocated above */
@@ -349,11 +393,23 @@
/* table_ptr was deallocated above */
+ acpi_ut_remove_reference(ddb_handle);
return_ACPI_STATUS(status);
}
+ /* Invoke table handler if present */
+
+ if (acpi_gbl_table_handler) {
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD,
+ table_desc.pointer,
+ acpi_gbl_table_handler_context);
+ }
+
cleanup:
if (ACPI_FAILURE(status)) {
+
+ /* Delete allocated buffer or mapping */
+
acpi_tb_delete_table(&table_desc);
}
return_ACPI_STATUS(status);
@@ -376,6 +432,7 @@
acpi_status status = AE_OK;
union acpi_operand_object *table_desc = ddb_handle;
acpi_native_uint table_index;
+ struct acpi_table_header *table;
ACPI_FUNCTION_TRACE(ex_unload_table);
@@ -395,17 +452,25 @@
table_index = (acpi_native_uint) table_desc->reference.object;
+ /* Invoke table handler if present */
+
+ if (acpi_gbl_table_handler) {
+ status = acpi_get_table_by_index(table_index, &table);
+ if (ACPI_SUCCESS(status)) {
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_UNLOAD,
+ table,
+ acpi_gbl_table_handler_context);
+ }
+ }
+
/*
* Delete the entire namespace under this table Node
* (Offset contains the table_id)
*/
acpi_tb_delete_namespace_by_owner(table_index);
- acpi_tb_release_owner_id(table_index);
+ (void)acpi_tb_release_owner_id(table_index);
acpi_tb_set_table_loaded_flag(table_index, FALSE);
- /* Delete the table descriptor (ddb_handle) */
-
- acpi_ut_remove_reference(table_desc);
- return_ACPI_STATUS(status);
+ return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index 79f2c0d..fd954b4 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index 6e9a23e..60e62c4 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -96,6 +96,9 @@
* to the original Node.
*/
switch (target_node->type) {
+
+ /* For these types, the sub-object can change dynamically via a Store */
+
case ACPI_TYPE_INTEGER:
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
@@ -103,9 +106,18 @@
case ACPI_TYPE_BUFFER_FIELD:
/*
+ * These types open a new scope, so we need the NS node in order to access
+ * any children.
+ */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+ case ACPI_TYPE_LOCAL_SCOPE:
+
+ /*
* The new alias has the type ALIAS and points to the original
- * NS node, not the object itself. This is because for these
- * types, the object can change dynamically via a Store.
+ * NS node, not the object itself.
*/
alias_node->type = ACPI_TYPE_LOCAL_ALIAS;
alias_node->object =
@@ -115,9 +127,7 @@
case ACPI_TYPE_METHOD:
/*
- * The new alias has the type ALIAS and points to the original
- * NS node, not the object itself. This is because for these
- * types, the object can change dynamically via a Store.
+ * Control method aliases need to be differentiated
*/
alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS;
alias_node->object =
@@ -342,101 +352,6 @@
/*******************************************************************************
*
- * FUNCTION: acpi_ex_create_table_region
- *
- * PARAMETERS: walk_state - Current state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Create a new data_table_region object
- *
- ******************************************************************************/
-
-acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
-{
- acpi_status status;
- union acpi_operand_object **operand = &walk_state->operands[0];
- union acpi_operand_object *obj_desc;
- struct acpi_namespace_node *node;
- union acpi_operand_object *region_obj2;
- acpi_native_uint table_index;
- struct acpi_table_header *table;
-
- ACPI_FUNCTION_TRACE(ex_create_table_region);
-
- /* Get the Node from the object stack */
-
- node = walk_state->op->common.node;
-
- /*
- * If the region object is already attached to this node,
- * just return
- */
- if (acpi_ns_get_attached_object(node)) {
- return_ACPI_STATUS(AE_OK);
- }
-
- /* Find the ACPI table */
-
- status = acpi_tb_find_table(operand[1]->string.pointer,
- operand[2]->string.pointer,
- operand[3]->string.pointer, &table_index);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Create the region descriptor */
-
- obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_REGION);
- if (!obj_desc) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- region_obj2 = obj_desc->common.next_object;
- region_obj2->extra.region_context = NULL;
-
- status = acpi_get_table_by_index(table_index, &table);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
- /* Init the region from the operands */
-
- obj_desc->region.space_id = REGION_DATA_TABLE;
- obj_desc->region.address =
- (acpi_physical_address) ACPI_TO_INTEGER(table);
- obj_desc->region.length = table->length;
- obj_desc->region.node = node;
- obj_desc->region.flags = AOPOBJ_DATA_VALID;
-
- /* Install the new region object in the parent Node */
-
- status = acpi_ns_attach_object(node, obj_desc, ACPI_TYPE_REGION);
- if (ACPI_FAILURE(status)) {
- goto cleanup;
- }
-
- status = acpi_ev_initialize_region(obj_desc, FALSE);
- if (ACPI_FAILURE(status)) {
- if (status == AE_NOT_EXIST) {
- status = AE_OK;
- } else {
- goto cleanup;
- }
- }
-
- obj_desc->region.flags |= AOPOBJ_SETUP_COMPLETE;
-
- cleanup:
-
- /* Remove local reference to the object */
-
- acpi_ut_remove_reference(obj_desc);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ex_create_processor
*
* PARAMETERS: walk_state - Current state
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index 51c9c29..74f1b22 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -500,25 +500,28 @@
acpi_os_printf("Reference: Debug\n");
break;
- case AML_NAME_OP:
-
- ACPI_DUMP_PATHNAME(obj_desc->reference.object,
- "Reference: Name: ", ACPI_LV_INFO,
- _COMPONENT);
- ACPI_DUMP_ENTRY(obj_desc->reference.object,
- ACPI_LV_INFO);
- break;
-
case AML_INDEX_OP:
acpi_os_printf("Reference: Index %p\n",
obj_desc->reference.object);
break;
+ case AML_LOAD_OP:
+
+ acpi_os_printf("Reference: [DdbHandle] TableIndex %p\n",
+ obj_desc->reference.object);
+ break;
+
case AML_REF_OF_OP:
- acpi_os_printf("Reference: (RefOf) %p\n",
- obj_desc->reference.object);
+ acpi_os_printf("Reference: (RefOf) %p [%s]\n",
+ obj_desc->reference.object,
+ acpi_ut_get_type_name(((union
+ acpi_operand_object
+ *)obj_desc->
+ reference.
+ object)->common.
+ type));
break;
case AML_ARG_OP:
@@ -559,8 +562,9 @@
case AML_INT_NAMEPATH_OP:
- acpi_os_printf("Reference.Node->Name %X\n",
- obj_desc->reference.node->name.integer);
+ acpi_os_printf("Reference: Namepath %X [%4.4s]\n",
+ obj_desc->reference.node->name.integer,
+ obj_desc->reference.node->name.ascii);
break;
default:
@@ -640,8 +644,8 @@
acpi_os_printf("\n");
} else {
acpi_os_printf(" base %8.8X%8.8X Length %X\n",
- ACPI_FORMAT_UINT64(obj_desc->region.
- address),
+ ACPI_FORMAT_NATIVE_UINT(obj_desc->region.
+ address),
obj_desc->region.length);
}
break;
@@ -877,20 +881,43 @@
ret_buf.length = ACPI_ALLOCATE_LOCAL_BUFFER;
if (obj_desc->reference.opcode == AML_INT_NAMEPATH_OP) {
- acpi_os_printf("Named Object %p ", obj_desc->reference.node);
+ acpi_os_printf(" Named Object %p ", obj_desc->reference.node);
status =
acpi_ns_handle_to_pathname(obj_desc->reference.node,
&ret_buf);
if (ACPI_FAILURE(status)) {
- acpi_os_printf("Could not convert name to pathname\n");
+ acpi_os_printf(" Could not convert name to pathname\n");
} else {
acpi_os_printf("%s\n", (char *)ret_buf.pointer);
ACPI_FREE(ret_buf.pointer);
}
} else if (obj_desc->reference.object) {
- acpi_os_printf("\nReferenced Object: %p\n",
- obj_desc->reference.object);
+ if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) ==
+ ACPI_DESC_TYPE_OPERAND) {
+ acpi_os_printf(" Target: %p",
+ obj_desc->reference.object);
+ if (obj_desc->reference.opcode == AML_LOAD_OP) {
+ /*
+ * For DDBHandle reference,
+ * obj_desc->Reference.Object is the table index
+ */
+ acpi_os_printf(" [DDBHandle]\n");
+ } else {
+ acpi_os_printf(" [%s]\n",
+ acpi_ut_get_type_name(((union
+ acpi_operand_object
+ *)
+ obj_desc->
+ reference.
+ object)->
+ common.
+ type));
+ }
+ } else {
+ acpi_os_printf(" Target: %p\n",
+ obj_desc->reference.object);
+ }
}
}
@@ -976,7 +1003,9 @@
case ACPI_TYPE_LOCAL_REFERENCE:
- acpi_os_printf("[Object Reference] ");
+ acpi_os_printf("[Object Reference] %s",
+ (acpi_ps_get_opcode_info
+ (obj_desc->reference.opcode))->name);
acpi_ex_dump_reference_obj(obj_desc);
break;
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index 2d88a3d..3e440d8 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -71,7 +71,6 @@
union acpi_operand_object *buffer_desc;
acpi_size length;
void *buffer;
- u8 locked;
ACPI_FUNCTION_TRACE_PTR(ex_read_data_from_field, obj_desc);
@@ -111,9 +110,7 @@
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.
- field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/*
* Perform the read.
@@ -125,7 +122,7 @@
buffer.pointer),
ACPI_READ | (obj_desc->field.
attribute << 16));
- acpi_ex_release_global_lock(locked);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
goto exit;
}
@@ -175,13 +172,12 @@
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/* Read from the field */
status = acpi_ex_extract_from_field(obj_desc, buffer, (u32) length);
- acpi_ex_release_global_lock(locked);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
exit:
if (ACPI_FAILURE(status)) {
@@ -214,10 +210,7 @@
{
acpi_status status;
u32 length;
- u32 required_length;
void *buffer;
- void *new_buffer;
- u8 locked;
union acpi_operand_object *buffer_desc;
ACPI_FUNCTION_TRACE_PTR(ex_write_data_to_field, obj_desc);
@@ -278,9 +271,7 @@
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.
- field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/*
* Perform the write (returns status and perhaps data in the
@@ -291,7 +282,7 @@
(acpi_integer *) buffer,
ACPI_WRITE | (obj_desc->field.
attribute << 16));
- acpi_ex_release_global_lock(locked);
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
*result_desc = buffer_desc;
return_ACPI_STATUS(status);
@@ -319,35 +310,6 @@
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- /*
- * We must have a buffer that is at least as long as the field
- * we are writing to. This is because individual fields are
- * indivisible and partial writes are not supported -- as per
- * the ACPI specification.
- */
- new_buffer = NULL;
- required_length =
- ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
-
- if (length < required_length) {
-
- /* We need to create a new buffer */
-
- new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
- if (!new_buffer) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
-
- /*
- * Copy the original data to the new buffer, starting
- * at Byte zero. All unused (upper) bytes of the
- * buffer will be 0.
- */
- ACPI_MEMCPY((char *)new_buffer, (char *)buffer, length);
- buffer = new_buffer;
- length = required_length;
- }
-
ACPI_DEBUG_PRINT((ACPI_DB_BFIELD,
"FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
source_desc,
@@ -366,19 +328,12 @@
/* Lock entire transaction if requested */
- locked =
- acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
+ acpi_ex_acquire_global_lock(obj_desc->common_field.field_flags);
/* Write to the field */
status = acpi_ex_insert_into_field(obj_desc, buffer, length);
- acpi_ex_release_global_lock(locked);
-
- /* Free temporary buffer if we used one */
-
- if (new_buffer) {
- ACPI_FREE(new_buffer);
- }
+ acpi_ex_release_global_lock(obj_desc->common_field.field_flags);
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index 65a48b6..e336b5d 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -263,7 +263,8 @@
rgn_desc->region.space_id,
obj_desc->common_field.access_byte_width,
obj_desc->common_field.base_byte_offset,
- field_datum_byte_offset, (void *)address));
+ field_datum_byte_offset, ACPI_CAST_PTR(void,
+ address)));
/* Invoke the appropriate address_space/op_region handler */
@@ -805,18 +806,39 @@
u32 datum_count;
u32 field_datum_count;
u32 i;
+ u32 required_length;
+ void *new_buffer;
ACPI_FUNCTION_TRACE(ex_insert_into_field);
/* Validate input buffer */
- if (buffer_length <
- ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length)) {
- ACPI_ERROR((AE_INFO,
- "Field size %X (bits) is too large for buffer (%X)",
- obj_desc->common_field.bit_length, buffer_length));
+ new_buffer = NULL;
+ required_length =
+ ACPI_ROUND_BITS_UP_TO_BYTES(obj_desc->common_field.bit_length);
+ /*
+ * We must have a buffer that is at least as long as the field
+ * we are writing to. This is because individual fields are
+ * indivisible and partial writes are not supported -- as per
+ * the ACPI specification.
+ */
+ if (buffer_length < required_length) {
- return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
+ /* We need to create a new buffer */
+
+ new_buffer = ACPI_ALLOCATE_ZEROED(required_length);
+ if (!new_buffer) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /*
+ * Copy the original data to the new buffer, starting
+ * at Byte zero. All unused (upper) bytes of the
+ * buffer will be 0.
+ */
+ ACPI_MEMCPY((char *)new_buffer, (char *)buffer, buffer_length);
+ buffer = new_buffer;
+ buffer_length = required_length;
}
/*
@@ -866,7 +888,7 @@
merged_datum,
field_offset);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ goto exit;
}
field_offset += obj_desc->common_field.access_byte_width;
@@ -924,5 +946,11 @@
mask, merged_datum,
field_offset);
+ exit:
+ /* Free temporary buffer if we used one */
+
+ if (new_buffer) {
+ ACPI_FREE(new_buffer);
+ }
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index f13d1ce..cc956a5 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 6748e3e..c873ab4 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -126,6 +126,79 @@
/*******************************************************************************
*
+ * FUNCTION: acpi_ex_acquire_mutex_object
+ *
+ * PARAMETERS: time_desc - Timeout in milliseconds
+ * obj_desc - Mutex object
+ * Thread - Current thread state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
+ * path that supports multiple acquires by the same thread.
+ *
+ * MUTEX: Interpreter must be locked
+ *
+ * NOTE: This interface is called from three places:
+ * 1) From acpi_ex_acquire_mutex, via an AML Acquire() operator
+ * 2) From acpi_ex_acquire_global_lock when an AML Field access requires the
+ * global lock
+ * 3) From the external interface, acpi_acquire_global_lock
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_acquire_mutex_object(u16 timeout,
+ union acpi_operand_object *obj_desc,
+ acpi_thread_id thread_id)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE_PTR(ex_acquire_mutex_object, obj_desc);
+
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Support for multiple acquires by the owning thread */
+
+ if (obj_desc->mutex.thread_id == thread_id) {
+ /*
+ * The mutex is already owned by this thread, just increment the
+ * acquisition depth
+ */
+ obj_desc->mutex.acquisition_depth++;
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_acquire_global_lock(timeout);
+ } else {
+ status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
+ timeout);
+ }
+
+ if (ACPI_FAILURE(status)) {
+
+ /* Includes failure from a timeout on time_desc */
+
+ return_ACPI_STATUS(status);
+ }
+
+ /* Acquired the mutex: update mutex object */
+
+ obj_desc->mutex.thread_id = thread_id;
+ obj_desc->mutex.acquisition_depth = 1;
+ obj_desc->mutex.original_sync_level = 0;
+ obj_desc->mutex.owner_thread = NULL; /* Used only for AML Acquire() */
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_ex_acquire_mutex
*
* PARAMETERS: time_desc - Timeout integer
@@ -151,7 +224,7 @@
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Sanity check: we must have a valid thread ID */
+ /* Must have a valid thread ID */
if (!walk_state->thread) {
ACPI_ERROR((AE_INFO,
@@ -161,7 +234,7 @@
}
/*
- * Current Sync must be less than or equal to the sync level of the
+ * Current sync level must be less than or equal to the sync level of the
* mutex. This mechanism provides some deadlock prevention
*/
if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
@@ -172,51 +245,89 @@
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
- /* Support for multiple acquires by the owning thread */
+ status = acpi_ex_acquire_mutex_object((u16) time_desc->integer.value,
+ obj_desc,
+ walk_state->thread->thread_id);
+ if (ACPI_SUCCESS(status) && obj_desc->mutex.acquisition_depth == 1) {
+
+ /* Save Thread object, original/current sync levels */
+
+ obj_desc->mutex.owner_thread = walk_state->thread;
+ obj_desc->mutex.original_sync_level =
+ walk_state->thread->current_sync_level;
+ walk_state->thread->current_sync_level =
+ obj_desc->mutex.sync_level;
+
+ /* Link the mutex to the current thread for force-unlock at method exit */
+
+ acpi_ex_link_mutex(obj_desc, walk_state->thread);
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_release_mutex_object
+ *
+ * PARAMETERS: obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release a previously acquired Mutex, low level interface.
+ * Provides a common path that supports multiple releases (after
+ * previous multiple acquires) by the same thread.
+ *
+ * MUTEX: Interpreter must be locked
+ *
+ * NOTE: This interface is called from three places:
+ * 1) From acpi_ex_release_mutex, via an AML Acquire() operator
+ * 2) From acpi_ex_release_global_lock when an AML Field access requires the
+ * global lock
+ * 3) From the external interface, acpi_release_global_lock
+ *
+ ******************************************************************************/
+
+acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(ex_release_mutex_object);
+
+ if (obj_desc->mutex.acquisition_depth == 0) {
+ return (AE_NOT_ACQUIRED);
+ }
+
+ /* Match multiple Acquires with multiple Releases */
+
+ obj_desc->mutex.acquisition_depth--;
+ if (obj_desc->mutex.acquisition_depth != 0) {
+
+ /* Just decrement the depth and return */
+
+ return_ACPI_STATUS(AE_OK);
+ }
if (obj_desc->mutex.owner_thread) {
- if (obj_desc->mutex.owner_thread->thread_id ==
- walk_state->thread->thread_id) {
- /*
- * The mutex is already owned by this thread, just increment the
- * acquisition depth
- */
- obj_desc->mutex.acquisition_depth++;
- return_ACPI_STATUS(AE_OK);
- }
+
+ /* Unlink the mutex from the owner's list */
+
+ acpi_ex_unlink_mutex(obj_desc);
+ obj_desc->mutex.owner_thread = NULL;
}
- /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+ /* Release the mutex, special case for Global Lock */
- if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
- status =
- acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
+ status = acpi_ev_release_global_lock();
} else {
- status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
- (u16) time_desc->integer.
- value);
+ acpi_os_release_mutex(obj_desc->mutex.os_mutex);
}
- if (ACPI_FAILURE(status)) {
+ /* Clear mutex info */
- /* Includes failure from a timeout on time_desc */
-
- return_ACPI_STATUS(status);
- }
-
- /* Have the mutex: update mutex and walk info and save the sync_level */
-
- obj_desc->mutex.owner_thread = walk_state->thread;
- obj_desc->mutex.acquisition_depth = 1;
- obj_desc->mutex.original_sync_level =
- walk_state->thread->current_sync_level;
-
- walk_state->thread->current_sync_level = obj_desc->mutex.sync_level;
-
- /* Link the mutex to the current thread for force-unlock at method exit */
-
- acpi_ex_link_mutex(obj_desc, walk_state->thread);
- return_ACPI_STATUS(AE_OK);
+ obj_desc->mutex.thread_id = 0;
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
@@ -253,22 +364,13 @@
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
}
- /* Sanity check: we must have a valid thread ID */
-
- if (!walk_state->thread) {
- ACPI_ERROR((AE_INFO,
- "Cannot release Mutex [%4.4s], null thread info",
- acpi_ut_get_node_name(obj_desc->mutex.node)));
- return_ACPI_STATUS(AE_AML_INTERNAL);
- }
-
/*
* The Mutex is owned, but this thread must be the owner.
* Special case for Global Lock, any thread can release
*/
if ((obj_desc->mutex.owner_thread->thread_id !=
walk_state->thread->thread_id)
- && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
+ && (obj_desc != acpi_gbl_global_lock_mutex)) {
ACPI_ERROR((AE_INFO,
"Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
(unsigned long)walk_state->thread->thread_id,
@@ -278,45 +380,37 @@
return_ACPI_STATUS(AE_AML_NOT_OWNER);
}
+ /* Must have a valid thread ID */
+
+ if (!walk_state->thread) {
+ ACPI_ERROR((AE_INFO,
+ "Cannot release Mutex [%4.4s], null thread info",
+ acpi_ut_get_node_name(obj_desc->mutex.node)));
+ return_ACPI_STATUS(AE_AML_INTERNAL);
+ }
+
/*
* The sync level of the mutex must be less than or equal to the current
* sync level
*/
if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
ACPI_ERROR((AE_INFO,
- "Cannot release Mutex [%4.4s], incorrect SyncLevel",
- acpi_ut_get_node_name(obj_desc->mutex.node)));
+ "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d",
+ acpi_ut_get_node_name(obj_desc->mutex.node),
+ obj_desc->mutex.sync_level,
+ walk_state->thread->current_sync_level));
return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
}
- /* Match multiple Acquires with multiple Releases */
+ status = acpi_ex_release_mutex_object(obj_desc);
- obj_desc->mutex.acquisition_depth--;
- if (obj_desc->mutex.acquisition_depth != 0) {
+ if (obj_desc->mutex.acquisition_depth == 0) {
- /* Just decrement the depth and return */
+ /* Restore the original sync_level */
- return_ACPI_STATUS(AE_OK);
+ walk_state->thread->current_sync_level =
+ obj_desc->mutex.original_sync_level;
}
-
- /* Unlink the mutex from the owner's list */
-
- acpi_ex_unlink_mutex(obj_desc);
-
- /* Release the mutex, special case for Global Lock */
-
- if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
- status = acpi_ev_release_global_lock();
- } else {
- acpi_os_release_mutex(obj_desc->mutex.os_mutex);
- }
-
- /* Update the mutex and restore sync_level */
-
- obj_desc->mutex.owner_thread = NULL;
- walk_state->thread->current_sync_level =
- obj_desc->mutex.original_sync_level;
-
return_ACPI_STATUS(status);
}
@@ -357,7 +451,7 @@
/* Release the mutex, special case for Global Lock */
- if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ if (obj_desc == acpi_gbl_global_lock_mutex) {
/* Ignore errors */
@@ -369,6 +463,7 @@
/* Mark mutex unowned */
obj_desc->mutex.owner_thread = NULL;
+ obj_desc->mutex.thread_id = 0;
/* Update Thread sync_level (Last mutex is the important one) */
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index 308eae5..817e67b 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
index 252f10a..7c3bea5 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -121,6 +121,7 @@
if ((ACPI_FAILURE(status)) || walk_state->result_obj) {
acpi_ut_remove_reference(return_desc);
+ walk_state->result_obj = NULL;
} else {
/* Save the return value */
@@ -739,26 +740,38 @@
value = acpi_gbl_integer_byte_width;
break;
- case ACPI_TYPE_BUFFER:
- value = temp_desc->buffer.length;
- break;
-
case ACPI_TYPE_STRING:
value = temp_desc->string.length;
break;
+ case ACPI_TYPE_BUFFER:
+
+ /* Buffer arguments may not be evaluated at this point */
+
+ status = acpi_ds_get_buffer_arguments(temp_desc);
+ value = temp_desc->buffer.length;
+ break;
+
case ACPI_TYPE_PACKAGE:
+
+ /* Package arguments may not be evaluated at this point */
+
+ status = acpi_ds_get_package_arguments(temp_desc);
value = temp_desc->package.count;
break;
default:
ACPI_ERROR((AE_INFO,
- "Operand is not Buf/Int/Str/Pkg - found type %s",
+ "Operand must be Buffer/Integer/String/Package - found type %s",
acpi_ut_get_type_name(type)));
status = AE_AML_OPERAND_TYPE;
goto cleanup;
}
+ if (ACPI_FAILURE(status)) {
+ goto cleanup;
+ }
+
/*
* Now that we have the size of the object, create a result
* object to hold the value
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index 17e652e..8e8bbb6 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -241,10 +241,6 @@
goto cleanup;
}
- /* Return the remainder */
-
- walk_state->result_obj = return_desc1;
-
cleanup:
/*
* Since the remainder is not returned indirectly, remove a reference to
@@ -259,6 +255,12 @@
acpi_ut_remove_reference(return_desc1);
}
+ /* Save return object (the remainder) on success */
+
+ else {
+ walk_state->result_obj = return_desc1;
+ }
+
return_ACPI_STATUS(status);
}
@@ -490,6 +492,7 @@
if (ACPI_FAILURE(status)) {
acpi_ut_remove_reference(return_desc);
+ walk_state->result_obj = NULL;
}
return_ACPI_STATUS(status);
@@ -583,8 +586,6 @@
return_desc->integer.value = ACPI_INTEGER_MAX;
}
- walk_state->result_obj = return_desc;
-
cleanup:
/* Delete return object on error */
@@ -593,5 +594,11 @@
acpi_ut_remove_reference(return_desc);
}
+ /* Save return object on success */
+
+ else {
+ walk_state->result_obj = return_desc;
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
index 7fe67cf..9cb4197 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/executer/exoparg3.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -260,6 +260,7 @@
if (ACPI_FAILURE(status) || walk_state->result_obj) {
acpi_ut_remove_reference(return_desc);
+ walk_state->result_obj = NULL;
}
/* Set the return object and exit */
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
index bd80a9c..67d4873 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/executer/exoparg6.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -322,8 +322,6 @@
goto cleanup;
}
- walk_state->result_obj = return_desc;
-
cleanup:
/* Delete return object on error */
@@ -332,5 +330,11 @@
acpi_ut_remove_reference(return_desc);
}
+ /* Save return object on success */
+
+ else {
+ walk_state->result_obj = return_desc;
+ }
+
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index efe5d4b..3a2f8cd 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -412,6 +412,7 @@
acpi_status acpi_ex_prep_field_value(struct acpi_create_field_info *info)
{
union acpi_operand_object *obj_desc;
+ union acpi_operand_object *second_desc = NULL;
u32 type;
acpi_status status;
@@ -494,6 +495,20 @@
obj_desc->field.access_byte_width,
obj_desc->bank_field.region_obj,
obj_desc->bank_field.bank_obj));
+
+ /*
+ * Remember location in AML stream of the field unit
+ * opcode and operands -- since the bank_value
+ * operands must be evaluated.
+ */
+ second_desc = obj_desc->common.next_object;
+ second_desc->extra.aml_start =
+ ((union acpi_parse_object *)(info->data_register_node))->
+ named.data;
+ second_desc->extra.aml_length =
+ ((union acpi_parse_object *)(info->data_register_node))->
+ named.length;
+
break;
case ACPI_TYPE_LOCAL_INDEX_FIELD:
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 3f51b7e..7cd8bb5 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -160,7 +160,7 @@
if (!mem_info->mapped_logical_address) {
ACPI_ERROR((AE_INFO,
"Could not map memory at %8.8X%8.8X, size %X",
- ACPI_FORMAT_UINT64(address),
+ ACPI_FORMAT_NATIVE_UINT(address),
(u32) window_size));
mem_info->mapped_length = 0;
return_ACPI_STATUS(AE_NO_MEMORY);
@@ -182,7 +182,8 @@
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"System-Memory (width %d) R/W %d Address=%8.8X%8.8X\n",
- bit_width, function, ACPI_FORMAT_UINT64(address)));
+ bit_width, function,
+ ACPI_FORMAT_NATIVE_UINT(address)));
/*
* Perform the memory read or write
@@ -284,7 +285,8 @@
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"System-IO (width %d) R/W %d Address=%8.8X%8.8X\n",
- bit_width, function, ACPI_FORMAT_UINT64(address)));
+ bit_width, function,
+ ACPI_FORMAT_NATIVE_UINT(address)));
/* Decode the function parameter */
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 2b3a01c..5596f42 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -116,9 +116,11 @@
* Several object types require no further processing:
* 1) Device/Thermal objects don't have a "real" subobject, return the Node
* 2) Method locals and arguments have a pseudo-Node
+ * 3) 10/2007: Added method type to assist with Package construction.
*/
if ((entry_type == ACPI_TYPE_DEVICE) ||
(entry_type == ACPI_TYPE_THERMAL) ||
+ (entry_type == ACPI_TYPE_METHOD) ||
(node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) {
return_ACPI_STATUS(AE_OK);
}
@@ -214,7 +216,6 @@
/* For these objects, just return the object attached to the Node */
case ACPI_TYPE_MUTEX:
- case ACPI_TYPE_METHOD:
case ACPI_TYPE_POWER:
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_EVENT:
@@ -238,12 +239,11 @@
case ACPI_TYPE_LOCAL_REFERENCE:
switch (source_desc->reference.opcode) {
- case AML_LOAD_OP:
-
- /* This is a ddb_handle */
- /* Return an additional reference to the object */
-
+ case AML_LOAD_OP: /* This is a ddb_handle */
case AML_REF_OF_OP:
+ case AML_INDEX_OP:
+
+ /* Return an additional reference to the object */
obj_desc = source_desc;
acpi_ut_add_reference(obj_desc);
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index 6c64e55..b35f7c8 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -140,7 +140,6 @@
{
acpi_status status = AE_OK;
union acpi_operand_object *stack_desc;
- void *temp_node;
union acpi_operand_object *obj_desc = NULL;
u16 opcode;
@@ -156,23 +155,6 @@
opcode = stack_desc->reference.opcode;
switch (opcode) {
- case AML_NAME_OP:
-
- /*
- * Convert name reference to a namespace node
- * Then, acpi_ex_resolve_node_to_value can be used to get the value
- */
- temp_node = stack_desc->reference.object;
-
- /* Delete the Reference Object */
-
- acpi_ut_remove_reference(stack_desc);
-
- /* Return the namespace node */
-
- (*stack_ptr) = temp_node;
- break;
-
case AML_LOCAL_OP:
case AML_ARG_OP:
@@ -207,15 +189,25 @@
switch (stack_desc->reference.target_type) {
case ACPI_TYPE_BUFFER_FIELD:
- /* Just return - leave the Reference on the stack */
+ /* Just return - do not dereference */
break;
case ACPI_TYPE_PACKAGE:
+ /* If method call or copy_object - do not dereference */
+
+ if ((walk_state->opcode ==
+ AML_INT_METHODCALL_OP)
+ || (walk_state->opcode == AML_COPY_OP)) {
+ break;
+ }
+
+ /* Otherwise, dereference the package_index to a package element */
+
obj_desc = *stack_desc->reference.where;
if (obj_desc) {
/*
- * Valid obj descriptor, copy pointer to return value
+ * Valid object descriptor, copy pointer to return value
* (i.e., dereference the package index)
* Delete the ref object, increment the returned object
*/
@@ -224,11 +216,11 @@
*stack_ptr = obj_desc;
} else {
/*
- * A NULL object descriptor means an unitialized element of
+ * A NULL object descriptor means an uninitialized element of
* the package, can't dereference it
*/
ACPI_ERROR((AE_INFO,
- "Attempt to deref an Index to NULL pkg element Idx=%p",
+ "Attempt to dereference an Index to NULL package element Idx=%p",
stack_desc));
status = AE_AML_UNINITIALIZED_ELEMENT;
}
@@ -239,7 +231,7 @@
/* Invalid reference object */
ACPI_ERROR((AE_INFO,
- "Unknown TargetType %X in Index/Reference obj %p",
+ "Unknown TargetType %X in Index/Reference object %p",
stack_desc->reference.target_type,
stack_desc));
status = AE_AML_INTERNAL;
@@ -251,7 +243,7 @@
case AML_DEBUG_OP:
case AML_LOAD_OP:
- /* Just leave the object as-is */
+ /* Just leave the object as-is, do not dereference */
break;
@@ -390,10 +382,10 @@
}
/*
- * For reference objects created via the ref_of or Index operators,
- * we need to get to the base object (as per the ACPI specification
- * of the object_type and size_of operators). This means traversing
- * the list of possibly many nested references.
+ * For reference objects created via the ref_of, Index, or Load/load_table
+ * operators, we need to get to the base object (as per the ACPI
+ * specification of the object_type and size_of operators). This means
+ * traversing the list of possibly many nested references.
*/
while (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
switch (obj_desc->reference.opcode) {
@@ -463,6 +455,11 @@
}
break;
+ case AML_LOAD_OP:
+
+ type = ACPI_TYPE_DDB_HANDLE;
+ goto exit;
+
case AML_LOCAL_OP:
case AML_ARG_OP:
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index 09d897b..73e29e5 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -137,7 +137,6 @@
union acpi_operand_object *obj_desc;
acpi_status status = AE_OK;
u8 object_type;
- void *temp_node;
u32 arg_types;
const struct acpi_opcode_info *op_info;
u32 this_arg_type;
@@ -239,7 +238,6 @@
/*lint -fallthrough */
- case AML_NAME_OP:
case AML_INDEX_OP:
case AML_REF_OF_OP:
case AML_ARG_OP:
@@ -332,15 +330,6 @@
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
-
- if (obj_desc->reference.opcode == AML_NAME_OP) {
-
- /* Convert a named reference to the actual named object */
-
- temp_node = obj_desc->reference.object;
- acpi_ut_remove_reference(obj_desc);
- (*stack_ptr) = temp_node;
- }
goto next_operand;
case ARGI_DATAREFOBJ: /* Store operator only */
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index f4b69a6..76c875b 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -84,8 +84,12 @@
ACPI_FUNCTION_TRACE_PTR(ex_do_debug_object, source_desc);
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s",
- level, " "));
+ /* Print line header as long as we are not in the middle of an object display */
+
+ if (!((level > 0) && index == 0)) {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s",
+ level, " "));
+ }
/* Display index for package output only */
@@ -95,12 +99,12 @@
}
if (!source_desc) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "<Null Object>\n"));
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[Null Object]\n"));
return_VOID;
}
if (ACPI_GET_DESCRIPTOR_TYPE(source_desc) == ACPI_DESC_TYPE_OPERAND) {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s: ",
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%s ",
acpi_ut_get_object_type_name
(source_desc)));
@@ -123,6 +127,8 @@
return_VOID;
}
+ /* source_desc is of type ACPI_DESC_TYPE_OPERAND */
+
switch (ACPI_GET_OBJECT_TYPE(source_desc)) {
case ACPI_TYPE_INTEGER:
@@ -147,7 +153,7 @@
(u32) source_desc->buffer.length));
ACPI_DUMP_BUFFER(source_desc->buffer.pointer,
(source_desc->buffer.length <
- 32) ? source_desc->buffer.length : 32);
+ 256) ? source_desc->buffer.length : 256);
break;
case ACPI_TYPE_STRING:
@@ -160,7 +166,7 @@
case ACPI_TYPE_PACKAGE:
ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
- "[0x%.2X Elements]\n",
+ "[Contains 0x%.2X Elements]\n",
source_desc->package.count));
/* Output the entire contents of the package */
@@ -180,12 +186,59 @@
(source_desc->reference.opcode),
source_desc->reference.offset));
} else {
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]\n",
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "[%s]",
acpi_ps_get_opcode_name
(source_desc->reference.opcode)));
}
- if (source_desc->reference.object) {
+ if (source_desc->reference.opcode == AML_LOAD_OP) { /* Load and load_table */
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
+ " Table OwnerId %p\n",
+ source_desc->reference.object));
+ break;
+ }
+
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, " "));
+
+ /* Check for valid node first, then valid object */
+
+ if (source_desc->reference.node) {
+ if (ACPI_GET_DESCRIPTOR_TYPE
+ (source_desc->reference.node) !=
+ ACPI_DESC_TYPE_NAMED) {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
+ " %p - Not a valid namespace node\n",
+ source_desc->reference.
+ node));
+ } else {
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT,
+ "Node %p [%4.4s] ",
+ source_desc->reference.
+ node,
+ (source_desc->reference.
+ node)->name.ascii));
+
+ switch ((source_desc->reference.node)->type) {
+
+ /* These types have no attached object */
+
+ case ACPI_TYPE_DEVICE:
+ acpi_os_printf("Device\n");
+ break;
+
+ case ACPI_TYPE_THERMAL:
+ acpi_os_printf("Thermal Zone\n");
+ break;
+
+ default:
+ acpi_ex_do_debug_object((source_desc->
+ reference.
+ node)->object,
+ level + 4, 0);
+ break;
+ }
+ }
+ } else if (source_desc->reference.object) {
if (ACPI_GET_DESCRIPTOR_TYPE
(source_desc->reference.object) ==
ACPI_DESC_TYPE_NAMED) {
@@ -198,18 +251,13 @@
acpi_ex_do_debug_object(source_desc->reference.
object, level + 4, 0);
}
- } else if (source_desc->reference.node) {
- acpi_ex_do_debug_object((source_desc->reference.node)->
- object, level + 4, 0);
}
break;
default:
- ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%p %s\n",
- source_desc,
- acpi_ut_get_object_type_name
- (source_desc)));
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, "%p\n",
+ source_desc));
break;
}
@@ -313,7 +361,6 @@
* 4) Store to the debug object
*/
switch (ref_desc->reference.opcode) {
- case AML_NAME_OP:
case AML_REF_OF_OP:
/* Storing an object into a Name "container" */
@@ -415,11 +462,24 @@
*/
obj_desc = *(index_desc->reference.where);
- status =
- acpi_ut_copy_iobject_to_iobject(source_desc, &new_desc,
- walk_state);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ if (ACPI_GET_OBJECT_TYPE(source_desc) ==
+ ACPI_TYPE_LOCAL_REFERENCE
+ && source_desc->reference.opcode == AML_LOAD_OP) {
+
+ /* This is a DDBHandle, just add a reference to it */
+
+ acpi_ut_add_reference(source_desc);
+ new_desc = source_desc;
+ } else {
+ /* Normal object, copy it */
+
+ status =
+ acpi_ut_copy_iobject_to_iobject(source_desc,
+ &new_desc,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
}
if (obj_desc) {
@@ -571,10 +631,17 @@
/* If no implicit conversion, drop into the default case below */
- if ((!implicit_conversion) || (walk_state->opcode == AML_COPY_OP)) {
-
- /* Force execution of default (no implicit conversion) */
-
+ if ((!implicit_conversion) ||
+ ((walk_state->opcode == AML_COPY_OP) &&
+ (target_type != ACPI_TYPE_LOCAL_REGION_FIELD) &&
+ (target_type != ACPI_TYPE_LOCAL_BANK_FIELD) &&
+ (target_type != ACPI_TYPE_LOCAL_INDEX_FIELD))) {
+ /*
+ * Force execution of default (no implicit conversion). Note:
+ * copy_object does not perform an implicit conversion, as per the ACPI
+ * spec -- except in case of region/bank/index fields -- because these
+ * objects must retain their original type permanently.
+ */
target_type = ACPI_TYPE_ANY;
}
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index 1d622c6..a6d2168 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
index 8233d40..9a75ff0 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index 9460baf..68990f1 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,6 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
-#include <acpi/acevents.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exsystem")
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index 6b0aecc..86c0388 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,7 +61,6 @@
#include <acpi/acpi.h>
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
-#include <acpi/acevents.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME("exutils")
@@ -217,9 +216,10 @@
/*
* Object must be a valid number and we must be executing
- * a control method
+ * a control method. NS node could be there for AML_INT_NAMEPATH_OP.
*/
if ((!obj_desc) ||
+ (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) != ACPI_DESC_TYPE_OPERAND) ||
(ACPI_GET_OBJECT_TYPE(obj_desc) != ACPI_TYPE_INTEGER)) {
return;
}
@@ -240,72 +240,73 @@
* PARAMETERS: field_flags - Flags with Lock rule:
* always_lock or never_lock
*
- * RETURN: TRUE/FALSE indicating whether the lock was actually acquired
+ * RETURN: None
*
- * DESCRIPTION: Obtain the global lock and keep track of this fact via two
- * methods. A global variable keeps the state of the lock, and
- * the state is returned to the caller.
+ * DESCRIPTION: Obtain the ACPI hardware Global Lock, only if the field
+ * flags specifiy that it is to be obtained before field access.
*
******************************************************************************/
-u8 acpi_ex_acquire_global_lock(u32 field_flags)
+void acpi_ex_acquire_global_lock(u32 field_flags)
{
- u8 locked = FALSE;
acpi_status status;
ACPI_FUNCTION_TRACE(ex_acquire_global_lock);
- /* Only attempt lock if the always_lock bit is set */
+ /* Only use the lock if the always_lock bit is set */
- if (field_flags & AML_FIELD_LOCK_RULE_MASK) {
-
- /* We should attempt to get the lock, wait forever */
-
- status = acpi_ev_acquire_global_lock(ACPI_WAIT_FOREVER);
- if (ACPI_SUCCESS(status)) {
- locked = TRUE;
- } else {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not acquire Global Lock"));
- }
+ if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) {
+ return_VOID;
}
- return_UINT8(locked);
+ /* Attempt to get the global lock, wait forever */
+
+ status = acpi_ex_acquire_mutex_object(ACPI_WAIT_FOREVER,
+ acpi_gbl_global_lock_mutex,
+ acpi_os_get_thread_id());
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not acquire Global Lock"));
+ }
+
+ return_VOID;
}
/*******************************************************************************
*
* FUNCTION: acpi_ex_release_global_lock
*
- * PARAMETERS: locked_by_me - Return value from corresponding call to
- * acquire_global_lock.
+ * PARAMETERS: field_flags - Flags with Lock rule:
+ * always_lock or never_lock
*
* RETURN: None
*
- * DESCRIPTION: Release the global lock if it is locked.
+ * DESCRIPTION: Release the ACPI hardware Global Lock
*
******************************************************************************/
-void acpi_ex_release_global_lock(u8 locked_by_me)
+void acpi_ex_release_global_lock(u32 field_flags)
{
acpi_status status;
ACPI_FUNCTION_TRACE(ex_release_global_lock);
- /* Only attempt unlock if the caller locked it */
+ /* Only use the lock if the always_lock bit is set */
- if (locked_by_me) {
+ if (!(field_flags & AML_FIELD_LOCK_RULE_MASK)) {
+ return_VOID;
+ }
- /* OK, now release the lock */
+ /* Release the global lock */
- status = acpi_ev_release_global_lock();
- if (ACPI_FAILURE(status)) {
+ status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
+ if (ACPI_FAILURE(status)) {
- /* Report the error, but there isn't much else we can do */
+ /* Report the error, but there isn't much else we can do */
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not release ACPI Global Lock"));
- }
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Could not release Global Lock"));
}
return_VOID;
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index c8e3cba..6cf10cb 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -192,17 +192,13 @@
}
/* 'status' [R/W] */
- entry = create_proc_entry(ACPI_FAN_FILE_STATE,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_FAN_FILE_STATE,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_fan_state_ops,
+ device);
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_fan_state_ops;
- entry->data = device;
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
@@ -260,24 +256,23 @@
result = PTR_ERR(cdev);
goto end;
}
- if (cdev) {
- printk(KERN_INFO PREFIX
- "%s is registered as cooling_device%d\n",
- device->dev.bus_id, cdev->id);
- acpi_driver_data(device) = cdev;
- result = sysfs_create_link(&device->dev.kobj,
- &cdev->device.kobj,
- "thermal_cooling");
- if (result)
- return result;
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev.bus_id, cdev->id);
- result = sysfs_create_link(&cdev->device.kobj,
- &device->dev.kobj,
- "device");
- if (result)
- return result;
- }
+ acpi_driver_data(device) = cdev;
+ result = sysfs_create_link(&device->dev.kobj,
+ &cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+
+ result = sysfs_create_link(&cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
result = acpi_fan_add_fs(device);
if (result)
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
index eda0978..06f8634 100644
--- a/drivers/acpi/glue.c
+++ b/drivers/acpi/glue.c
@@ -142,6 +142,7 @@
static int acpi_bind_one(struct device *dev, acpi_handle handle)
{
+ struct acpi_device *acpi_dev;
acpi_status status;
if (dev->archdata.acpi_handle) {
@@ -157,6 +158,16 @@
}
dev->archdata.acpi_handle = handle;
+ status = acpi_bus_get_device(handle, &acpi_dev);
+ if (!ACPI_FAILURE(status)) {
+ int ret;
+
+ ret = sysfs_create_link(&dev->kobj, &acpi_dev->dev.kobj,
+ "firmware_node");
+ ret = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj,
+ "physical_node");
+ }
+
return 0;
}
@@ -165,8 +176,17 @@
if (!dev->archdata.acpi_handle)
return 0;
if (dev == acpi_get_physical_device(dev->archdata.acpi_handle)) {
+ struct acpi_device *acpi_dev;
+
/* acpi_get_physical_device increase refcnt by one */
put_device(dev);
+
+ if (!acpi_bus_get_device(dev->archdata.acpi_handle,
+ &acpi_dev)) {
+ sysfs_remove_link(&dev->kobj, "firmware_node");
+ sysfs_remove_link(&acpi_dev->dev.kobj, "physical_node");
+ }
+
acpi_detach_data(dev->archdata.acpi_handle,
acpi_glue_data_handler);
dev->archdata.acpi_handle = NULL;
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
index 6031ca1..816894e 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 117a05c..14bc4f4 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index 73f9c5f..ddf792a 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -7,7 +7,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 4290e01..d9937e0 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,9 +70,10 @@
/* Get the FACS */
- status =
- acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- (struct acpi_table_header **)&facs);
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &facs));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -124,9 +125,10 @@
/* Get the FACS */
- status =
- acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
- (struct acpi_table_header **)&facs);
+ status = acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+ ACPI_CAST_INDIRECT_PTR(struct
+ acpi_table_header,
+ &facs));
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
index c32eab6..b53d575 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index 57faf59..c39a7f6 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -208,8 +208,7 @@
/* Special case for ACPI Global Lock */
if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
- acpi_gbl_global_lock_mutex =
- obj_desc->mutex.os_mutex;
+ acpi_gbl_global_lock_mutex = obj_desc;
/* Create additional counting semaphore for global lock */
@@ -582,44 +581,68 @@
return_ACPI_STATUS(status);
}
- /*
- * Sanity typecheck of the target object:
- *
- * If 1) This is the last segment (num_segments == 0)
- * 2) And we are looking for a specific type
- * (Not checking for TYPE_ANY)
- * 3) Which is not an alias
- * 4) Which is not a local type (TYPE_SCOPE)
- * 5) And the type of target object is known (not TYPE_ANY)
- * 6) And target object does not match what we are looking for
- *
- * Then we have a type mismatch. Just warn and ignore it.
- */
- if ((num_segments == 0) &&
- (type_to_check_for != ACPI_TYPE_ANY) &&
- (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) &&
- (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) &&
- (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) &&
- (this_node->type != ACPI_TYPE_ANY) &&
- (this_node->type != type_to_check_for)) {
+ /* More segments to follow? */
- /* Complain about a type mismatch */
-
- ACPI_WARNING((AE_INFO,
- "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)",
- ACPI_CAST_PTR(char, &simple_name),
- acpi_ut_get_type_name(this_node->type),
- acpi_ut_get_type_name
- (type_to_check_for)));
+ if (num_segments > 0) {
+ /*
+ * If we have an alias to an object that opens a scope (such as a
+ * device or processor), we need to dereference the alias here so that
+ * we can access any children of the original node (via the remaining
+ * segments).
+ */
+ if (this_node->type == ACPI_TYPE_LOCAL_ALIAS) {
+ if (acpi_ns_opens_scope
+ (((struct acpi_namespace_node *)this_node->
+ object)->type)) {
+ this_node =
+ (struct acpi_namespace_node *)
+ this_node->object;
+ }
+ }
}
- /*
- * If this is the last name segment and we are not looking for a
- * specific type, but the type of found object is known, use that type
- * to see if it opens a scope.
- */
- if ((num_segments == 0) && (type == ACPI_TYPE_ANY)) {
- type = this_node->type;
+ /* Special handling for the last segment (num_segments == 0) */
+
+ else {
+ /*
+ * Sanity typecheck of the target object:
+ *
+ * If 1) This is the last segment (num_segments == 0)
+ * 2) And we are looking for a specific type
+ * (Not checking for TYPE_ANY)
+ * 3) Which is not an alias
+ * 4) Which is not a local type (TYPE_SCOPE)
+ * 5) And the type of target object is known (not TYPE_ANY)
+ * 6) And target object does not match what we are looking for
+ *
+ * Then we have a type mismatch. Just warn and ignore it.
+ */
+ if ((type_to_check_for != ACPI_TYPE_ANY) &&
+ (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) &&
+ (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS)
+ && (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE)
+ && (this_node->type != ACPI_TYPE_ANY)
+ && (this_node->type != type_to_check_for)) {
+
+ /* Complain about a type mismatch */
+
+ ACPI_WARNING((AE_INFO,
+ "NsLookup: Type mismatch on %4.4s (%s), searching for (%s)",
+ ACPI_CAST_PTR(char, &simple_name),
+ acpi_ut_get_type_name(this_node->
+ type),
+ acpi_ut_get_type_name
+ (type_to_check_for)));
+ }
+
+ /*
+ * If this is the last name segment and we are not looking for a
+ * specific type, but the type of found object is known, use that type
+ * to (later) see if it opens a scope.
+ */
+ if (type == ACPI_TYPE_ANY) {
+ type = this_node->type;
+ }
}
/* Point to next name segment and make this node current */
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index 1d693d8..3a1740a 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index 1fc4f86..5445751 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -249,7 +249,9 @@
acpi_os_printf("ID %X Len %.4X Addr %p\n",
obj_desc->processor.proc_id,
obj_desc->processor.length,
- (char *)obj_desc->processor.address);
+ ACPI_CAST_PTR(void,
+ obj_desc->processor.
+ address));
break;
case ACPI_TYPE_DEVICE:
@@ -320,9 +322,8 @@
space_id));
if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
acpi_os_printf(" Addr %8.8X%8.8X Len %.4X\n",
- ACPI_FORMAT_UINT64(obj_desc->
- region.
- address),
+ ACPI_FORMAT_NATIVE_UINT
+ (obj_desc->region.address),
obj_desc->region.length);
} else {
acpi_os_printf
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
index 5097e16..428f50f 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 97b2ac5..14bdfa9 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index 33db224..6d6d930 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -244,6 +244,10 @@
info->field_count++;
break;
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ info->field_count++;
+ break;
+
case ACPI_TYPE_BUFFER:
info->buffer_count++;
break;
@@ -287,6 +291,12 @@
status = acpi_ds_get_buffer_field_arguments(obj_desc);
break;
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ info->field_init++;
+ status = acpi_ds_get_bank_field_arguments(obj_desc);
+ break;
+
case ACPI_TYPE_BUFFER:
info->buffer_init++;
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index d4f9654..2c92f6c 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -107,11 +107,11 @@
goto unlock;
}
- status = acpi_ns_parse_table(table_index, node->child);
+ status = acpi_ns_parse_table(table_index, node);
if (ACPI_SUCCESS(status)) {
acpi_tb_set_table_loaded_flag(table_index, TRUE);
} else {
- acpi_tb_release_owner_id(table_index);
+ (void)acpi_tb_release_owner_id(table_index);
}
unlock:
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index cbd94af..cffef1b 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -180,6 +180,12 @@
next_node = node;
while (next_node && (next_node != acpi_gbl_root_node)) {
+ if (ACPI_GET_DESCRIPTOR_TYPE(next_node) != ACPI_DESC_TYPE_NAMED) {
+ ACPI_ERROR((AE_INFO,
+ "Invalid NS Node (%p) while traversing path",
+ next_node));
+ return 0;
+ }
size += ACPI_PATH_SEGMENT_LENGTH;
next_node = acpi_ns_get_parent_node(next_node);
}
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
index d9d7377..15fe09e 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/namespace/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c
index e696aa8..46a79b0 100644
--- a/drivers/acpi/namespace/nsparse.c
+++ b/drivers/acpi/namespace/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -64,7 +64,8 @@
******************************************************************************/
acpi_status
acpi_ns_one_complete_parse(acpi_native_uint pass_number,
- acpi_native_uint table_index)
+ acpi_native_uint table_index,
+ struct acpi_namespace_node * start_node)
{
union acpi_parse_object *parse_root;
acpi_status status;
@@ -111,14 +112,25 @@
aml_start = (u8 *) table + sizeof(struct acpi_table_header);
aml_length = table->length - sizeof(struct acpi_table_header);
status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
- aml_start, aml_length, NULL,
- (u8) pass_number);
+ aml_start, (u32) aml_length,
+ NULL, (u8) pass_number);
}
if (ACPI_FAILURE(status)) {
acpi_ds_delete_walk_state(walk_state);
- acpi_ps_delete_parse_tree(parse_root);
- return_ACPI_STATUS(status);
+ goto cleanup;
+ }
+
+ /* start_node is the default location to load the table */
+
+ if (start_node && start_node != acpi_gbl_root_node) {
+ status =
+ acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD,
+ walk_state);
+ if (ACPI_FAILURE(status)) {
+ acpi_ds_delete_walk_state(walk_state);
+ goto cleanup;
+ }
}
/* Parse the AML */
@@ -127,6 +139,7 @@
(unsigned)pass_number));
status = acpi_ps_parse_aml(walk_state);
+ cleanup:
acpi_ps_delete_parse_tree(parse_root);
return_ACPI_STATUS(status);
}
@@ -163,7 +176,9 @@
* performs another complete parse of the AML.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n"));
- status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index);
+ status =
+ acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index,
+ start_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -178,7 +193,9 @@
* parse objects are all cached.
*/
ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n"));
- status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index);
+ status =
+ acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index,
+ start_node);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index e863be6..8399276 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index 90fd059..64c0398 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index 280b835..3c905ce 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -77,9 +77,7 @@
/* It's really the parent's _scope_ that we want */
- if (parent_node->child) {
- next_node = parent_node->child;
- }
+ next_node = parent_node->child;
}
else {
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index b92133f..a8d5491 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -467,10 +467,13 @@
return (AE_CTRL_DEPTH);
}
- if (!(flags & ACPI_STA_DEVICE_PRESENT)) {
-
- /* Don't examine children of the device if not present */
-
+ if (!(flags & ACPI_STA_DEVICE_PRESENT) &&
+ !(flags & ACPI_STA_DEVICE_FUNCTIONING)) {
+ /*
+ * Don't examine the children of the device only when the
+ * device is neither present nor functional. See ACPI spec,
+ * description of _STA for more information.
+ */
return (AE_CTRL_DEPTH);
}
@@ -539,7 +542,7 @@
* value is returned to the caller.
*
* This is a wrapper for walk_namespace, but the callback performs
- * additional filtering. Please see acpi_get_device_callback.
+ * additional filtering. Please see acpi_ns_get_device_callback.
*
******************************************************************************/
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index b489781..a287ed5 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index faa3758..2b375ee 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index a498a6c..235a138 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -742,6 +742,7 @@
void acpi_os_wait_events_complete(void *context)
{
flush_workqueue(kacpid_wq);
+ flush_workqueue(kacpi_notify_wq);
}
EXPORT_SYMBOL(acpi_os_wait_events_complete);
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index c2b9835..f1e8bf6 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -230,12 +230,12 @@
struct acpi_parse_state *parser_state,
union acpi_parse_object *arg, u8 possible_method_call)
{
+ acpi_status status;
char *path;
union acpi_parse_object *name_op;
- acpi_status status;
union acpi_operand_object *method_desc;
struct acpi_namespace_node *node;
- union acpi_generic_state scope_info;
+ u8 *start = parser_state->aml;
ACPI_FUNCTION_TRACE(ps_get_next_namepath);
@@ -249,25 +249,18 @@
return_ACPI_STATUS(AE_OK);
}
- /* Setup search scope info */
-
- scope_info.scope.node = NULL;
- node = parser_state->start_node;
- if (node) {
- scope_info.scope.node = node;
- }
-
/*
- * Lookup the name in the internal namespace. We don't want to add
- * anything new to the namespace here, however, so we use MODE_EXECUTE.
+ * Lookup the name in the internal namespace, starting with the current
+ * scope. We don't want to add anything new to the namespace here,
+ * however, so we use MODE_EXECUTE.
* Allow searching of the parent tree, but don't open a new scope -
* we just want to lookup the object (must be mode EXECUTE to perform
* the upsearch)
*/
- status =
- acpi_ns_lookup(&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
- ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
- NULL, &node);
+ status = acpi_ns_lookup(walk_state->scope_info, path,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
+ NULL, &node);
/*
* If this name is a control method invocation, we must
@@ -275,6 +268,16 @@
*/
if (ACPI_SUCCESS(status) &&
possible_method_call && (node->type == ACPI_TYPE_METHOD)) {
+ if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) {
+ /*
+ * acpi_ps_get_next_namestring has increased the AML pointer,
+ * so we need to restore the saved AML pointer for method call.
+ */
+ walk_state->parser_state.aml = start;
+ walk_state->arg_count = 1;
+ acpi_ps_init_op(arg, AML_INT_METHODCALL_OP);
+ return_ACPI_STATUS(AE_OK);
+ }
/* This name is actually a control method invocation */
@@ -686,9 +689,29 @@
return_ACPI_STATUS(AE_NO_MEMORY);
}
- status =
- acpi_ps_get_next_namepath(walk_state, parser_state,
- arg, 0);
+ /* To support super_name arg of Unload */
+
+ if (walk_state->op->common.aml_opcode == AML_UNLOAD_OP) {
+ status =
+ acpi_ps_get_next_namepath(walk_state,
+ parser_state, arg,
+ 1);
+
+ /*
+ * If the super_name arg of Unload is a method call,
+ * we have restored the AML pointer, just free this Arg
+ */
+ if (arg->common.aml_opcode ==
+ AML_INT_METHODCALL_OP) {
+ acpi_ps_free_op(arg);
+ arg = NULL;
+ }
+ } else {
+ status =
+ acpi_ps_get_next_namepath(walk_state,
+ parser_state, arg,
+ 0);
+ }
} else {
/* Single complex argument, nothing returned */
diff --git a/drivers/acpi/parser/psloop.c b/drivers/acpi/parser/psloop.c
index 773aee8..c06238e 100644
--- a/drivers/acpi/parser/psloop.c
+++ b/drivers/acpi/parser/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -182,6 +182,7 @@
ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
unnamed_op->common.value.arg = NULL;
+ unnamed_op->common.arg_list_length = 0;
unnamed_op->common.aml_opcode = walk_state->opcode;
/*
@@ -241,7 +242,8 @@
acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
acpi_gbl_depth++;
- if ((*op)->common.aml_opcode == AML_REGION_OP) {
+ if ((*op)->common.aml_opcode == AML_REGION_OP ||
+ (*op)->common.aml_opcode == AML_DATA_REGION_OP) {
/*
* Defer final parsing of an operation_region body, because we don't
* have enough info in the first pass to parse it correctly (i.e.,
@@ -280,6 +282,9 @@
acpi_status status = AE_OK;
union acpi_parse_object *op;
union acpi_parse_object *named_op = NULL;
+ union acpi_parse_object *parent_scope;
+ u8 argument_count;
+ const struct acpi_opcode_info *op_info;
ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
@@ -320,8 +325,32 @@
op->named.length = 0;
}
- acpi_ps_append_arg(acpi_ps_get_parent_scope
- (&(walk_state->parser_state)), op);
+ if (walk_state->opcode == AML_BANK_FIELD_OP) {
+ /*
+ * Backup to beginning of bank_field declaration
+ * body_length is unknown until we parse the body
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
+
+ parent_scope = acpi_ps_get_parent_scope(&(walk_state->parser_state));
+ acpi_ps_append_arg(parent_scope, op);
+
+ if (parent_scope) {
+ op_info =
+ acpi_ps_get_opcode_info(parent_scope->common.aml_opcode);
+ if (op_info->flags & AML_HAS_TARGET) {
+ argument_count =
+ acpi_ps_get_argument_count(op_info->type);
+ if (parent_scope->common.arg_list_length >
+ argument_count) {
+ op->common.flags |= ACPI_PARSEOP_TARGET;
+ }
+ } else if (parent_scope->common.aml_opcode == AML_INCREMENT_OP) {
+ op->common.flags |= ACPI_PARSEOP_TARGET;
+ }
+ }
if (walk_state->descending_callback != NULL) {
/*
@@ -603,13 +632,6 @@
acpi_ps_pop_scope(&(walk_state->parser_state), op,
&walk_state->arg_types,
&walk_state->arg_count);
-
- if ((*op)->common.aml_opcode != AML_WHILE_OP) {
- status2 = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
- }
}
/* Close this iteration of the While loop */
@@ -640,10 +662,6 @@
if (ACPI_FAILURE(status2)) {
return_ACPI_STATUS(status2);
}
- status2 = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_FAILURE(status2)) {
- return_ACPI_STATUS(status2);
- }
acpi_ut_delete_generic_state
(acpi_ut_pop_generic_state
@@ -1005,7 +1023,8 @@
acpi_gbl_depth--;
}
- if (op->common.aml_opcode == AML_REGION_OP) {
+ if (op->common.aml_opcode == AML_REGION_OP ||
+ op->common.aml_opcode == AML_DATA_REGION_OP) {
/*
* Skip parsing of control method or opregion body,
* because we don't have enough info in the first pass
@@ -1030,6 +1049,16 @@
(u32) (parser_state->aml - op->named.data);
}
+ if (op->common.aml_opcode == AML_BANK_FIELD_OP) {
+ /*
+ * Backup to beginning of bank_field declaration
+ *
+ * body_length is unknown until we parse the body
+ */
+ op->named.length =
+ (u32) (parser_state->aml - op->named.data);
+ }
+
/* This op complete, notify the dispatcher */
if (walk_state->ascending_callback != NULL) {
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 9296e86..f425ab3 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,9 @@
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME("psopcode")
+static const u8 acpi_gbl_argument_count[] =
+ { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
+
/*******************************************************************************
*
* NAME: acpi_gbl_aml_op_info
@@ -59,6 +62,7 @@
* the operand type.
*
******************************************************************************/
+
/*
* Summary of opcode types/flags
*
@@ -176,6 +180,7 @@
AML_CREATE_QWORD_FIELD_OP
******************************************************************************/
+
/*
* Master Opcode information table. A summary of everything we know about each
* opcode, all in one place.
@@ -515,9 +520,10 @@
AML_TYPE_NAMED_FIELD,
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
/* 5F */ ACPI_OP("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP,
- ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
+ ACPI_TYPE_LOCAL_BANK_FIELD, AML_CLASS_NAMED_OBJECT,
AML_TYPE_NAMED_FIELD,
- AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
+ AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD |
+ AML_DEFER),
/* Internal opcodes that map to invalid AML opcodes */
@@ -619,9 +625,9 @@
AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R),
/* 7C */ ACPI_OP("DataTableRegion", ARGP_DATA_REGION_OP,
ARGI_DATA_REGION_OP, ACPI_TYPE_REGION,
- AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE,
+ AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX,
AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE |
- AML_NSNODE | AML_NAMED),
+ AML_NSNODE | AML_NAMED | AML_DEFER),
/* 7D */ ACPI_OP("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP,
ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT,
AML_TYPE_NAMED_NO_OBJ,
@@ -779,3 +785,25 @@
#endif
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_argument_count
+ *
+ * PARAMETERS: op_type - Type associated with the AML opcode
+ *
+ * RETURN: Argument count
+ *
+ * DESCRIPTION: Obtain the number of expected arguments for an AML opcode
+ *
+ ******************************************************************************/
+
+u8 acpi_ps_get_argument_count(u32 op_type)
+{
+
+ if (op_type <= AML_TYPE_EXEC_6A_0T_1R) {
+ return (acpi_gbl_argument_count[op_type]);
+ }
+
+ return (0);
+}
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index 5d63f48..15e1702 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -205,6 +205,8 @@
|| (op->common.parent->common.aml_opcode ==
AML_PACKAGE_OP)
|| (op->common.parent->common.aml_opcode ==
+ AML_BANK_FIELD_OP)
+ || (op->common.parent->common.aml_opcode ==
AML_VAR_PACKAGE_OP)) {
replacement_op =
acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP);
@@ -349,19 +351,13 @@
parser_state->aml = walk_state->aml_last_while;
walk_state->control_state->common.value = FALSE;
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_BREAK;
- }
+ status = AE_CTRL_BREAK;
break;
case AE_CTRL_CONTINUE:
parser_state->aml = walk_state->aml_last_while;
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_CONTINUE;
- }
+ status = AE_CTRL_CONTINUE;
break;
case AE_CTRL_PENDING:
@@ -383,10 +379,7 @@
* Just close out this package
*/
parser_state->aml = acpi_ps_get_next_package_end(parser_state);
- status = acpi_ds_result_stack_pop(walk_state);
- if (ACPI_SUCCESS(status)) {
- status = AE_CTRL_PENDING;
- }
+ status = AE_CTRL_PENDING;
break;
case AE_CTRL_FALSE:
@@ -541,7 +534,7 @@
if ((status == AE_ALREADY_EXISTS) &&
(!walk_state->method_desc->method.mutex)) {
ACPI_INFO((AE_INFO,
- "Marking method %4.4s as Serialized",
+ "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error",
walk_state->method_node->name.
ascii));
@@ -601,6 +594,30 @@
* The object is deleted
*/
if (!previous_walk_state->return_desc) {
+ /*
+ * In slack mode execution, if there is no return value
+ * we should implicitly return zero (0) as a default value.
+ */
+ if (acpi_gbl_enable_interpreter_slack &&
+ !previous_walk_state->
+ implicit_return_obj) {
+ previous_walk_state->
+ implicit_return_obj =
+ acpi_ut_create_internal_object
+ (ACPI_TYPE_INTEGER);
+ if (!previous_walk_state->
+ implicit_return_obj) {
+ return_ACPI_STATUS
+ (AE_NO_MEMORY);
+ }
+
+ previous_walk_state->
+ implicit_return_obj->
+ integer.value = 0;
+ }
+
+ /* Restart the calling control method */
+
status =
acpi_ds_restart_control_method
(walk_state,
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
index 77cfa4e..ee50e67 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/parser/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
index 966e7ea..1dd355d 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/parser/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -171,6 +171,8 @@
while (arg) {
arg->common.parent = op;
arg = arg->common.next;
+
+ op->common.arg_list_length++;
}
}
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index 8ca5200..7cf1f65 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
index 49f9757..8b86ad5 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
index 94103bc..5258145 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index 76bf6d9..81e4f08 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -93,6 +93,7 @@
static struct list_head acpi_power_resource_list;
static const struct file_operations acpi_power_fops = {
+ .owner = THIS_MODULE,
.open = acpi_power_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -121,7 +122,7 @@
}
*resource = acpi_driver_data(device);
- if (!resource)
+ if (!*resource)
return -ENODEV;
return 0;
@@ -543,15 +544,11 @@
}
/* 'status' [R] */
- entry = create_proc_entry(ACPI_POWER_FILE_STATUS,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_POWER_FILE_STATUS,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_power_fops, acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_power_fops;
- entry->data = acpi_driver_data(device);
- }
-
return 0;
}
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index a825b43..386e5aa 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -112,6 +112,7 @@
#define UNINSTALL_NOTIFY_HANDLER 2
static const struct file_operations acpi_processor_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -326,40 +327,30 @@
acpi_device_dir(device)->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_INFO,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_processor_info_fops,
+ acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_processor_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'throttling' [R/W] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_THROTTLING,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_processor_throttling_fops,
+ acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_processor_throttling_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'limit' [R/W] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_LIMIT,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_processor_limit_fops,
+ acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_processor_limit_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
@@ -612,6 +603,15 @@
request_region(pr->throttling.address, 6, "ACPI CPU throttle");
}
+ /*
+ * If ACPI describes a slot number for this CPU, we can use it
+ * ensure we get the right value in the "physical id" field
+ * of /proc/cpuinfo
+ */
+ status = acpi_evaluate_object(pr->handle, "_SUN", NULL, &buffer);
+ if (ACPI_SUCCESS(status))
+ arch_fix_phys_package_id(pr->id, object.integer.value);
+
return 0;
}
@@ -674,22 +674,21 @@
result = PTR_ERR(pr->cdev);
goto end;
}
- if (pr->cdev) {
- printk(KERN_INFO PREFIX
- "%s is registered as cooling_device%d\n",
- device->dev.bus_id, pr->cdev->id);
- result = sysfs_create_link(&device->dev.kobj,
- &pr->cdev->device.kobj,
- "thermal_cooling");
- if (result)
- return result;
- result = sysfs_create_link(&pr->cdev->device.kobj,
- &device->dev.kobj,
- "device");
- if (result)
- return result;
- }
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev.bus_id, pr->cdev->id);
+
+ result = sysfs_create_link(&device->dev.kobj,
+ &pr->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ result = sysfs_create_link(&pr->cdev->device.kobj,
+ &device->dev.kobj,
+ "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
if (pr->flags.throttling) {
printk(KERN_INFO PREFIX "%s [%s] (supports",
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 0d90ff5..2dd2c1f 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -847,6 +847,7 @@
/* all processors need to support C1 */
pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
pr->power.states[ACPI_STATE_C1].valid = 1;
+ pr->power.states[ACPI_STATE_C1].entry_method = ACPI_CSTATE_HALT;
}
/* the C0 state only exists as a filler in our array */
pr->power.states[ACPI_STATE_C0].valid = 1;
@@ -959,6 +960,9 @@
cx.address);
}
+ if (cx.type == ACPI_STATE_C1) {
+ cx.valid = 1;
+ }
obj = &(element->package.elements[2]);
if (obj->type != ACPI_TYPE_INTEGER)
@@ -1282,6 +1286,7 @@
}
static const struct file_operations acpi_processor_power_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_power_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -1294,6 +1299,8 @@
{
int result = 0;
+ if (boot_option_idle_override)
+ return 0;
if (!pr)
return -EINVAL;
@@ -1733,6 +1740,9 @@
{
int ret;
+ if (boot_option_idle_override)
+ return 0;
+
if (!pr)
return -EINVAL;
@@ -1763,6 +1773,8 @@
struct proc_dir_entry *entry = NULL;
unsigned int i;
+ if (boot_option_idle_override)
+ return 0;
if (!first_run) {
dmi_check_system(processor_power_dmi_table);
@@ -1798,7 +1810,7 @@
* Note that we use previously set idle handler will be used on
* platforms that only support C1.
*/
- if ((pr->flags.power) && (!boot_option_idle_override)) {
+ if (pr->flags.power) {
#ifdef CONFIG_CPU_IDLE
acpi_processor_setup_cpuidle(pr);
pr->power.dev.cpu = pr->id;
@@ -1822,24 +1834,23 @@
}
/* 'power' [R] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_PROCESSOR_FILE_POWER,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_processor_power_fops,
+ acpi_driver_data(device));
if (!entry)
return -EIO;
- else {
- entry->proc_fops = &acpi_processor_power_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
int acpi_processor_power_exit(struct acpi_processor *pr,
struct acpi_device *device)
{
+ if (boot_option_idle_override)
+ return 0;
+
#ifdef CONFIG_CPU_IDLE
- if ((pr->flags.power) && (!boot_option_idle_override))
+ if (pr->flags.power)
cpuidle_unregister_device(&pr->power.dev);
#endif
pr->flags.power_setup_done = 0;
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index b477a4b..d80b2d1 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -411,6 +411,7 @@
static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_processor_perf_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_perf_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -456,7 +457,6 @@
static void acpi_cpufreq_add_file(struct acpi_processor *pr)
{
- struct proc_dir_entry *entry = NULL;
struct acpi_device *device = NULL;
@@ -464,14 +464,9 @@
return;
/* add file 'performance' [R/W] */
- entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
- S_IFREG | S_IRUGO,
- acpi_device_dir(device));
- if (entry){
- entry->proc_fops = &acpi_processor_perf_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ proc_create_data(ACPI_PROCESSOR_FILE_PERFORMANCE, S_IFREG | S_IRUGO,
+ acpi_device_dir(device),
+ &acpi_processor_perf_fops, acpi_driver_data(device));
return;
}
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
index 649ae99..ef34b18 100644
--- a/drivers/acpi/processor_thermal.c
+++ b/drivers/acpi/processor_thermal.c
@@ -509,6 +509,7 @@
}
struct file_operations acpi_processor_limit_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_limit_open_fs,
.read = seq_read,
.write = acpi_processor_write_limit,
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
index 0bba3a9..bb06738 100644
--- a/drivers/acpi/processor_throttling.c
+++ b/drivers/acpi/processor_throttling.c
@@ -1252,6 +1252,7 @@
}
struct file_operations acpi_processor_throttling_fops = {
+ .owner = THIS_MODULE,
.open = acpi_processor_throttling_open_fs,
.read = seq_read,
.write = acpi_processor_write_throttling,
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
index 271e615..7f96332 100644
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/resources/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index 0dd2ce8..8a112d1 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -73,7 +73,7 @@
static u8 acpi_rs_count_set_bits(u16 bit_field)
{
- u8 bits_set;
+ acpi_native_uint bits_set;
ACPI_FUNCTION_ENTRY();
@@ -81,10 +81,10 @@
/* Zero the least significant bit that is set */
- bit_field &= (bit_field - 1);
+ bit_field &= (u16) (bit_field - 1);
}
- return (bits_set);
+ return ((u8) bits_set);
}
/*******************************************************************************
@@ -211,6 +211,24 @@
* variable-length fields
*/
switch (resource->type) {
+ case ACPI_RESOURCE_TYPE_IRQ:
+
+ /* Length can be 3 or 2 */
+
+ if (resource->data.irq.descriptor_length == 2) {
+ total_size--;
+ }
+ break;
+
+ case ACPI_RESOURCE_TYPE_START_DEPENDENT:
+
+ /* Length can be 1 or 0 */
+
+ if (resource->data.irq.descriptor_length == 0) {
+ total_size--;
+ }
+ break;
+
case ACPI_RESOURCE_TYPE_VENDOR:
/*
* Vendor Defined Resource:
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index 50da494..faddaee 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
index 46da116..6bbbb7b 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -87,8 +87,10 @@
*
******************************************************************************/
-struct acpi_rsdump_info acpi_rs_dump_irq[6] = {
+struct acpi_rsdump_info acpi_rs_dump_irq[7] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_irq), "IRQ", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(irq.descriptor_length),
+ "Descriptor Length", NULL},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.triggering), "Triggering",
acpi_gbl_he_decode},
{ACPI_RSD_1BITFLAG, ACPI_RSD_OFFSET(irq.polarity), "Polarity",
@@ -115,9 +117,11 @@
NULL}
};
-struct acpi_rsdump_info acpi_rs_dump_start_dpf[3] = {
+struct acpi_rsdump_info acpi_rs_dump_start_dpf[4] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_start_dpf),
"Start-Dependent-Functions", NULL},
+ {ACPI_RSD_UINT8, ACPI_RSD_OFFSET(start_dpf.descriptor_length),
+ "Descriptor Length", NULL},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.compatibility_priority),
"Compatibility Priority", acpi_gbl_config_decode},
{ACPI_RSD_2BITFLAG, ACPI_RSD_OFFSET(start_dpf.performance_robustness),
diff --git a/drivers/acpi/resources/rsinfo.c b/drivers/acpi/resources/rsinfo.c
index 2c2adb6..3f0a1fe 100644
--- a/drivers/acpi/resources/rsinfo.c
+++ b/drivers/acpi/resources/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
index b297bc3..b66d42e 100644
--- a/drivers/acpi/resources/rsio.c
+++ b/drivers/acpi/resources/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -185,7 +185,7 @@
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_get_start_dpf[5] = {
+struct acpi_rsconvert_info acpi_rs_get_start_dpf[6] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_START_DEPENDENT,
ACPI_RS_SIZE(struct acpi_resource_start_dependent),
ACPI_RSC_TABLE_SIZE(acpi_rs_get_start_dpf)},
@@ -196,6 +196,12 @@
ACPI_ACCEPTABLE_CONFIGURATION,
2},
+ /* Get the descriptor length (0 or 1 for Start Dpf descriptor) */
+
+ {ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.start_dpf.descriptor_length),
+ AML_OFFSET(start_dpf.descriptor_type),
+ 0},
+
/* All done if there is no flag byte present in the descriptor */
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 1},
@@ -219,7 +225,9 @@
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_set_start_dpf[6] = {
+struct acpi_rsconvert_info acpi_rs_set_start_dpf[10] = {
+ /* Start with a default descriptor of length 1 */
+
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_START_DEPENDENT,
sizeof(struct aml_resource_start_dependent),
ACPI_RSC_TABLE_SIZE(acpi_rs_set_start_dpf)},
@@ -236,6 +244,33 @@
AML_OFFSET(start_dpf.flags),
2},
/*
+ * All done if the output descriptor length is required to be 1
+ * (i.e., optimization to 0 bytes cannot be attempted)
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.start_dpf.descriptor_length),
+ 1},
+
+ /* Set length to 0 bytes (no flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0,
+ sizeof(struct aml_resource_start_dependent_noprio)},
+
+ /*
+ * All done if the output descriptor length is required to be 0.
+ *
+ * TBD: Perhaps we should check for error if input flags are not
+ * compatible with a 0-byte descriptor.
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.start_dpf.descriptor_length),
+ 0},
+
+ /* Reset length to 1 byte (descriptor with flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_start_dependent)},
+
+ /*
* All done if flags byte is necessary -- if either priority value
* is not ACPI_ACCEPTABLE_CONFIGURATION
*/
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
index 5657f7b..a8805ef 100644
--- a/drivers/acpi/resources/rsirq.c
+++ b/drivers/acpi/resources/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -52,7 +52,7 @@
* acpi_rs_get_irq
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_get_irq[7] = {
+struct acpi_rsconvert_info acpi_rs_get_irq[8] = {
{ACPI_RSC_INITGET, ACPI_RESOURCE_TYPE_IRQ,
ACPI_RS_SIZE(struct acpi_resource_irq),
ACPI_RSC_TABLE_SIZE(acpi_rs_get_irq)},
@@ -69,6 +69,12 @@
ACPI_EDGE_SENSITIVE,
1},
+ /* Get the descriptor length (2 or 3 for IRQ descriptor) */
+
+ {ACPI_RSC_2BITFLAG, ACPI_RS_OFFSET(data.irq.descriptor_length),
+ AML_OFFSET(irq.descriptor_type),
+ 0},
+
/* All done if no flag byte present in descriptor */
{ACPI_RSC_EXIT_NE, ACPI_RSC_COMPARE_AML_LENGTH, 0, 3},
@@ -94,7 +100,9 @@
*
******************************************************************************/
-struct acpi_rsconvert_info acpi_rs_set_irq[9] = {
+struct acpi_rsconvert_info acpi_rs_set_irq[13] = {
+ /* Start with a default descriptor of length 3 */
+
{ACPI_RSC_INITSET, ACPI_RESOURCE_NAME_IRQ,
sizeof(struct aml_resource_irq),
ACPI_RSC_TABLE_SIZE(acpi_rs_set_irq)},
@@ -105,7 +113,7 @@
AML_OFFSET(irq.irq_mask),
ACPI_RS_OFFSET(data.irq.interrupt_count)},
- /* Set the flags byte by default */
+ /* Set the flags byte */
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.triggering),
AML_OFFSET(irq.flags),
@@ -118,6 +126,33 @@
{ACPI_RSC_1BITFLAG, ACPI_RS_OFFSET(data.irq.sharable),
AML_OFFSET(irq.flags),
4},
+
+ /*
+ * All done if the output descriptor length is required to be 3
+ * (i.e., optimization to 2 bytes cannot be attempted)
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.irq.descriptor_length),
+ 3},
+
+ /* Set length to 2 bytes (no flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)},
+
+ /*
+ * All done if the output descriptor length is required to be 2.
+ *
+ * TBD: Perhaps we should check for error if input flags are not
+ * compatible with a 2-byte descriptor.
+ */
+ {ACPI_RSC_EXIT_EQ, ACPI_RSC_COMPARE_VALUE,
+ ACPI_RS_OFFSET(data.irq.descriptor_length),
+ 2},
+
+ /* Reset length to 3 bytes (descriptor with flags byte) */
+
+ {ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq)},
+
/*
* Check if the flags byte is necessary. Not needed if the flags are:
* ACPI_EDGE_SENSITIVE, ACPI_ACTIVE_HIGH, ACPI_EXCLUSIVE
@@ -134,7 +169,7 @@
ACPI_RS_OFFSET(data.irq.sharable),
ACPI_EXCLUSIVE},
- /* irq_no_flags() descriptor can be used */
+ /* We can optimize to a 2-byte irq_no_flags() descriptor */
{ACPI_RSC_LENGTH, 0, 0, sizeof(struct aml_resource_irq_noflags)}
};
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index ca21e46..b78c7e7 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c
index 521eab7..63b21ab 100644
--- a/drivers/acpi/resources/rsmemory.c
+++ b/drivers/acpi/resources/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index c7081af..de1ac38 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -497,6 +497,17 @@
}
break;
+ case ACPI_RSC_EXIT_EQ:
+ /*
+ * Control - Exit conversion if equal
+ */
+ if (*ACPI_ADD_PTR(u8, resource,
+ COMPARE_TARGET(info)) ==
+ COMPARE_VALUE(info)) {
+ goto exit;
+ }
+ break;
+
default:
ACPI_ERROR((AE_INFO, "Invalid conversion opcode"));
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index 11c0bd7..befe230 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,17 +97,17 @@
u16 acpi_rs_encode_bitmask(u8 * list, u8 count)
{
acpi_native_uint i;
- u16 mask;
+ acpi_native_uint mask;
ACPI_FUNCTION_ENTRY();
/* Encode the list into a single bitmask */
for (i = 0, mask = 0; i < count; i++) {
- mask |= (0x0001 << list[i]);
+ mask |= (0x1 << list[i]);
}
- return (mask);
+ return ((u16) mask);
}
/*******************************************************************************
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index 4c3fd4c..f59f4c4 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 585ae3c..10a3651 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -483,8 +483,6 @@
struct file_operations *state_fops,
struct file_operations *alarm_fops, void *data)
{
- struct proc_dir_entry *entry = NULL;
-
if (!*dir) {
*dir = proc_mkdir(dir_name, parent_dir);
if (!*dir) {
@@ -494,34 +492,19 @@
}
/* 'info' [R] */
- if (info_fops) {
- entry = create_proc_entry(ACPI_SBS_FILE_INFO, S_IRUGO, *dir);
- if (entry) {
- entry->proc_fops = info_fops;
- entry->data = data;
- entry->owner = THIS_MODULE;
- }
- }
+ if (info_fops)
+ proc_create_data(ACPI_SBS_FILE_INFO, S_IRUGO, *dir,
+ info_fops, data);
/* 'state' [R] */
- if (state_fops) {
- entry = create_proc_entry(ACPI_SBS_FILE_STATE, S_IRUGO, *dir);
- if (entry) {
- entry->proc_fops = state_fops;
- entry->data = data;
- entry->owner = THIS_MODULE;
- }
- }
+ if (state_fops)
+ proc_create_data(ACPI_SBS_FILE_STATE, S_IRUGO, *dir,
+ state_fops, data);
/* 'alarm' [R/W] */
- if (alarm_fops) {
- entry = create_proc_entry(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir);
- if (entry) {
- entry->proc_fops = alarm_fops;
- entry->data = data;
- entry->owner = THIS_MODULE;
- }
- }
+ if (alarm_fops)
+ proc_create_data(ACPI_SBS_FILE_ALARM, S_IRUGO, *dir,
+ alarm_fops, data);
return 0;
}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e6ce262..6d85289 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -677,9 +677,8 @@
device->wakeup.resources.count = package->package.count - 2;
for (i = 0; i < device->wakeup.resources.count; i++) {
element = &(package->package.elements[i + 2]);
- if (element->type != ACPI_TYPE_ANY) {
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
return AE_BAD_DATA;
- }
device->wakeup.resources.handles[i] = element->reference.handle;
}
@@ -692,6 +691,9 @@
acpi_status status = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package = NULL;
+ union acpi_object in_arg[3];
+ struct acpi_object_list arg_list = { 3, in_arg };
+ acpi_status psw_status = AE_OK;
struct acpi_device_id button_device_ids[] = {
{"PNP0C0D", 0},
@@ -700,7 +702,6 @@
{"", 0},
};
-
/* _PRW */
status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
if (ACPI_FAILURE(status)) {
@@ -718,6 +719,45 @@
kfree(buffer.pointer);
device->wakeup.flags.valid = 1;
+ /* Call _PSW/_DSW object to disable its ability to wake the sleeping
+ * system for the ACPI device with the _PRW object.
+ * The _PSW object is depreciated in ACPI 3.0 and is replaced by _DSW.
+ * So it is necessary to call _DSW object first. Only when it is not
+ * present will the _PSW object used.
+ */
+ /*
+ * Three agruments are needed for the _DSW object.
+ * Argument 0: enable/disable the wake capabilities
+ * When _DSW object is called to disable the wake capabilities, maybe
+ * the first argument is filled. The value of the other two agruments
+ * is meaningless.
+ */
+ in_arg[0].type = ACPI_TYPE_INTEGER;
+ in_arg[0].integer.value = 0;
+ in_arg[1].type = ACPI_TYPE_INTEGER;
+ in_arg[1].integer.value = 0;
+ in_arg[2].type = ACPI_TYPE_INTEGER;
+ in_arg[2].integer.value = 0;
+ psw_status = acpi_evaluate_object(device->handle, "_DSW",
+ &arg_list, NULL);
+ if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in evaluate _DSW\n"));
+ /*
+ * When the _DSW object is not present, OSPM will call _PSW object.
+ */
+ if (psw_status == AE_NOT_FOUND) {
+ /*
+ * Only one agruments is required for the _PSW object.
+ * agrument 0: enable/disable the wake capabilities
+ */
+ arg_list.count = 1;
+ in_arg[0].integer.value = 0;
+ psw_status = acpi_evaluate_object(device->handle, "_PSW",
+ &arg_list, NULL);
+ if (ACPI_FAILURE(psw_status) && (psw_status != AE_NOT_FOUND))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "error in "
+ "evaluate _PSW\n"));
+ }
/* Power button, Lid switch always enable wakeup */
if (!acpi_match_device_ids(device, button_device_ids))
device->wakeup.flags.run_wake = 1;
@@ -882,10 +922,7 @@
static int
acpi_video_bus_match(struct acpi_device *device)
{
- acpi_handle h_dummy1;
- acpi_handle h_dummy2;
- acpi_handle h_dummy3;
-
+ acpi_handle h_dummy;
if (!device)
return -EINVAL;
@@ -895,18 +932,18 @@
*/
/* Does this device able to support video switching ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy)))
return 0;
/* Does this device able to retrieve a video ROM ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy)))
return 0;
/* Does this device able to configure which video head to be POSTed ? */
- if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
- ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy)))
return 0;
return -ENODEV;
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 71183ee..c3b0cd8 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -51,7 +51,7 @@
}
#ifdef CONFIG_SUSPEND
-static struct platform_suspend_ops acpi_pm_ops;
+static struct platform_suspend_ops acpi_suspend_ops;
extern void do_suspend_lowlevel(void);
@@ -65,11 +65,11 @@
static int init_8259A_after_S1;
/**
- * acpi_pm_begin - Set the target system sleep state to the state
+ * acpi_suspend_begin - Set the target system sleep state to the state
* associated with given @pm_state, if supported.
*/
-static int acpi_pm_begin(suspend_state_t pm_state)
+static int acpi_suspend_begin(suspend_state_t pm_state)
{
u32 acpi_state = acpi_suspend_states[pm_state];
int error = 0;
@@ -85,13 +85,13 @@
}
/**
- * acpi_pm_prepare - Do preliminary suspend work.
+ * acpi_suspend_prepare - Do preliminary suspend work.
*
* If necessary, set the firmware waking vector and do arch-specific
* nastiness to get the wakeup code to the waking vector.
*/
-static int acpi_pm_prepare(void)
+static int acpi_suspend_prepare(void)
{
int error = acpi_sleep_prepare(acpi_target_sleep_state);
@@ -104,7 +104,7 @@
}
/**
- * acpi_pm_enter - Actually enter a sleep state.
+ * acpi_suspend_enter - Actually enter a sleep state.
* @pm_state: ignored
*
* Flush caches and go to sleep. For STR we have to call arch-specific
@@ -112,7 +112,7 @@
* It's unfortunate, but it works. Please fix if you're feeling frisky.
*/
-static int acpi_pm_enter(suspend_state_t pm_state)
+static int acpi_suspend_enter(suspend_state_t pm_state)
{
acpi_status status = AE_OK;
unsigned long flags = 0;
@@ -169,13 +169,13 @@
}
/**
- * acpi_pm_finish - Instruct the platform to leave a sleep state.
+ * acpi_suspend_finish - Instruct the platform to leave a sleep state.
*
* This is called after we wake back up (or if entering the sleep state
* failed).
*/
-static void acpi_pm_finish(void)
+static void acpi_suspend_finish(void)
{
u32 acpi_state = acpi_target_sleep_state;
@@ -196,19 +196,19 @@
}
/**
- * acpi_pm_end - Finish up suspend sequence.
+ * acpi_suspend_end - Finish up suspend sequence.
*/
-static void acpi_pm_end(void)
+static void acpi_suspend_end(void)
{
/*
- * This is necessary in case acpi_pm_finish() is not called during a
+ * This is necessary in case acpi_suspend_finish() is not called during a
* failing transition to a sleep state.
*/
acpi_target_sleep_state = ACPI_STATE_S0;
}
-static int acpi_pm_state_valid(suspend_state_t pm_state)
+static int acpi_suspend_state_valid(suspend_state_t pm_state)
{
u32 acpi_state;
@@ -224,13 +224,13 @@
}
}
-static struct platform_suspend_ops acpi_pm_ops = {
- .valid = acpi_pm_state_valid,
- .begin = acpi_pm_begin,
- .prepare = acpi_pm_prepare,
- .enter = acpi_pm_enter,
- .finish = acpi_pm_finish,
- .end = acpi_pm_end,
+static struct platform_suspend_ops acpi_suspend_ops = {
+ .valid = acpi_suspend_state_valid,
+ .begin = acpi_suspend_begin,
+ .prepare = acpi_suspend_prepare,
+ .enter = acpi_suspend_enter,
+ .finish = acpi_suspend_finish,
+ .end = acpi_suspend_end,
};
/*
@@ -492,7 +492,7 @@
}
}
- suspend_set_ops(&acpi_pm_ops);
+ suspend_set_ops(&acpi_suspend_ops);
#endif
#ifdef CONFIG_HIBERNATION
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index f8df521..8a5fe87 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -440,6 +440,7 @@
}
static const struct file_operations acpi_system_wakeup_device_fops = {
+ .owner = THIS_MODULE,
.open = acpi_system_wakeup_device_open_fs,
.read = seq_read,
.write = acpi_system_write_wakeup_device,
@@ -449,6 +450,7 @@
#ifdef CONFIG_ACPI_PROCFS
static const struct file_operations acpi_system_sleep_fops = {
+ .owner = THIS_MODULE,
.open = acpi_system_sleep_open_fs,
.read = seq_read,
.write = acpi_system_write_sleep,
@@ -459,6 +461,7 @@
#ifdef HAVE_ACPI_LEGACY_ALARM
static const struct file_operations acpi_system_alarm_fops = {
+ .owner = THIS_MODULE,
.open = acpi_system_alarm_open_fs,
.read = seq_read,
.write = acpi_system_write_alarm,
@@ -477,37 +480,26 @@
static int __init acpi_sleep_proc_init(void)
{
- struct proc_dir_entry *entry = NULL;
-
if (acpi_disabled)
return 0;
#ifdef CONFIG_ACPI_PROCFS
/* 'sleep' [R/W] */
- entry =
- create_proc_entry("sleep", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_sleep_fops;
+ proc_create("sleep", S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_root_dir, &acpi_system_sleep_fops);
#endif /* CONFIG_ACPI_PROCFS */
#ifdef HAVE_ACPI_LEGACY_ALARM
/* 'alarm' [R/W] */
- entry =
- create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_alarm_fops;
+ proc_create("alarm", S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_root_dir, &acpi_system_alarm_fops);
acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
#endif /* HAVE_ACPI_LEGACY_ALARM */
/* 'wakeup device' [R/W] */
- entry =
- create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_wakeup_device_fops;
+ proc_create("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_root_dir, &acpi_system_wakeup_device_fops);
return 0;
}
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
index 4749f37..769f248 100644
--- a/drivers/acpi/system.c
+++ b/drivers/acpi/system.c
@@ -396,6 +396,7 @@
}
static const struct file_operations acpi_system_info_ops = {
+ .owner = THIS_MODULE,
.open = acpi_system_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -406,6 +407,7 @@
loff_t *);
static const struct file_operations acpi_system_dsdt_ops = {
+ .owner = THIS_MODULE,
.read = acpi_system_read_dsdt,
};
@@ -430,6 +432,7 @@
loff_t *);
static const struct file_operations acpi_system_fadt_ops = {
+ .owner = THIS_MODULE,
.read = acpi_system_read_fadt,
};
@@ -454,31 +457,23 @@
{
struct proc_dir_entry *entry;
int error = 0;
- char *name;
/* 'info' [R] */
- name = ACPI_SYSTEM_FILE_INFO;
- entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
+ entry = proc_create(ACPI_SYSTEM_FILE_INFO, S_IRUGO, acpi_root_dir,
+ &acpi_system_info_ops);
if (!entry)
goto Error;
- else {
- entry->proc_fops = &acpi_system_info_ops;
- }
/* 'dsdt' [R] */
- name = ACPI_SYSTEM_FILE_DSDT;
- entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_dsdt_ops;
- else
+ entry = proc_create(ACPI_SYSTEM_FILE_DSDT, S_IRUSR, acpi_root_dir,
+ &acpi_system_dsdt_ops);
+ if (!entry)
goto Error;
/* 'fadt' [R] */
- name = ACPI_SYSTEM_FILE_FADT;
- entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
- if (entry)
- entry->proc_fops = &acpi_system_fadt_ops;
- else
+ entry = proc_create(ACPI_SYSTEM_FILE_FADT, S_IRUSR, acpi_root_dir,
+ &acpi_system_fadt_ops);
+ if (!entry)
goto Error;
Done:
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
index 002bb33..949d411 100644
--- a/drivers/acpi/tables/tbfadt.c
+++ b/drivers/acpi/tables/tbfadt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c
index 058c064..9ca3afc 100644
--- a/drivers/acpi/tables/tbfind.c
+++ b/drivers/acpi/tables/tbfind.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,12 +70,22 @@
{
acpi_native_uint i;
acpi_status status;
+ struct acpi_table_header header;
ACPI_FUNCTION_TRACE(tb_find_table);
+ /* Normalize the input strings */
+
+ ACPI_MEMSET(&header, 0, sizeof(struct acpi_table_header));
+ ACPI_STRNCPY(header.signature, signature, ACPI_NAME_SIZE);
+ ACPI_STRNCPY(header.oem_id, oem_id, ACPI_OEM_ID_SIZE);
+ ACPI_STRNCPY(header.oem_table_id, oem_table_id, ACPI_OEM_TABLE_ID_SIZE);
+
+ /* Search for the table */
+
for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature),
- signature, ACPI_NAME_SIZE)) {
+ header.signature, ACPI_NAME_SIZE)) {
/* Not the requested table */
@@ -104,20 +114,24 @@
if (!ACPI_MEMCMP
(acpi_gbl_root_table_list.tables[i].pointer->signature,
- signature, ACPI_NAME_SIZE) && (!oem_id[0]
- ||
- !ACPI_MEMCMP
- (acpi_gbl_root_table_list.
- tables[i].pointer->oem_id,
- oem_id, ACPI_OEM_ID_SIZE))
+ header.signature, ACPI_NAME_SIZE) && (!oem_id[0]
+ ||
+ !ACPI_MEMCMP
+ (acpi_gbl_root_table_list.
+ tables[i].pointer->
+ oem_id,
+ header.oem_id,
+ ACPI_OEM_ID_SIZE))
&& (!oem_table_id[0]
|| !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i].
- pointer->oem_table_id, oem_table_id,
+ pointer->oem_table_id,
+ header.oem_table_id,
ACPI_OEM_TABLE_ID_SIZE))) {
*table_index = i;
ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
- "Found table [%4.4s]\n", signature));
+ "Found table [%4.4s]\n",
+ header.signature));
return_ACPI_STATUS(AE_OK);
}
}
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 3bc0c67..402f93e 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -125,13 +125,20 @@
/* The table must be either an SSDT or a PSDT or an OEMx */
- if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT))
- &&
- (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT))
- && (strncmp(table_desc->pointer->signature, "OEM", 3))) {
- ACPI_ERROR((AE_INFO,
- "Table has invalid signature [%4.4s], must be SSDT, PSDT or OEMx",
- table_desc->pointer->signature));
+ if (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT)&&
+ !ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)&&
+ strncmp(table_desc->pointer->signature, "OEM", 3)) {
+ /* Check for a printable name */
+ if (acpi_ut_valid_acpi_name(
+ *(u32 *) table_desc->pointer->signature)) {
+ ACPI_ERROR((AE_INFO, "Table has invalid signature "
+ "[%4.4s], must be SSDT or PSDT",
+ table_desc->pointer->signature));
+ } else {
+ ACPI_ERROR((AE_INFO, "Table has invalid signature "
+ "(0x%8.8X), must be SSDT or PSDT",
+ *(u32 *) table_desc->pointer->signature));
+ }
return_ACPI_STATUS(AE_BAD_SIGNATURE);
}
@@ -162,6 +169,7 @@
acpi_tb_delete_table(table_desc);
*table_index = i;
+ status = AE_ALREADY_EXISTS;
goto release;
}
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index 010f196..bc019b9 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -212,7 +212,7 @@
if (checksum) {
ACPI_WARNING((AE_INFO,
- "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
+ "Incorrect checksum in table [%4.4s] - %2.2X, should be %2.2X",
table->signature, table->checksum,
(u8) (table->checksum - checksum)));
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index a9e3331..fb57b93 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -635,6 +635,95 @@
ACPI_EXPORT_SYMBOL(acpi_load_tables)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_table_handler
+ *
+ * PARAMETERS: Handler - Table event handler
+ * Context - Value passed to the handler on each event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install table event handler
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_table_handler(acpi_tbl_handler handler, void *context)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_install_table_handler);
+
+ if (!handler) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Don't allow more than one handler */
+
+ if (acpi_gbl_table_handler) {
+ status = AE_ALREADY_EXISTS;
+ goto cleanup;
+ }
+
+ /* Install the handler */
+
+ acpi_gbl_table_handler = handler;
+ acpi_gbl_table_handler_context = context;
+
+ cleanup:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_table_handler)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_table_handler
+ *
+ * PARAMETERS: Handler - Table event handler that was installed
+ * previously.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove table event handler
+ *
+ ******************************************************************************/
+acpi_status acpi_remove_table_handler(acpi_tbl_handler handler)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_remove_table_handler);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Make sure that the installed handler is the same */
+
+ if (!handler || handler != acpi_gbl_table_handler) {
+ status = AE_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ /* Remove the handler */
+
+ acpi_gbl_table_handler = NULL;
+
+ cleanup:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_remove_table_handler)
+
+
static int __init acpi_no_auto_ssdt_setup(char *s) {
printk(KERN_NOTICE "ACPI: SSDT auto-load disabled\n");
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index 9ecb4b6..b8c0dfa 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 766bd25..504385b 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -198,6 +198,7 @@
};
static const struct file_operations acpi_thermal_state_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -205,6 +206,7 @@
};
static const struct file_operations acpi_thermal_temp_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_temp_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -212,6 +214,7 @@
};
static const struct file_operations acpi_thermal_trip_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_trip_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -219,6 +222,7 @@
};
static const struct file_operations acpi_thermal_cooling_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_cooling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_cooling_mode,
@@ -227,6 +231,7 @@
};
static const struct file_operations acpi_thermal_polling_fops = {
+ .owner = THIS_MODULE,
.open = acpi_thermal_polling_open_fs,
.read = seq_read,
.write = acpi_thermal_write_polling,
@@ -884,10 +889,15 @@
static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
+ int result;
if (!tz)
return -EINVAL;
+ result = acpi_thermal_get_temperature(tz);
+ if (result)
+ return result;
+
return sprintf(buf, "%ld\n", KELVIN_TO_MILLICELSIUS(tz->temperature));
}
@@ -1012,6 +1022,18 @@
return -EINVAL;
}
+static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
+ unsigned long *temperature) {
+ struct acpi_thermal *tz = thermal->devdata;
+
+ if (tz->trips.critical.flags.valid) {
+ *temperature = KELVIN_TO_MILLICELSIUS(
+ tz->trips.critical.temperature);
+ return 0;
+ } else
+ return -EINVAL;
+}
+
typedef int (*cb)(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
@@ -1103,6 +1125,7 @@
.set_mode = thermal_set_mode,
.get_trip_type = thermal_get_trip_type,
.get_trip_temp = thermal_get_trip_temp,
+ .get_crit_temp = thermal_get_crit_temp,
};
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
@@ -1123,7 +1146,7 @@
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++, trips++);
- tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
+ tz->thermal_zone = thermal_zone_device_register("acpitz",
trips, tz, &acpi_thermal_zone_ops);
if (IS_ERR(tz->thermal_zone))
return -ENODEV;
@@ -1419,63 +1442,47 @@
}
/* 'state' [R] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_STATE,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_thermal_state_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_state_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'temperature' [R] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
- S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE,
+ S_IRUGO, acpi_device_dir(device),
+ &acpi_thermal_temp_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_temp_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'trip_points' [R] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
- S_IRUGO,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS,
+ S_IRUGO,
+ acpi_device_dir(device),
+ &acpi_thermal_trip_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_trip_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'cooling_mode' [R/W] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_thermal_cooling_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_cooling_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
/* 'polling_frequency' [R/W] */
- entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
- S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ entry = proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ acpi_device_dir(device),
+ &acpi_thermal_polling_fops,
+ acpi_driver_data(device));
if (!entry)
return -ENODEV;
- else {
- entry->proc_fops = &acpi_thermal_polling_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
return 0;
}
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index 6e56d5f..ede0848 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -147,7 +147,7 @@
if (acpi_gbl_display_final_mem_stats) {
ACPI_STRCPY(buffer, "MEMORY");
- acpi_db_display_statistics(buffer);
+ (void)acpi_db_display_statistics(buffer);
}
#endif
diff --git a/drivers/acpi/utilities/utcache.c b/drivers/acpi/utilities/utcache.c
index 285a0f5..245fa80 100644
--- a/drivers/acpi/utilities/utcache.c
+++ b/drivers/acpi/utilities/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 879eaa1..655c290 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,8 @@
#include <acpi/acpi.h>
#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utcopy")
@@ -172,22 +174,21 @@
case ACPI_TYPE_LOCAL_REFERENCE:
- /*
- * This is an object reference. Attempt to dereference it.
- */
+ /* This is an object reference. */
+
switch (internal_object->reference.opcode) {
case AML_INT_NAMEPATH_OP:
/* For namepath, return the object handle ("reference") */
default:
- /*
- * Use the object type of "Any" to indicate a reference
- * to object containing a handle to an ACPI named object.
- */
- external_object->type = ACPI_TYPE_ANY;
+
+ /* We are referring to the namespace node */
+
external_object->reference.handle =
internal_object->reference.node;
+ external_object->reference.actual_type =
+ acpi_ns_get_type(internal_object->reference.node);
break;
}
break;
@@ -215,6 +216,11 @@
/*
* There is no corresponding external object type
*/
+ ACPI_ERROR((AE_INFO,
+ "Unsupported object type, cannot convert to external object: %s",
+ acpi_ut_get_type_name(ACPI_GET_OBJECT_TYPE
+ (internal_object))));
+
return_ACPI_STATUS(AE_SUPPORT);
}
@@ -455,6 +461,7 @@
case ACPI_TYPE_STRING:
case ACPI_TYPE_BUFFER:
case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_LOCAL_REFERENCE:
internal_object = acpi_ut_create_internal_object((u8)
external_object->
@@ -464,9 +471,18 @@
}
break;
+ case ACPI_TYPE_ANY: /* This is the case for a NULL object */
+
+ *ret_internal_object = NULL;
+ return_ACPI_STATUS(AE_OK);
+
default:
/* All other types are not supported */
+ ACPI_ERROR((AE_INFO,
+ "Unsupported object type, cannot convert to internal object: %s",
+ acpi_ut_get_type_name(external_object->type)));
+
return_ACPI_STATUS(AE_SUPPORT);
}
@@ -502,6 +518,10 @@
external_object->buffer.length);
internal_object->buffer.length = external_object->buffer.length;
+
+ /* Mark buffer data valid */
+
+ internal_object->buffer.flags |= AOPOBJ_DATA_VALID;
break;
case ACPI_TYPE_INTEGER:
@@ -509,6 +529,15 @@
internal_object->integer.value = external_object->integer.value;
break;
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ /* TBD: should validate incoming handle */
+
+ internal_object->reference.opcode = AML_INT_NAMEPATH_OP;
+ internal_object->reference.node =
+ external_object->reference.handle;
+ break;
+
default:
/* Other types can't get here */
break;
@@ -570,13 +599,17 @@
/* Truncate package and delete it */
- package_object->package.count = i;
+ package_object->package.count = (u32) i;
package_elements[i] = NULL;
acpi_ut_remove_reference(package_object);
return_ACPI_STATUS(status);
}
}
+ /* Mark package data valid */
+
+ package_object->package.flags |= AOPOBJ_DATA_VALID;
+
*internal_object = package_object;
return_ACPI_STATUS(status);
}
@@ -709,7 +742,15 @@
/*
* We copied the reference object, so we now must add a reference
* to the object pointed to by the reference
+ *
+ * DDBHandle reference (from Load/load_table is a special reference,
+ * it's Reference.Object is the table index, so does not need to
+ * increase the reference count
*/
+ if (source_desc->reference.opcode == AML_LOAD_OP) {
+ break;
+ }
+
acpi_ut_add_reference(source_desc->reference.object);
break;
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 7361204..f938f46 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -68,9 +68,9 @@
void acpi_ut_init_stack_ptr_trace(void)
{
- u32 current_sp;
+ acpi_size current_sp;
- acpi_gbl_entry_stack_pointer = ACPI_PTR_DIFF(¤t_sp, NULL);
+ acpi_gbl_entry_stack_pointer = ¤t_sp;
}
/*******************************************************************************
@@ -89,10 +89,8 @@
{
acpi_size current_sp;
- current_sp = ACPI_PTR_DIFF(¤t_sp, NULL);
-
- if (current_sp < acpi_gbl_lowest_stack_pointer) {
- acpi_gbl_lowest_stack_pointer = current_sp;
+ if (¤t_sp < acpi_gbl_lowest_stack_pointer) {
+ acpi_gbl_lowest_stack_pointer = ¤t_sp;
}
if (acpi_gbl_nesting_level > acpi_gbl_deepest_nesting) {
@@ -203,6 +201,7 @@
va_start(args, format);
acpi_os_vprintf(format, args);
+ va_end(args);
}
ACPI_EXPORT_SYMBOL(acpi_ut_debug_print)
@@ -240,6 +239,7 @@
va_start(args, format);
acpi_os_vprintf(format, args);
+ va_end(args);
}
ACPI_EXPORT_SYMBOL(acpi_ut_debug_print_raw)
@@ -524,6 +524,11 @@
u32 temp32;
u8 buf_char;
+ if (!buffer) {
+ acpi_os_printf("Null Buffer Pointer in DumpBuffer!\n");
+ return;
+ }
+
if ((count < 4) || (count & 0x01)) {
display = DB_BYTE_DISPLAY;
}
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index f777ceb..1fbc351 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -158,7 +158,7 @@
"***** Mutex %p, OS Mutex %p\n",
object, object->mutex.os_mutex));
- if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+ if (object == acpi_gbl_global_lock_mutex) {
/* Global Lock has extra semaphore */
@@ -252,6 +252,17 @@
}
break;
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ ACPI_DEBUG_PRINT((ACPI_DB_ALLOCATIONS,
+ "***** Bank Field %p\n", object));
+
+ second_desc = acpi_ns_get_secondary_object(object);
+ if (second_desc) {
+ acpi_ut_delete_object_desc(second_desc);
+ }
+ break;
+
default:
break;
}
@@ -524,10 +535,12 @@
case ACPI_TYPE_LOCAL_REFERENCE:
/*
- * The target of an Index (a package, string, or buffer) must track
- * changes to the ref count of the index.
+ * The target of an Index (a package, string, or buffer) or a named
+ * reference must track changes to the ref count of the index or
+ * target object.
*/
- if (object->reference.opcode == AML_INDEX_OP) {
+ if ((object->reference.opcode == AML_INDEX_OP) ||
+ (object->reference.opcode == AML_INT_NAMEPATH_OP)) {
next_object = object->reference.object;
}
break;
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index 0042b7e..05e61be 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 630c9a2..a6e71b8 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -602,6 +602,48 @@
return (acpi_gbl_mutex_names[mutex_id]);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_notify_name
+ *
+ * PARAMETERS: notify_value - Value from the Notify() request
+ *
+ * RETURN: String corresponding to the Notify Value.
+ *
+ * DESCRIPTION: Translate a Notify Value to a notify namestring.
+ *
+ ******************************************************************************/
+
+/* Names for Notify() values, used for debug output */
+
+static const char *acpi_gbl_notify_value_names[] = {
+ "Bus Check",
+ "Device Check",
+ "Device Wake",
+ "Eject Request",
+ "Device Check Light",
+ "Frequency Mismatch",
+ "Bus Mode Mismatch",
+ "Power Fault",
+ "Capabilities Check",
+ "Device PLD Check",
+ "Reserved",
+ "System Locality Update"
+};
+
+const char *acpi_ut_get_notify_name(u32 notify_value)
+{
+
+ if (notify_value <= ACPI_NOTIFY_MAX) {
+ return (acpi_gbl_notify_value_names[notify_value]);
+ } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
+ return ("Reserved");
+ } else { /* Greater or equal to 0x80 */
+
+ return ("**Device Specific**");
+ }
+}
#endif
/*******************************************************************************
@@ -675,12 +717,13 @@
acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL;
- /* Global notify handlers */
+ /* Global handlers */
acpi_gbl_system_notify.handler = NULL;
acpi_gbl_device_notify.handler = NULL;
acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL;
+ acpi_gbl_table_handler = NULL;
/* Global Lock support */
@@ -722,7 +765,7 @@
acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST;
#ifdef ACPI_DEBUG_OUTPUT
- acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX;
+ acpi_gbl_lowest_stack_pointer = ACPI_CAST_PTR(acpi_size, ACPI_SIZE_MAX);
#endif
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
index ad3c0d0..cae515f 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/utilities/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -125,9 +125,12 @@
acpi_gbl_startup_flags = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Shutting down ACPI Subsystem\n"));
+#ifndef ACPI_ASL_COMPILER
+
/* Close the acpi_event Handling */
acpi_ev_terminate();
+#endif
/* Close the Namespace */
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
index 0c56a0d..c927324 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/utilities/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -276,7 +276,7 @@
*out_quotient = in_dividend / divisor;
}
if (out_remainder) {
- *out_remainder = (u32) in_dividend % divisor;
+ *out_remainder = (u32) (in_dividend % divisor);
}
return_ACPI_STATUS(AE_OK);
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index 2d19f71..e4ba719 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1033,6 +1033,7 @@
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ va_end(args);
}
void ACPI_INTERNAL_VAR_XFACE
@@ -1061,6 +1062,8 @@
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+ va_end(args);
+ va_end(args);
}
void ACPI_INTERNAL_VAR_XFACE
@@ -1077,4 +1080,5 @@
va_start(args, format);
acpi_os_vprintf(format, args);
acpi_os_printf("\n");
+ va_end(args);
}
diff --git a/drivers/acpi/utilities/utmutex.c b/drivers/acpi/utilities/utmutex.c
index 4820bc8..f7d602b 100644
--- a/drivers/acpi/utilities/utmutex.c
+++ b/drivers/acpi/utilities/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index e08b3fa..e68466d 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -107,6 +107,7 @@
switch (type) {
case ACPI_TYPE_REGION:
case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
/* These types require a secondary object */
@@ -469,9 +470,8 @@
case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_POWER:
- /*
- * No extra data for these types
- */
+ /* No extra data for these types */
+
break;
case ACPI_TYPE_LOCAL_REFERENCE:
diff --git a/drivers/acpi/utilities/utresrc.c b/drivers/acpi/utilities/utresrc.c
index b630ee1..c3e3e13 100644
--- a/drivers/acpi/utilities/utresrc.c
+++ b/drivers/acpi/utilities/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utstate.c b/drivers/acpi/utilities/utstate.c
index edcaafa..63a6d3d 100644
--- a/drivers/acpi/utilities/utstate.c
+++ b/drivers/acpi/utilities/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index 2d49691..f8bdadf 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -49,6 +49,7 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utxface")
+#ifndef ACPI_ASL_COMPILER
/*******************************************************************************
*
* FUNCTION: acpi_initialize_subsystem
@@ -192,24 +193,6 @@
}
}
- /*
- * Complete the GPE initialization for the GPE blocks defined in the FADT
- * (GPE block 0 and 1).
- *
- * Note1: This is where the _PRW methods are executed for the GPEs. These
- * methods can only be executed after the SCI and Global Lock handlers are
- * installed and initialized.
- *
- * Note2: Currently, there seems to be no need to run the _REG methods
- * before execution of the _PRW methods and enabling of the GPEs.
- */
- if (!(flags & ACPI_NO_EVENT_INIT)) {
- status = acpi_ev_install_fadt_gpes();
- if (ACPI_FAILURE(status)) {
- return (status);
- }
- }
-
return_ACPI_STATUS(status);
}
@@ -280,6 +263,23 @@
}
/*
+ * Complete the GPE initialization for the GPE blocks defined in the FADT
+ * (GPE block 0 and 1).
+ *
+ * Note1: This is where the _PRW methods are executed for the GPEs. These
+ * methods can only be executed after the SCI and Global Lock handlers are
+ * installed and initialized.
+ *
+ * Note2: Currently, there seems to be no need to run the _REG methods
+ * before execution of the _PRW methods and enabling of the GPEs.
+ */
+ if (!(flags & ACPI_NO_EVENT_INIT)) {
+ status = acpi_ev_install_fadt_gpes();
+ if (ACPI_FAILURE(status))
+ return (status);
+ }
+
+ /*
* Empty the caches (delete the cached objects) on the assumption that
* the table load filled them up more than they will be at runtime --
* thus wasting non-paged memory.
@@ -292,6 +292,7 @@
ACPI_EXPORT_SYMBOL(acpi_initialize_objects)
+#endif
/*******************************************************************************
*
* FUNCTION: acpi_terminate
@@ -335,6 +336,7 @@
}
ACPI_EXPORT_SYMBOL(acpi_terminate)
+#ifndef ACPI_ASL_COMPILER
#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -490,3 +492,4 @@
}
ACPI_EXPORT_SYMBOL(acpi_purge_cached_objects)
+#endif
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 44ea60c..1009261 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -398,7 +398,7 @@
element = &(package->package.elements[i]);
- if (element->type != ACPI_TYPE_ANY) {
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE) {
status = AE_BAD_DATA;
printk(KERN_ERR PREFIX
"Expecting a [Reference] package element, found type %X\n",
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 980a741..5e5dda3a 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -57,8 +57,6 @@
#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x88
#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x89
-#define ACPI_VIDEO_HEAD_INVALID (~0u - 1)
-#define ACPI_VIDEO_HEAD_END (~0u)
#define MAX_NAME_LEN 20
#define ACPI_VIDEO_DISPLAY_CRT 1
@@ -192,6 +190,7 @@
/* bus */
static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_video_bus_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -200,6 +199,7 @@
static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_video_bus_ROM_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_ROM_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -209,6 +209,7 @@
static int acpi_video_bus_POST_info_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_bus_POST_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_POST_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -217,6 +218,7 @@
static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_video_bus_POST_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_POST_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -225,6 +227,7 @@
static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
static struct file_operations acpi_video_bus_DOS_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_bus_DOS_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -235,6 +238,7 @@
static int acpi_video_device_info_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_device_info_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_device_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -244,6 +248,7 @@
static int acpi_video_device_state_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_device_state_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_device_state_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -253,6 +258,7 @@
static int acpi_video_device_brightness_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_device_brightness_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_device_brightness_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -262,6 +268,7 @@
static int acpi_video_device_EDID_open_fs(struct inode *inode,
struct file *file);
static struct file_operations acpi_video_device_EDID_fops = {
+ .owner = THIS_MODULE,
.open = acpi_video_device_EDID_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -734,21 +741,19 @@
if (IS_ERR(device->cdev))
return;
- if (device->cdev) {
- printk(KERN_INFO PREFIX
- "%s is registered as cooling_device%d\n",
- device->dev->dev.bus_id, device->cdev->id);
- result = sysfs_create_link(&device->dev->dev.kobj,
- &device->cdev->device.kobj,
- "thermal_cooling");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- result = sysfs_create_link(&device->cdev->device.kobj,
- &device->dev->dev.kobj,
- "device");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- }
+ printk(KERN_INFO PREFIX
+ "%s is registered as cooling_device%d\n",
+ device->dev->dev.bus_id, device->cdev->id);
+ result = sysfs_create_link(&device->dev->dev.kobj,
+ &device->cdev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ result = sysfs_create_link(&device->cdev->device.kobj,
+ &device->dev->dev.kobj, "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+
}
if (device->cap._DCS && device->cap._DSS){
static int count = 0;
@@ -1050,87 +1055,82 @@
static int acpi_video_device_add_fs(struct acpi_device *device)
{
- struct proc_dir_entry *entry = NULL;
+ struct proc_dir_entry *entry, *device_dir;
struct acpi_video_device *vid_dev;
-
- if (!device)
- return -ENODEV;
-
vid_dev = acpi_driver_data(device);
if (!vid_dev)
return -ENODEV;
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- vid_dev->video->dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- acpi_device_dir(device)->owner = THIS_MODULE;
- }
+ device_dir = proc_mkdir(acpi_device_bid(device),
+ vid_dev->video->dir);
+ if (!device_dir)
+ return -ENOMEM;
+
+ device_dir->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("info", S_IRUGO, device_dir,
+ &acpi_video_device_info_fops, acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_device_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_dir;
/* 'state' [R/W] */
- entry =
- create_proc_entry("state", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ acpi_video_device_state_fops.write = acpi_video_device_write_state;
+ entry = proc_create_data("state", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir,
+ &acpi_video_device_state_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- acpi_video_device_state_fops.write = acpi_video_device_write_state;
- entry->proc_fops = &acpi_video_device_state_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_info;
/* 'brightness' [R/W] */
- entry =
- create_proc_entry("brightness", S_IFREG | S_IRUGO | S_IWUSR,
- acpi_device_dir(device));
+ acpi_video_device_brightness_fops.write =
+ acpi_video_device_write_brightness;
+ entry = proc_create_data("brightness", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir,
+ &acpi_video_device_brightness_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- acpi_video_device_brightness_fops.write = acpi_video_device_write_brightness;
- entry->proc_fops = &acpi_video_device_brightness_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_state;
/* 'EDID' [R] */
- entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("EDID", S_IRUGO, device_dir,
+ &acpi_video_device_EDID_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_device_EDID_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_brightness;
+
+ acpi_device_dir(device) = device_dir;
return 0;
+
+ err_remove_brightness:
+ remove_proc_entry("brightness", device_dir);
+ err_remove_state:
+ remove_proc_entry("state", device_dir);
+ err_remove_info:
+ remove_proc_entry("info", device_dir);
+ err_remove_dir:
+ remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
+ return -ENOMEM;
}
static int acpi_video_device_remove_fs(struct acpi_device *device)
{
struct acpi_video_device *vid_dev;
+ struct proc_dir_entry *device_dir;
vid_dev = acpi_driver_data(device);
if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
return -ENODEV;
- if (acpi_device_dir(device)) {
- remove_proc_entry("info", acpi_device_dir(device));
- remove_proc_entry("state", acpi_device_dir(device));
- remove_proc_entry("brightness", acpi_device_dir(device));
- remove_proc_entry("EDID", acpi_device_dir(device));
+ device_dir = acpi_device_dir(device);
+ if (device_dir) {
+ remove_proc_entry("info", device_dir);
+ remove_proc_entry("state", device_dir);
+ remove_proc_entry("brightness", device_dir);
+ remove_proc_entry("EDID", device_dir);
remove_proc_entry(acpi_device_bid(device), vid_dev->video->dir);
acpi_device_dir(device) = NULL;
}
@@ -1337,94 +1337,81 @@
static int acpi_video_bus_add_fs(struct acpi_device *device)
{
- struct proc_dir_entry *entry = NULL;
- struct acpi_video_bus *video;
+ struct acpi_video_bus *video = acpi_driver_data(device);
+ struct proc_dir_entry *device_dir;
+ struct proc_dir_entry *entry;
+ device_dir = proc_mkdir(acpi_device_bid(device), acpi_video_dir);
+ if (!device_dir)
+ return -ENOMEM;
- video = acpi_driver_data(device);
-
- if (!acpi_device_dir(device)) {
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
- acpi_video_dir);
- if (!acpi_device_dir(device))
- return -ENODEV;
- video->dir = acpi_device_dir(device);
- acpi_device_dir(device)->owner = THIS_MODULE;
- }
+ device_dir->owner = THIS_MODULE;
/* 'info' [R] */
- entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("info", S_IRUGO, device_dir,
+ &acpi_video_bus_info_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_bus_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_dir;
/* 'ROM' [R] */
- entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("ROM", S_IRUGO, device_dir,
+ &acpi_video_bus_ROM_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_bus_ROM_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_info;
/* 'POST_info' [R] */
- entry =
- create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
+ entry = proc_create_data("POST_info", S_IRUGO, device_dir,
+ &acpi_video_bus_POST_info_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- entry->proc_fops = &acpi_video_bus_POST_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_rom;
/* 'POST' [R/W] */
- entry =
- create_proc_entry("POST", S_IFREG | S_IRUGO | S_IRUSR,
- acpi_device_dir(device));
+ acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
+ entry = proc_create_data("POST", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir,
+ &acpi_video_bus_POST_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- acpi_video_bus_POST_fops.write = acpi_video_bus_write_POST;
- entry->proc_fops = &acpi_video_bus_POST_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_post_info;
/* 'DOS' [R/W] */
- entry =
- create_proc_entry("DOS", S_IFREG | S_IRUGO | S_IRUSR,
- acpi_device_dir(device));
+ acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
+ entry = proc_create_data("DOS", S_IFREG | S_IRUGO | S_IWUSR,
+ device_dir,
+ &acpi_video_bus_DOS_fops,
+ acpi_driver_data(device));
if (!entry)
- return -ENODEV;
- else {
- acpi_video_bus_DOS_fops.write = acpi_video_bus_write_DOS;
- entry->proc_fops = &acpi_video_bus_DOS_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
+ goto err_remove_post;
+ video->dir = acpi_device_dir(device) = device_dir;
return 0;
+
+ err_remove_post:
+ remove_proc_entry("POST", device_dir);
+ err_remove_post_info:
+ remove_proc_entry("POST_info", device_dir);
+ err_remove_rom:
+ remove_proc_entry("ROM", device_dir);
+ err_remove_info:
+ remove_proc_entry("info", device_dir);
+ err_remove_dir:
+ remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
+ return -ENOMEM;
}
static int acpi_video_bus_remove_fs(struct acpi_device *device)
{
- struct acpi_video_bus *video;
+ struct proc_dir_entry *device_dir = acpi_device_dir(device);
-
- video = acpi_driver_data(device);
-
- if (acpi_device_dir(device)) {
- remove_proc_entry("info", acpi_device_dir(device));
- remove_proc_entry("ROM", acpi_device_dir(device));
- remove_proc_entry("POST_info", acpi_device_dir(device));
- remove_proc_entry("POST", acpi_device_dir(device));
- remove_proc_entry("DOS", acpi_device_dir(device));
+ if (device_dir) {
+ remove_proc_entry("info", device_dir);
+ remove_proc_entry("ROM", device_dir);
+ remove_proc_entry("POST_info", device_dir);
+ remove_proc_entry("POST", device_dir);
+ remove_proc_entry("DOS", device_dir);
remove_proc_entry(acpi_device_bid(device), acpi_video_dir);
acpi_device_dir(device) = NULL;
}
@@ -1440,11 +1427,15 @@
static struct acpi_video_device_attrib*
acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
{
- int count;
+ struct acpi_video_enumerated_device *ids;
+ int i;
- for(count = 0; count < video->attached_count; count++)
- if((video->attached_array[count].value.int_val & 0xffff) == device_id)
- return &(video->attached_array[count].value.attrib);
+ for (i = 0; i < video->attached_count; i++) {
+ ids = &video->attached_array[i];
+ if ((ids->value.int_val & 0xffff) == device_id)
+ return &ids->value.attrib;
+ }
+
return NULL;
}
@@ -1571,20 +1562,16 @@
acpi_video_device_bind(struct acpi_video_bus *video,
struct acpi_video_device *device)
{
+ struct acpi_video_enumerated_device *ids;
int i;
-#define IDS_VAL(i) video->attached_array[i].value.int_val
-#define IDS_BIND(i) video->attached_array[i].bind_info
-
- for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID &&
- i < video->attached_count; i++) {
- if (device->device_id == (IDS_VAL(i) & 0xffff)) {
- IDS_BIND(i) = device;
+ for (i = 0; i < video->attached_count; i++) {
+ ids = &video->attached_array[i];
+ if (device->device_id == (ids->value.int_val & 0xffff)) {
+ ids->bind_info = device;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
}
}
-#undef IDS_VAL
-#undef IDS_BIND
}
/*
@@ -1603,7 +1590,7 @@
int status;
int count;
int i;
- struct acpi_video_enumerated_device *active_device_list;
+ struct acpi_video_enumerated_device *active_list;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *dod = NULL;
union acpi_object *obj;
@@ -1624,13 +1611,10 @@
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
dod->package.count));
- active_device_list = kmalloc((1 +
- dod->package.count) *
- sizeof(struct
- acpi_video_enumerated_device),
- GFP_KERNEL);
-
- if (!active_device_list) {
+ active_list = kcalloc(1 + dod->package.count,
+ sizeof(struct acpi_video_enumerated_device),
+ GFP_KERNEL);
+ if (!active_list) {
status = -ENOMEM;
goto out;
}
@@ -1640,23 +1624,24 @@
obj = &dod->package.elements[i];
if (obj->type != ACPI_TYPE_INTEGER) {
- printk(KERN_ERR PREFIX "Invalid _DOD data\n");
- active_device_list[i].value.int_val =
- ACPI_VIDEO_HEAD_INVALID;
+ printk(KERN_ERR PREFIX
+ "Invalid _DOD data in element %d\n", i);
+ continue;
}
- active_device_list[i].value.int_val = obj->integer.value;
- active_device_list[i].bind_info = NULL;
+
+ active_list[count].value.int_val = obj->integer.value;
+ active_list[count].bind_info = NULL;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
(int)obj->integer.value));
count++;
}
- active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
kfree(video->attached_array);
- video->attached_array = active_device_list;
+ video->attached_array = active_list;
video->attached_count = count;
- out:
+
+ out:
kfree(buffer.pointer);
return status;
}
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 292aa9a..1c11df9 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -566,11 +566,11 @@
If unsure, say N.
-config PATA_RB500
- tristate "RouterBoard 500 PATA CompactFlash support"
- depends on MIKROTIK_RB500
+config PATA_RB532
+ tristate "RouterBoard 532 PATA CompactFlash support"
+ depends on MIKROTIK_RB532
help
- This option enables support for the RouterBoard 500
+ This option enables support for the RouterBoard 532
PATA CompactFlash controller.
If unsure, say N.
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index 1fbc2aa..b693d82 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -55,7 +55,7 @@
obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
obj-$(CONFIG_PATA_QDI) += pata_qdi.o
obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
-obj-$(CONFIG_PATA_RB500) += pata_rb500_cf.o
+obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o
obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 7c4f886..8cace9a 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -358,7 +358,7 @@
/* board_ahci_sb600 */
{
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
- AHCI_HFLAG_32BIT_ONLY |
+ AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
AHCI_HFLAG_SECT255 | AHCI_HFLAG_NO_PMP),
.flags = AHCI_FLAG_COMMON,
.pio_mask = 0x1f, /* pio0-4 */
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 51b7d2f..3bc4885 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -3933,6 +3933,9 @@
/* Devices which get the IVB wrong */
{ "QUANTUM FIREBALLlct10 05", "A03.0900", ATA_HORKAGE_IVB, },
+ /* Maybe we should just blacklist TSSTcorp... */
+ { "TSSTcorp CDDVDW SH-S202H", "SB00", ATA_HORKAGE_IVB, },
+ { "TSSTcorp CDDVDW SH-S202H", "SB01", ATA_HORKAGE_IVB, },
{ "TSSTcorp CDDVDW SH-S202J", "SB00", ATA_HORKAGE_IVB, },
{ "TSSTcorp CDDVDW SH-S202J", "SB01", ATA_HORKAGE_IVB, },
{ "TSSTcorp CDDVDW SH-S202N", "SB00", ATA_HORKAGE_IVB, },
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index a34f324..3ce4392 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -49,7 +49,11 @@
#include "libata.h"
-#define SECTOR_SIZE 512
+#define SECTOR_SIZE 512
+#define ATA_SCSI_RBUF_SIZE 4096
+
+static DEFINE_SPINLOCK(ata_scsi_rbuf_lock);
+static u8 ata_scsi_rbuf[ATA_SCSI_RBUF_SIZE];
typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc);
@@ -179,6 +183,13 @@
ata_scsi_lpm_show, ata_scsi_lpm_put);
EXPORT_SYMBOL_GPL(dev_attr_link_power_management_policy);
+static void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
+{
+ cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+ scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
+}
+
static void ata_scsi_invalid_field(struct scsi_cmnd *cmd,
void (*done)(struct scsi_cmnd *))
{
@@ -1632,53 +1643,48 @@
/**
* ata_scsi_rbuf_get - Map response buffer.
- * @cmd: SCSI command containing buffer to be mapped.
- * @buf_out: Pointer to mapped area.
+ * @flags: unsigned long variable to store irq enable status
+ * @copy_in: copy in from user buffer
*
- * Maps buffer contained within SCSI command @cmd.
+ * Prepare buffer for simulated SCSI commands.
*
* LOCKING:
- * spin_lock_irqsave(host lock)
+ * spin_lock_irqsave(ata_scsi_rbuf_lock) on success
*
* RETURNS:
- * Length of response buffer.
+ * Pointer to response buffer.
*/
-
-static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
+static void *ata_scsi_rbuf_get(struct scsi_cmnd *cmd, bool copy_in,
+ unsigned long *flags)
{
- u8 *buf;
- unsigned int buflen;
+ spin_lock_irqsave(&ata_scsi_rbuf_lock, *flags);
- struct scatterlist *sg = scsi_sglist(cmd);
-
- if (sg) {
- buf = kmap_atomic(sg_page(sg), KM_IRQ0) + sg->offset;
- buflen = sg->length;
- } else {
- buf = NULL;
- buflen = 0;
- }
-
- *buf_out = buf;
- return buflen;
+ memset(ata_scsi_rbuf, 0, ATA_SCSI_RBUF_SIZE);
+ if (copy_in)
+ sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
+ ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE);
+ return ata_scsi_rbuf;
}
/**
* ata_scsi_rbuf_put - Unmap response buffer.
* @cmd: SCSI command containing buffer to be unmapped.
- * @buf: buffer to unmap
+ * @copy_out: copy out result
+ * @flags: @flags passed to ata_scsi_rbuf_get()
*
- * Unmaps response buffer contained within @cmd.
+ * Returns rbuf buffer. The result is copied to @cmd's buffer if
+ * @copy_back is true.
*
* LOCKING:
- * spin_lock_irqsave(host lock)
+ * Unlocks ata_scsi_rbuf_lock.
*/
-
-static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
+static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, bool copy_out,
+ unsigned long *flags)
{
- struct scatterlist *sg = scsi_sglist(cmd);
- if (sg)
- kunmap_atomic(buf - sg->offset, KM_IRQ0);
+ if (copy_out)
+ sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd),
+ ata_scsi_rbuf, ATA_SCSI_RBUF_SIZE);
+ spin_unlock_irqrestore(&ata_scsi_rbuf_lock, *flags);
}
/**
@@ -1696,24 +1702,17 @@
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen))
+static void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+ unsigned int (*actor)(struct ata_scsi_args *args, u8 *rbuf))
{
u8 *rbuf;
- unsigned int buflen, rc;
+ unsigned int rc;
struct scsi_cmnd *cmd = args->cmd;
unsigned long flags;
- local_irq_save(flags);
-
- buflen = ata_scsi_rbuf_get(cmd, &rbuf);
- memset(rbuf, 0, buflen);
- rc = actor(args, rbuf, buflen);
- ata_scsi_rbuf_put(cmd, rbuf);
-
- local_irq_restore(flags);
+ rbuf = ata_scsi_rbuf_get(cmd, false, &flags);
+ rc = actor(args, rbuf);
+ ata_scsi_rbuf_put(cmd, rc == 0, &flags);
if (rc == 0)
cmd->result = SAM_STAT_GOOD;
@@ -1721,26 +1720,9 @@
}
/**
- * ATA_SCSI_RBUF_SET - helper to set values in SCSI response buffer
- * @idx: byte index into SCSI response buffer
- * @val: value to set
- *
- * To be used by SCSI command simulator functions. This macros
- * expects two local variables, u8 *rbuf and unsigned int buflen,
- * are in scope.
- *
- * LOCKING:
- * None.
- */
-#define ATA_SCSI_RBUF_SET(idx, val) do { \
- if ((idx) < buflen) rbuf[(idx)] = (u8)(val); \
- } while (0)
-
-/**
* ata_scsiop_inq_std - Simulate INQUIRY command
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Returns standard device identification data associated
* with non-VPD INQUIRY command output.
@@ -1748,10 +1730,17 @@
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
{
+ const u8 versions[] = {
+ 0x60, /* SAM-3 (no version claimed) */
+
+ 0x03,
+ 0x20, /* SBC-2 (no version claimed) */
+
+ 0x02,
+ 0x60 /* SPC-3 (no version claimed) */
+ };
u8 hdr[] = {
TYPE_DISK,
0,
@@ -1760,35 +1749,21 @@
95 - 4
};
+ VPRINTK("ENTER\n");
+
/* set scsi removeable (RMB) bit per ata bit */
if (ata_id_removeable(args->id))
hdr[1] |= (1 << 7);
- VPRINTK("ENTER\n");
-
memcpy(rbuf, hdr, sizeof(hdr));
+ memcpy(&rbuf[8], "ATA ", 8);
+ ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);
+ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
- if (buflen > 35) {
- memcpy(&rbuf[8], "ATA ", 8);
- ata_id_string(args->id, &rbuf[16], ATA_ID_PROD, 16);
- ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
- if (rbuf[32] == 0 || rbuf[32] == ' ')
- memcpy(&rbuf[32], "n/a ", 4);
- }
+ if (rbuf[32] == 0 || rbuf[32] == ' ')
+ memcpy(&rbuf[32], "n/a ", 4);
- if (buflen > 63) {
- const u8 versions[] = {
- 0x60, /* SAM-3 (no version claimed) */
-
- 0x03,
- 0x20, /* SBC-2 (no version claimed) */
-
- 0x02,
- 0x60 /* SPC-3 (no version claimed) */
- };
-
- memcpy(rbuf + 59, versions, sizeof(versions));
- }
+ memcpy(rbuf + 59, versions, sizeof(versions));
return 0;
}
@@ -1797,27 +1772,22 @@
* ata_scsiop_inq_00 - Simulate INQUIRY VPD page 0, list of pages
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Returns list of inquiry VPD pages available.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf)
{
const u8 pages[] = {
0x00, /* page 0x00, this page */
0x80, /* page 0x80, unit serial no page */
0x83 /* page 0x83, device ident page */
};
+
rbuf[3] = sizeof(pages); /* number of supported VPD pages */
-
- if (buflen > 6)
- memcpy(rbuf + 4, pages, sizeof(pages));
-
+ memcpy(rbuf + 4, pages, sizeof(pages));
return 0;
}
@@ -1825,16 +1795,13 @@
* ata_scsiop_inq_80 - Simulate INQUIRY VPD page 80, device serial number
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Returns ATA device serial number.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf)
{
const u8 hdr[] = {
0,
@@ -1842,12 +1809,10 @@
0,
ATA_ID_SERNO_LEN, /* page len */
};
+
memcpy(rbuf, hdr, sizeof(hdr));
-
- if (buflen > (ATA_ID_SERNO_LEN + 4 - 1))
- ata_id_string(args->id, (unsigned char *) &rbuf[4],
- ATA_ID_SERNO, ATA_ID_SERNO_LEN);
-
+ ata_id_string(args->id, (unsigned char *) &rbuf[4],
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
return 0;
}
@@ -1855,7 +1820,6 @@
* ata_scsiop_inq_83 - Simulate INQUIRY VPD page 83, device identity
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Yields two logical unit device identification designators:
* - vendor specific ASCII containing the ATA serial number
@@ -1865,41 +1829,37 @@
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf)
{
- int num;
const int sat_model_serial_desc_len = 68;
+ int num;
rbuf[1] = 0x83; /* this page code */
num = 4;
- if (buflen > (ATA_ID_SERNO_LEN + num + 3)) {
- /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
- rbuf[num + 0] = 2;
- rbuf[num + 3] = ATA_ID_SERNO_LEN;
- num += 4;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO, ATA_ID_SERNO_LEN);
- num += ATA_ID_SERNO_LEN;
- }
- if (buflen > (sat_model_serial_desc_len + num + 3)) {
- /* SAT defined lu model and serial numbers descriptor */
- /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
- rbuf[num + 0] = 2;
- rbuf[num + 1] = 1;
- rbuf[num + 3] = sat_model_serial_desc_len;
- num += 4;
- memcpy(rbuf + num, "ATA ", 8);
- num += 8;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_PROD, ATA_ID_PROD_LEN);
- num += ATA_ID_PROD_LEN;
- ata_id_string(args->id, (unsigned char *) rbuf + num,
- ATA_ID_SERNO, ATA_ID_SERNO_LEN);
- num += ATA_ID_SERNO_LEN;
- }
+ /* piv=0, assoc=lu, code_set=ACSII, designator=vendor */
+ rbuf[num + 0] = 2;
+ rbuf[num + 3] = ATA_ID_SERNO_LEN;
+ num += 4;
+ ata_id_string(args->id, (unsigned char *) rbuf + num,
+ ATA_ID_SERNO, ATA_ID_SERNO_LEN);
+ num += ATA_ID_SERNO_LEN;
+
+ /* SAT defined lu model and serial numbers descriptor */
+ /* piv=0, assoc=lu, code_set=ACSII, designator=t10 vendor id */
+ rbuf[num + 0] = 2;
+ rbuf[num + 1] = 1;
+ rbuf[num + 3] = sat_model_serial_desc_len;
+ num += 4;
+ memcpy(rbuf + num, "ATA ", 8);
+ num += 8;
+ ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_PROD,
+ ATA_ID_PROD_LEN);
+ num += ATA_ID_PROD_LEN;
+ ata_id_string(args->id, (unsigned char *) rbuf + num, ATA_ID_SERNO,
+ ATA_ID_SERNO_LEN);
+ num += ATA_ID_SERNO_LEN;
+
rbuf[3] = num - 4; /* page len (assume less than 256 bytes) */
return 0;
}
@@ -1908,35 +1868,26 @@
* ata_scsiop_inq_89 - Simulate INQUIRY VPD page 89, ATA info
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Yields SAT-specified ATA VPD page.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_inq_89(struct ata_scsi_args *args, u8 *rbuf)
{
- u8 pbuf[60];
struct ata_taskfile tf;
- unsigned int i;
- if (!buflen)
- return 0;
-
- memset(&pbuf, 0, sizeof(pbuf));
memset(&tf, 0, sizeof(tf));
- pbuf[1] = 0x89; /* our page code */
- pbuf[2] = (0x238 >> 8); /* page size fixed at 238h */
- pbuf[3] = (0x238 & 0xff);
+ rbuf[1] = 0x89; /* our page code */
+ rbuf[2] = (0x238 >> 8); /* page size fixed at 238h */
+ rbuf[3] = (0x238 & 0xff);
- memcpy(&pbuf[8], "linux ", 8);
- memcpy(&pbuf[16], "libata ", 16);
- memcpy(&pbuf[32], DRV_VERSION, 4);
- ata_id_string(args->id, &pbuf[32], ATA_ID_FW_REV, 4);
+ memcpy(&rbuf[8], "linux ", 8);
+ memcpy(&rbuf[16], "libata ", 16);
+ memcpy(&rbuf[32], DRV_VERSION, 4);
+ ata_id_string(args->id, &rbuf[32], ATA_ID_FW_REV, 4);
/* we don't store the ATA device signature, so we fake it */
@@ -1944,19 +1895,12 @@
tf.lbal = 0x1;
tf.nsect = 0x1;
- ata_tf_to_fis(&tf, 0, 1, &pbuf[36]); /* TODO: PMP? */
- pbuf[36] = 0x34; /* force D2H Reg FIS (34h) */
+ ata_tf_to_fis(&tf, 0, 1, &rbuf[36]); /* TODO: PMP? */
+ rbuf[36] = 0x34; /* force D2H Reg FIS (34h) */
- pbuf[56] = ATA_CMD_ID_ATA;
+ rbuf[56] = ATA_CMD_ID_ATA;
- i = min(buflen, 60U);
- memcpy(rbuf, &pbuf[0], i);
- buflen -= i;
-
- if (!buflen)
- return 0;
-
- memcpy(&rbuf[60], &args->id[0], min(buflen, 512U));
+ memcpy(&rbuf[60], &args->id[0], 512);
return 0;
}
@@ -1964,7 +1908,6 @@
* ata_scsiop_noop - Command handler that simply returns success.
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* No operation. Simply returns success to caller, to indicate
* that the caller should successfully complete this SCSI command.
@@ -1972,47 +1915,16 @@
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf)
{
VPRINTK("ENTER\n");
return 0;
}
/**
- * ata_msense_push - Push data onto MODE SENSE data output buffer
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
- * @buf: Pointer to BLOB being added to output buffer
- * @buflen: Length of BLOB
- *
- * Store MODE SENSE data on an output buffer.
- *
- * LOCKING:
- * None.
- */
-
-static void ata_msense_push(u8 **ptr_io, const u8 *last,
- const u8 *buf, unsigned int buflen)
-{
- u8 *ptr = *ptr_io;
-
- if ((ptr + buflen - 1) > last)
- return;
-
- memcpy(ptr, buf, buflen);
-
- ptr += buflen;
-
- *ptr_io = ptr;
-}
-
-/**
* ata_msense_caching - Simulate MODE SENSE caching info page
* @id: device IDENTIFY data
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
+ * @buf: output buffer
*
* Generate a caching info page, which conditionally indicates
* write caching to the SCSI layer, depending on device
@@ -2021,58 +1933,43 @@
* LOCKING:
* None.
*/
-
-static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
- const u8 *last)
+static unsigned int ata_msense_caching(u16 *id, u8 *buf)
{
- u8 page[CACHE_MPAGE_LEN];
-
- memcpy(page, def_cache_mpage, sizeof(page));
+ memcpy(buf, def_cache_mpage, sizeof(def_cache_mpage));
if (ata_id_wcache_enabled(id))
- page[2] |= (1 << 2); /* write cache enable */
+ buf[2] |= (1 << 2); /* write cache enable */
if (!ata_id_rahead_enabled(id))
- page[12] |= (1 << 5); /* disable read ahead */
-
- ata_msense_push(ptr_io, last, page, sizeof(page));
- return sizeof(page);
+ buf[12] |= (1 << 5); /* disable read ahead */
+ return sizeof(def_cache_mpage);
}
/**
* ata_msense_ctl_mode - Simulate MODE SENSE control mode page
- * @dev: Device associated with this MODE SENSE command
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
+ * @buf: output buffer
*
* Generate a generic MODE SENSE control mode page.
*
* LOCKING:
* None.
*/
-
-static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
+static unsigned int ata_msense_ctl_mode(u8 *buf)
{
- ata_msense_push(ptr_io, last, def_control_mpage,
- sizeof(def_control_mpage));
+ memcpy(buf, def_control_mpage, sizeof(def_control_mpage));
return sizeof(def_control_mpage);
}
/**
* ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
- * @dev: Device associated with this MODE SENSE command
- * @ptr_io: (input/output) Location to store more output data
- * @last: End of output data buffer
+ * @bufp: output buffer
*
* Generate a generic MODE SENSE r/w error recovery page.
*
* LOCKING:
* None.
*/
-
-static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
+static unsigned int ata_msense_rw_recovery(u8 *buf)
{
-
- ata_msense_push(ptr_io, last, def_rw_recovery_mpage,
- sizeof(def_rw_recovery_mpage));
+ memcpy(buf, def_rw_recovery_mpage, sizeof(def_rw_recovery_mpage));
return sizeof(def_rw_recovery_mpage);
}
@@ -2104,7 +2001,6 @@
* ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Simulate MODE SENSE commands. Assume this is invoked for direct
* access devices (e.g. disks) only. There should be no block
@@ -2113,19 +2009,17 @@
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf)
{
struct ata_device *dev = args->dev;
- u8 *scsicmd = args->cmd->cmnd, *p, *last;
+ u8 *scsicmd = args->cmd->cmnd, *p = rbuf;
const u8 sat_blk_desc[] = {
0, 0, 0, 0, /* number of blocks: sat unspecified */
0,
0, 0x2, 0x0 /* block length: 512 bytes */
};
u8 pg, spg;
- unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen;
+ unsigned int ebd, page_control, six_byte;
u8 dpofua;
VPRINTK("ENTER\n");
@@ -2148,17 +2042,10 @@
goto invalid_fld;
}
- if (six_byte) {
- output_len = 4 + (ebd ? 8 : 0);
- alloc_len = scsicmd[4];
- } else {
- output_len = 8 + (ebd ? 8 : 0);
- alloc_len = (scsicmd[7] << 8) + scsicmd[8];
- }
- minlen = (alloc_len < buflen) ? alloc_len : buflen;
-
- p = rbuf + output_len;
- last = rbuf + minlen - 1;
+ if (six_byte)
+ p += 4 + (ebd ? 8 : 0);
+ else
+ p += 8 + (ebd ? 8 : 0);
pg = scsicmd[2] & 0x3f;
spg = scsicmd[3];
@@ -2171,61 +2058,48 @@
switch(pg) {
case RW_RECOVERY_MPAGE:
- output_len += ata_msense_rw_recovery(&p, last);
+ p += ata_msense_rw_recovery(p);
break;
case CACHE_MPAGE:
- output_len += ata_msense_caching(args->id, &p, last);
+ p += ata_msense_caching(args->id, p);
break;
- case CONTROL_MPAGE: {
- output_len += ata_msense_ctl_mode(&p, last);
+ case CONTROL_MPAGE:
+ p += ata_msense_ctl_mode(p);
break;
- }
case ALL_MPAGES:
- output_len += ata_msense_rw_recovery(&p, last);
- output_len += ata_msense_caching(args->id, &p, last);
- output_len += ata_msense_ctl_mode(&p, last);
+ p += ata_msense_rw_recovery(p);
+ p += ata_msense_caching(args->id, p);
+ p += ata_msense_ctl_mode(p);
break;
default: /* invalid page code */
goto invalid_fld;
}
- if (minlen < 1)
- return 0;
-
dpofua = 0;
if (ata_dev_supports_fua(args->id) && (dev->flags & ATA_DFLAG_LBA48) &&
(!(dev->flags & ATA_DFLAG_PIO) || dev->multi_count))
dpofua = 1 << 4;
if (six_byte) {
- output_len--;
- rbuf[0] = output_len;
- if (minlen > 2)
- rbuf[2] |= dpofua;
+ rbuf[0] = p - rbuf - 1;
+ rbuf[2] |= dpofua;
if (ebd) {
- if (minlen > 3)
- rbuf[3] = sizeof(sat_blk_desc);
- if (minlen > 11)
- memcpy(rbuf + 4, sat_blk_desc,
- sizeof(sat_blk_desc));
+ rbuf[3] = sizeof(sat_blk_desc);
+ memcpy(rbuf + 4, sat_blk_desc, sizeof(sat_blk_desc));
}
} else {
- output_len -= 2;
+ unsigned int output_len = p - rbuf - 2;
+
rbuf[0] = output_len >> 8;
- if (minlen > 1)
- rbuf[1] = output_len;
- if (minlen > 3)
- rbuf[3] |= dpofua;
+ rbuf[1] = output_len;
+ rbuf[3] |= dpofua;
if (ebd) {
- if (minlen > 7)
- rbuf[7] = sizeof(sat_blk_desc);
- if (minlen > 15)
- memcpy(rbuf + 8, sat_blk_desc,
- sizeof(sat_blk_desc));
+ rbuf[7] = sizeof(sat_blk_desc);
+ memcpy(rbuf + 8, sat_blk_desc, sizeof(sat_blk_desc));
}
}
return 0;
@@ -2245,15 +2119,13 @@
* ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Simulate READ CAPACITY commands.
*
* LOCKING:
* None.
*/
-unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf)
{
u64 last_lba = args->dev->n_sectors - 1; /* LBA of the last block */
@@ -2264,28 +2136,28 @@
last_lba = 0xffffffff;
/* sector count, 32-bit */
- ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 3));
- ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 2));
- ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 1));
- ATA_SCSI_RBUF_SET(3, last_lba);
+ rbuf[0] = last_lba >> (8 * 3);
+ rbuf[1] = last_lba >> (8 * 2);
+ rbuf[2] = last_lba >> (8 * 1);
+ rbuf[3] = last_lba;
/* sector size */
- ATA_SCSI_RBUF_SET(6, ATA_SECT_SIZE >> 8);
- ATA_SCSI_RBUF_SET(7, ATA_SECT_SIZE & 0xff);
+ rbuf[6] = ATA_SECT_SIZE >> 8;
+ rbuf[7] = ATA_SECT_SIZE & 0xff;
} else {
/* sector count, 64-bit */
- ATA_SCSI_RBUF_SET(0, last_lba >> (8 * 7));
- ATA_SCSI_RBUF_SET(1, last_lba >> (8 * 6));
- ATA_SCSI_RBUF_SET(2, last_lba >> (8 * 5));
- ATA_SCSI_RBUF_SET(3, last_lba >> (8 * 4));
- ATA_SCSI_RBUF_SET(4, last_lba >> (8 * 3));
- ATA_SCSI_RBUF_SET(5, last_lba >> (8 * 2));
- ATA_SCSI_RBUF_SET(6, last_lba >> (8 * 1));
- ATA_SCSI_RBUF_SET(7, last_lba);
+ rbuf[0] = last_lba >> (8 * 7);
+ rbuf[1] = last_lba >> (8 * 6);
+ rbuf[2] = last_lba >> (8 * 5);
+ rbuf[3] = last_lba >> (8 * 4);
+ rbuf[4] = last_lba >> (8 * 3);
+ rbuf[5] = last_lba >> (8 * 2);
+ rbuf[6] = last_lba >> (8 * 1);
+ rbuf[7] = last_lba;
/* sector size */
- ATA_SCSI_RBUF_SET(10, ATA_SECT_SIZE >> 8);
- ATA_SCSI_RBUF_SET(11, ATA_SECT_SIZE & 0xff);
+ rbuf[10] = ATA_SECT_SIZE >> 8;
+ rbuf[11] = ATA_SECT_SIZE & 0xff;
}
return 0;
@@ -2295,16 +2167,13 @@
* ata_scsiop_report_luns - Simulate REPORT LUNS command
* @args: device IDENTIFY data / SCSI command of interest.
* @rbuf: Response buffer, to which simulated SCSI cmd output is sent.
- * @buflen: Response buffer length.
*
* Simulate REPORT LUNS command.
*
* LOCKING:
* spin_lock_irqsave(host lock)
*/
-
-unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen)
+static unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf)
{
VPRINTK("ENTER\n");
rbuf[3] = 8; /* just one lun, LUN 0, size 8 bytes */
@@ -2312,53 +2181,6 @@
return 0;
}
-/**
- * ata_scsi_set_sense - Set SCSI sense data and status
- * @cmd: SCSI request to be handled
- * @sk: SCSI-defined sense key
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that builds a valid fixed format, current
- * response code and the given sense key (sk), additional sense
- * code (asc) and additional sense code qualifier (ascq) with
- * a SCSI command status of %SAM_STAT_CHECK_CONDITION and
- * DRIVER_SENSE set in the upper bits of scsi_cmnd::result .
- *
- * LOCKING:
- * Not required
- */
-
-void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq)
-{
- cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
-
- scsi_build_sense_buffer(0, cmd->sense_buffer, sk, asc, ascq);
-}
-
-/**
- * ata_scsi_badcmd - End a SCSI request with an error
- * @cmd: SCSI request to be handled
- * @done: SCSI command completion function
- * @asc: SCSI-defined additional sense code
- * @ascq: SCSI-defined additional sense code qualifier
- *
- * Helper function that completes a SCSI command with
- * %SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
- * and the specified additional sense codes.
- *
- * LOCKING:
- * spin_lock_irqsave(host lock)
- */
-
-void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
-{
- DPRINTK("ENTER\n");
- ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq);
-
- done(cmd);
-}
-
static void atapi_sense_complete(struct ata_queued_cmd *qc)
{
if (qc->err_mask && ((qc->err_mask & AC_ERR_DEV) == 0)) {
@@ -2485,13 +2307,10 @@
u8 *scsicmd = cmd->cmnd;
if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) {
- u8 *buf = NULL;
- unsigned int buflen;
unsigned long flags;
+ u8 *buf;
- local_irq_save(flags);
-
- buflen = ata_scsi_rbuf_get(cmd, &buf);
+ buf = ata_scsi_rbuf_get(cmd, true, &flags);
/* ATAPI devices typically report zero for their SCSI version,
* and sometimes deviate from the spec WRT response data
@@ -2506,9 +2325,7 @@
buf[3] = 0x32;
}
- ata_scsi_rbuf_put(cmd, buf);
-
- local_irq_restore(flags);
+ ata_scsi_rbuf_put(cmd, true, &flags);
}
cmd->result = SAM_STAT_GOOD;
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index ae2cfd9..4514283 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -146,34 +146,6 @@
extern int ata_scsi_offline_dev(struct ata_device *dev);
extern void ata_scsi_media_change_notify(struct ata_device *dev);
extern void ata_scsi_hotplug(struct work_struct *work);
-extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-
-extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-
-extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
- unsigned int buflen);
-extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *),
- u8 asc, u8 ascq);
-extern void ata_scsi_set_sense(struct scsi_cmnd *cmd,
- u8 sk, u8 asc, u8 ascq);
-extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
- unsigned int (*actor) (struct ata_scsi_args *args,
- u8 *rbuf, unsigned int buflen));
extern void ata_schedule_scsi_eh(struct Scsi_Host *shost);
extern void ata_scsi_dev_rescan(struct work_struct *work);
extern int ata_bus_probe(struct ata_port *ap);
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 78738fb..d7de7ba 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -88,8 +88,8 @@
pci_write_config_word(pdev, ATIIXP_IDE_PIO_MODE, pio_mode_data);
pci_read_config_word(pdev, ATIIXP_IDE_PIO_TIMING, &pio_timing_data);
- pio_mode_data &= ~(0xFF << timing_shift);
- pio_mode_data |= (pio_timings[pio] << timing_shift);
+ pio_timing_data &= ~(0xFF << timing_shift);
+ pio_timing_data |= (pio_timings[pio] << timing_shift);
pci_write_config_word(pdev, ATIIXP_IDE_PIO_TIMING, pio_timing_data);
}
diff --git a/drivers/ata/pata_bf54x.c b/drivers/ata/pata_bf54x.c
index a75de06..9ab8973 100644
--- a/drivers/ata/pata_bf54x.c
+++ b/drivers/ata/pata_bf54x.c
@@ -1272,8 +1272,8 @@
void bfin_thaw(struct ata_port *ap)
{
+ dev_dbg(ap->dev, "in atapi dma thaw\n");
bfin_check_status(ap);
- bfin_irq_clear(ap);
bfin_irq_on(ap);
}
@@ -1339,13 +1339,130 @@
return 0;
}
+static unsigned int bfin_ata_host_intr(struct ata_port *ap,
+ struct ata_queued_cmd *qc)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ u8 status, host_stat = 0;
+
+ VPRINTK("ata%u: protocol %d task_state %d\n",
+ ap->print_id, qc->tf.protocol, ap->hsm_task_state);
+
+ /* Check whether we are expecting interrupt in this state */
+ switch (ap->hsm_task_state) {
+ case HSM_ST_FIRST:
+ /* Some pre-ATAPI-4 devices assert INTRQ
+ * at this state when ready to receive CDB.
+ */
+
+ /* Check the ATA_DFLAG_CDB_INTR flag is enough here.
+ * The flag was turned on only for atapi devices.
+ * No need to check is_atapi_taskfile(&qc->tf) again.
+ */
+ if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
+ goto idle_irq;
+ break;
+ case HSM_ST_LAST:
+ if (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATAPI_PROT_DMA) {
+ /* check status of DMA engine */
+ host_stat = ap->ops->bmdma_status(ap);
+ VPRINTK("ata%u: host_stat 0x%X\n",
+ ap->print_id, host_stat);
+
+ /* if it's not our irq... */
+ if (!(host_stat & ATA_DMA_INTR))
+ goto idle_irq;
+
+ /* before we do anything else, clear DMA-Start bit */
+ ap->ops->bmdma_stop(qc);
+
+ if (unlikely(host_stat & ATA_DMA_ERR)) {
+ /* error when transfering data to/from memory */
+ qc->err_mask |= AC_ERR_HOST_BUS;
+ ap->hsm_task_state = HSM_ST_ERR;
+ }
+ }
+ break;
+ case HSM_ST:
+ break;
+ default:
+ goto idle_irq;
+ }
+
+ /* check altstatus */
+ status = ap->ops->sff_check_altstatus(ap);
+ if (status & ATA_BUSY)
+ goto busy_ata;
+
+ /* check main status, clearing INTRQ */
+ status = ap->ops->sff_check_status(ap);
+ if (unlikely(status & ATA_BUSY))
+ goto busy_ata;
+
+ /* ack bmdma irq events */
+ ap->ops->sff_irq_clear(ap);
+
+ ata_sff_hsm_move(ap, qc, status, 0);
+
+ if (unlikely(qc->err_mask) && (qc->tf.protocol == ATA_PROT_DMA ||
+ qc->tf.protocol == ATAPI_PROT_DMA))
+ ata_ehi_push_desc(ehi, "BMDMA stat 0x%x", host_stat);
+
+busy_ata:
+ return 1; /* irq handled */
+
+idle_irq:
+ ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+ if ((ap->stats.idle_irq % 1000) == 0) {
+ ap->ops->irq_ack(ap, 0); /* debug trap */
+ ata_port_printk(ap, KERN_WARNING, "irq trap\n");
+ return 1;
+ }
+#endif
+ return 0; /* irq not handled */
+}
+
+static irqreturn_t bfin_ata_interrupt(int irq, void *dev_instance)
+{
+ struct ata_host *host = dev_instance;
+ unsigned int i;
+ unsigned int handled = 0;
+ unsigned long flags;
+
+ /* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+ spin_lock_irqsave(&host->lock, flags);
+
+ for (i = 0; i < host->n_ports; i++) {
+ struct ata_port *ap;
+
+ ap = host->ports[i];
+ if (ap &&
+ !(ap->flags & ATA_FLAG_DISABLED)) {
+ struct ata_queued_cmd *qc;
+
+ qc = ata_qc_from_tag(ap, ap->link.active_tag);
+ if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING)) &&
+ (qc->flags & ATA_QCFLAG_ACTIVE))
+ handled |= bfin_ata_host_intr(ap, qc);
+ }
+ }
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_RETVAL(handled);
+}
+
+
static struct scsi_host_template bfin_sht = {
ATA_BASE_SHT(DRV_NAME),
.sg_tablesize = SG_NONE,
.dma_boundary = ATA_DMA_BOUNDARY,
};
-static const struct ata_port_operations bfin_pata_ops = {
+static struct ata_port_operations bfin_pata_ops = {
.inherits = &ata_sff_port_ops,
.set_piomode = bfin_set_piomode,
@@ -1370,7 +1487,6 @@
.thaw = bfin_thaw,
.softreset = bfin_softreset,
.postreset = bfin_postreset,
- .post_internal_cmd = bfin_bmdma_stop,
.sff_irq_clear = bfin_irq_clear,
.sff_irq_on = bfin_irq_on,
@@ -1507,7 +1623,7 @@
}
if (ata_host_activate(host, platform_get_irq(pdev, 0),
- ata_sff_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
+ bfin_ata_interrupt, IRQF_SHARED, &bfin_sht) != 0) {
peripheral_free_list(atapi_io_port);
dev_err(&pdev->dev, "Fail to attach ATAPI device\n");
return -ENODEV;
diff --git a/drivers/ata/pata_rb500_cf.c b/drivers/ata/pata_rb532_cf.c
similarity index 72%
rename from drivers/ata/pata_rb500_cf.c
rename to drivers/ata/pata_rb532_cf.c
index 4345174..a108d25 100644
--- a/drivers/ata/pata_rb500_cf.c
+++ b/drivers/ata/pata_rb532_cf.c
@@ -32,7 +32,7 @@
#include <asm/gpio.h>
-#define DRV_NAME "pata-rb500-cf"
+#define DRV_NAME "pata-rb532-cf"
#define DRV_VERSION "0.1.0"
#define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash"
@@ -43,7 +43,7 @@
#define RB500_CF_REG_CTRL 0x080E
#define RB500_CF_REG_DATA 0x0C00
-struct rb500_cf_info {
+struct rb532_cf_info {
void __iomem *iobase;
unsigned int gpio_line;
int frozen;
@@ -52,10 +52,10 @@
/* ------------------------------------------------------------------------ */
-static inline void rb500_pata_finish_io(struct ata_port *ap)
+static inline void rb532_pata_finish_io(struct ata_port *ap)
{
struct ata_host *ah = ap->host;
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
ata_sff_altstatus(ap);
ndelay(RB500_CF_IO_DELAY);
@@ -63,14 +63,14 @@
set_irq_type(info->irq, IRQ_TYPE_LEVEL_HIGH);
}
-static void rb500_pata_exec_command(struct ata_port *ap,
+static void rb532_pata_exec_command(struct ata_port *ap,
const struct ata_taskfile *tf)
{
writeb(tf->command, ap->ioaddr.command_addr);
- rb500_pata_finish_io(ap);
+ rb532_pata_finish_io(ap);
}
-static void rb500_pata_data_xfer(struct ata_device *adev, unsigned char *buf,
+static void rb532_pata_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data)
{
struct ata_port *ap = adev->link->ap;
@@ -84,27 +84,27 @@
*buf = readb(ioaddr);
}
- rb500_pata_finish_io(adev->link->ap);
+ rb532_pata_finish_io(adev->link->ap);
}
-static void rb500_pata_freeze(struct ata_port *ap)
+static void rb532_pata_freeze(struct ata_port *ap)
{
- struct rb500_cf_info *info = ap->host->private_data;
+ struct rb532_cf_info *info = ap->host->private_data;
info->frozen = 1;
}
-static void rb500_pata_thaw(struct ata_port *ap)
+static void rb532_pata_thaw(struct ata_port *ap)
{
- struct rb500_cf_info *info = ap->host->private_data;
+ struct rb532_cf_info *info = ap->host->private_data;
info->frozen = 0;
}
-static irqreturn_t rb500_pata_irq_handler(int irq, void *dev_instance)
+static irqreturn_t rb532_pata_irq_handler(int irq, void *dev_instance)
{
struct ata_host *ah = dev_instance;
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
if (gpio_get_value(info->gpio_line)) {
set_irq_type(info->irq, IRQ_TYPE_LEVEL_LOW);
@@ -117,30 +117,30 @@
return IRQ_HANDLED;
}
-static struct ata_port_operations rb500_pata_port_ops = {
+static struct ata_port_operations rb532_pata_port_ops = {
.inherits = &ata_sff_port_ops,
- .sff_exec_command = rb500_pata_exec_command,
- .sff_data_xfer = rb500_pata_data_xfer,
- .freeze = rb500_pata_freeze,
- .thaw = rb500_pata_thaw,
+ .sff_exec_command = rb532_pata_exec_command,
+ .sff_data_xfer = rb532_pata_data_xfer,
+ .freeze = rb532_pata_freeze,
+ .thaw = rb532_pata_thaw,
};
/* ------------------------------------------------------------------------ */
-static struct scsi_host_template rb500_pata_sht = {
+static struct scsi_host_template rb532_pata_sht = {
ATA_PIO_SHT(DRV_NAME),
};
/* ------------------------------------------------------------------------ */
-static void rb500_pata_setup_ports(struct ata_host *ah)
+static void rb532_pata_setup_ports(struct ata_host *ah)
{
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
struct ata_port *ap;
ap = ah->ports[0];
- ap->ops = &rb500_pata_port_ops;
+ ap->ops = &rb532_pata_port_ops;
ap->pio_mask = 0x1f; /* PIO4 */
ap->flags = ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO;
@@ -153,13 +153,13 @@
ap->ioaddr.data_addr = info->iobase + RB500_CF_REG_DATA;
}
-static __devinit int rb500_pata_driver_probe(struct platform_device *pdev)
+static __devinit int rb532_pata_driver_probe(struct platform_device *pdev)
{
unsigned int irq;
int gpio;
struct resource *res;
struct ata_host *ah;
- struct rb500_cf_info *info;
+ struct rb532_cf_info *info;
int ret;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -213,10 +213,10 @@
goto err_free_gpio;
}
- rb500_pata_setup_ports(ah);
+ rb532_pata_setup_ports(ah);
- ret = ata_host_activate(ah, irq, rb500_pata_irq_handler,
- IRQF_TRIGGER_LOW, &rb500_pata_sht);
+ ret = ata_host_activate(ah, irq, rb532_pata_irq_handler,
+ IRQF_TRIGGER_LOW, &rb532_pata_sht);
if (ret)
goto err_free_gpio;
@@ -228,10 +228,10 @@
return ret;
}
-static __devexit int rb500_pata_driver_remove(struct platform_device *pdev)
+static __devexit int rb532_pata_driver_remove(struct platform_device *pdev)
{
struct ata_host *ah = platform_get_drvdata(pdev);
- struct rb500_cf_info *info = ah->private_data;
+ struct rb532_cf_info *info = ah->private_data;
ata_host_detach(ah);
gpio_free(info->gpio_line);
@@ -242,9 +242,9 @@
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:" DRV_NAME);
-static struct platform_driver rb500_pata_platform_driver = {
- .probe = rb500_pata_driver_probe,
- .remove = __devexit_p(rb500_pata_driver_remove),
+static struct platform_driver rb532_pata_platform_driver = {
+ .probe = rb532_pata_driver_probe,
+ .remove = __devexit_p(rb532_pata_driver_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
@@ -255,16 +255,16 @@
#define DRV_INFO DRV_DESC " version " DRV_VERSION
-static int __init rb500_pata_module_init(void)
+static int __init rb532_pata_module_init(void)
{
printk(KERN_INFO DRV_INFO "\n");
- return platform_driver_register(&rb500_pata_platform_driver);
+ return platform_driver_register(&rb532_pata_platform_driver);
}
-static void __exit rb500_pata_module_exit(void)
+static void __exit rb532_pata_module_exit(void)
{
- platform_driver_unregister(&rb500_pata_platform_driver);
+ platform_driver_unregister(&rb532_pata_platform_driver);
}
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
@@ -273,5 +273,5 @@
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");
-module_init(rb500_pata_module_init);
-module_exit(rb500_pata_module_exit);
+module_init(rb532_pata_module_init);
+module_exit(rb532_pata_module_exit);
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index d484074..2fea6cb 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -464,11 +464,12 @@
}
pci_dev_put(isa);
- /* 0x40 low bits indicate enabled channels */
- pci_read_config_byte(pdev, 0x40 , &enable);
- enable &= 3;
- if (enable == 0) {
- return -ENODEV;
+ if (!(config->flags & VIA_NO_ENABLES)) {
+ /* 0x40 low bits indicate enabled channels */
+ pci_read_config_byte(pdev, 0x40 , &enable);
+ enable &= 3;
+ if (enable == 0)
+ return -ENODEV;
}
/* Initialise the FIFO for the enabled channels. */
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 26a6337..842b1a15 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -172,10 +172,11 @@
PCIE_IRQ_MASK_OFS = 0x1910,
PCIE_UNMASK_ALL_IRQS = 0x40a, /* assorted bits */
- HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
- HC_MAIN_IRQ_MASK_OFS = 0x1d64,
- HC_SOC_MAIN_IRQ_CAUSE_OFS = 0x20020,
- HC_SOC_MAIN_IRQ_MASK_OFS = 0x20024,
+ /* Host Controller Main Interrupt Cause/Mask registers (1 per-chip) */
+ PCI_HC_MAIN_IRQ_CAUSE_OFS = 0x1d60,
+ PCI_HC_MAIN_IRQ_MASK_OFS = 0x1d64,
+ SOC_HC_MAIN_IRQ_CAUSE_OFS = 0x20020,
+ SOC_HC_MAIN_IRQ_MASK_OFS = 0x20024,
ERR_IRQ = (1 << 0), /* shift by port # */
DONE_IRQ = (1 << 1), /* shift by port # */
HC0_IRQ_PEND = 0x1ff, /* bits 0-8 = HC0's ports */
@@ -445,8 +446,8 @@
const struct mv_hw_ops *ops;
int n_ports;
void __iomem *base;
- void __iomem *main_cause_reg_addr;
- void __iomem *main_mask_reg_addr;
+ void __iomem *main_irq_cause_addr;
+ void __iomem *main_irq_mask_addr;
u32 irq_cause_ofs;
u32 irq_mask_ofs;
u32 unmask_all_irqs;
@@ -727,8 +728,8 @@
* Simple code, with two return values, so macro rather than inline.
*
* port is the sole input, in range 0..7.
- * shift is one output, for use with the main_cause and main_mask registers.
- * hardport is the other output, in range 0..3
+ * shift is one output, for use with main_irq_cause / main_irq_mask registers.
+ * hardport is the other output, in range 0..3.
*
* Note that port and hardport may be the same variable in some cases.
*/
@@ -1679,12 +1680,12 @@
/**
* mv_host_intr - Handle all interrupts on the given host controller
* @host: host specific structure
- * @main_cause: Main interrupt cause register for the chip.
+ * @main_irq_cause: Main interrupt cause register for the chip.
*
* LOCKING:
* Inherited from caller.
*/
-static int mv_host_intr(struct ata_host *host, u32 main_cause)
+static int mv_host_intr(struct ata_host *host, u32 main_irq_cause)
{
struct mv_host_priv *hpriv = host->private_data;
void __iomem *mmio = hpriv->base, *hc_mmio = NULL;
@@ -1705,7 +1706,7 @@
* Do nothing if port is not interrupting or is disabled:
*/
MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
- port_cause = (main_cause >> shift) & (DONE_IRQ | ERR_IRQ);
+ port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ);
if (!port_cause || !ap || (ap->flags & ATA_FLAG_DISABLED))
continue;
/*
@@ -1811,20 +1812,20 @@
struct ata_host *host = dev_instance;
struct mv_host_priv *hpriv = host->private_data;
unsigned int handled = 0;
- u32 main_cause, main_mask;
+ u32 main_irq_cause, main_irq_mask;
spin_lock(&host->lock);
- main_cause = readl(hpriv->main_cause_reg_addr);
- main_mask = readl(hpriv->main_mask_reg_addr);
+ main_irq_cause = readl(hpriv->main_irq_cause_addr);
+ main_irq_mask = readl(hpriv->main_irq_mask_addr);
/*
* Deal with cases where we either have nothing pending, or have read
* a bogus register value which can indicate HW removal or PCI fault.
*/
- if ((main_cause & main_mask) && (main_cause != 0xffffffffU)) {
- if (unlikely((main_cause & PCI_ERR) && HAS_PCI(host)))
+ if ((main_irq_cause & main_irq_mask) && (main_irq_cause != 0xffffffffU)) {
+ if (unlikely((main_irq_cause & PCI_ERR) && HAS_PCI(host)))
handled = mv_pci_error(host, hpriv->base);
else
- handled = mv_host_intr(host, main_cause);
+ handled = mv_host_intr(host, main_irq_cause);
}
spin_unlock(&host->lock);
return IRQ_RETVAL(handled);
@@ -2027,7 +2028,7 @@
ZERO(MV_PCI_DISC_TIMER);
ZERO(MV_PCI_MSI_TRIGGER);
writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
- ZERO(HC_MAIN_IRQ_MASK_OFS);
+ ZERO(PCI_HC_MAIN_IRQ_MASK_OFS);
ZERO(MV_PCI_SERR_MASK);
ZERO(hpriv->irq_cause_ofs);
ZERO(hpriv->irq_mask_ofs);
@@ -2404,7 +2405,7 @@
{
struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int shift, hardport, port = ap->port_no;
- u32 main_mask;
+ u32 main_irq_mask;
/* FIXME: handle coalescing completion events properly */
@@ -2412,9 +2413,9 @@
MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
/* disable assertion of portN err, done events */
- main_mask = readl(hpriv->main_mask_reg_addr);
- main_mask &= ~((DONE_IRQ | ERR_IRQ) << shift);
- writelfl(main_mask, hpriv->main_mask_reg_addr);
+ main_irq_mask = readl(hpriv->main_irq_mask_addr);
+ main_irq_mask &= ~((DONE_IRQ | ERR_IRQ) << shift);
+ writelfl(main_irq_mask, hpriv->main_irq_mask_addr);
}
static void mv_eh_thaw(struct ata_port *ap)
@@ -2423,7 +2424,7 @@
unsigned int shift, hardport, port = ap->port_no;
void __iomem *hc_mmio = mv_hc_base_from_port(hpriv->base, port);
void __iomem *port_mmio = mv_ap_base(ap);
- u32 main_mask, hc_irq_cause;
+ u32 main_irq_mask, hc_irq_cause;
/* FIXME: handle coalescing completion events properly */
@@ -2438,9 +2439,9 @@
writelfl(hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
/* enable assertion of portN err, done events */
- main_mask = readl(hpriv->main_mask_reg_addr);
- main_mask |= ((DONE_IRQ | ERR_IRQ) << shift);
- writelfl(main_mask, hpriv->main_mask_reg_addr);
+ main_irq_mask = readl(hpriv->main_irq_mask_addr);
+ main_irq_mask |= ((DONE_IRQ | ERR_IRQ) << shift);
+ writelfl(main_irq_mask, hpriv->main_irq_mask_addr);
}
/**
@@ -2654,15 +2655,15 @@
goto done;
if (HAS_PCI(host)) {
- hpriv->main_cause_reg_addr = mmio + HC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_mask_reg_addr = mmio + HC_MAIN_IRQ_MASK_OFS;
+ hpriv->main_irq_cause_addr = mmio + PCI_HC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_irq_mask_addr = mmio + PCI_HC_MAIN_IRQ_MASK_OFS;
} else {
- hpriv->main_cause_reg_addr = mmio + HC_SOC_MAIN_IRQ_CAUSE_OFS;
- hpriv->main_mask_reg_addr = mmio + HC_SOC_MAIN_IRQ_MASK_OFS;
+ hpriv->main_irq_cause_addr = mmio + SOC_HC_MAIN_IRQ_CAUSE_OFS;
+ hpriv->main_irq_mask_addr = mmio + SOC_HC_MAIN_IRQ_MASK_OFS;
}
/* global interrupt mask: 0 == mask everything */
- writel(0, hpriv->main_mask_reg_addr);
+ writel(0, hpriv->main_irq_mask_addr);
n_hc = mv_get_hc_count(host->ports[0]->flags);
@@ -2712,23 +2713,23 @@
writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
if (IS_GEN_I(hpriv))
writelfl(~HC_MAIN_MASKED_IRQS_5,
- hpriv->main_mask_reg_addr);
+ hpriv->main_irq_mask_addr);
else
writelfl(~HC_MAIN_MASKED_IRQS,
- hpriv->main_mask_reg_addr);
+ hpriv->main_irq_mask_addr);
VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x "
"PCI int cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_cause_reg_addr),
- readl(hpriv->main_mask_reg_addr),
+ readl(hpriv->main_irq_cause_addr),
+ readl(hpriv->main_irq_mask_addr),
readl(mmio + hpriv->irq_cause_ofs),
readl(mmio + hpriv->irq_mask_ofs));
} else {
writelfl(~HC_MAIN_MASKED_IRQS_SOC,
- hpriv->main_mask_reg_addr);
+ hpriv->main_irq_mask_addr);
VPRINTK("HC MAIN IRQ cause/mask=0x%08x/0x%08x\n",
- readl(hpriv->main_cause_reg_addr),
- readl(hpriv->main_mask_reg_addr));
+ readl(hpriv->main_irq_cause_addr),
+ readl(hpriv->main_irq_mask_addr));
}
done:
return rc;
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 5aa12b0..6adb72a 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -33,6 +33,7 @@
#include <linux/interrupt.h>
#include <linux/poison.h>
#include <linux/bitrev.h>
+#include <linux/mutex.h>
#include <asm/atomic.h>
#include <asm/io.h>
@@ -1177,7 +1178,7 @@
vcc->tx_frame_bits = tx_frame_bits;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
if (dev->rxer[vci]) {
// RXer on the channel already, just modify rate...
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
@@ -1203,7 +1204,7 @@
schedule();
}
dev->txer[vci].tx_present = 1;
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
if (rxtp->traffic_class != ATM_NONE) {
@@ -1211,7 +1212,7 @@
vcc->rx_info.pool = pool;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
/* grow RX buffer pool */
if (!dev->rxq[pool].buffers_wanted)
dev->rxq[pool].buffers_wanted = rx_lats;
@@ -1237,7 +1238,7 @@
schedule();
// this link allows RX frames through
dev->rxer[vci] = atm_vcc;
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
// indicate readiness
@@ -1262,7 +1263,7 @@
if (atm_vcc->qos.txtp.traffic_class != ATM_NONE) {
command cmd;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
if (dev->rxer[vci]) {
// RXer still on the channel, just modify rate... XXX not really needed
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_RATE);
@@ -1277,7 +1278,7 @@
dev->txer[vci].tx_present = 0;
while (command_do (dev, &cmd))
schedule();
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
// disable RXing
@@ -1287,7 +1288,7 @@
// this is (the?) one reason why we need the amb_vcc struct
unsigned char pool = vcc->rx_info.pool;
- down (&dev->vcc_sf);
+ mutex_lock(&dev->vcc_sf);
if (dev->txer[vci].tx_present) {
// TXer still on the channel, just go to pool zero XXX not really needed
cmd.request = cpu_to_be32 (SRB_MODIFY_VC_FLAGS);
@@ -1314,7 +1315,7 @@
dev->rxq[pool].buffers_wanted = 0;
drain_rx_pool (dev, pool);
}
- up (&dev->vcc_sf);
+ mutex_unlock(&dev->vcc_sf);
}
// free our structure
@@ -2188,7 +2189,7 @@
// semaphore for txer/rxer modifications - we cannot use a
// spinlock as the critical region needs to switch processes
- init_MUTEX (&dev->vcc_sf);
+ mutex_init(&dev->vcc_sf);
// queue manipulation spinlocks; we want atomic reads and
// writes to the queue descriptors (handles IRQ and SMP)
// consider replacing "int pending" -> "atomic_t available"
diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h
index ff2a303..df55fa8 100644
--- a/drivers/atm/ambassador.h
+++ b/drivers/atm/ambassador.h
@@ -638,7 +638,7 @@
amb_txq txq;
amb_rxq rxq[NUM_RX_POOLS];
- struct semaphore vcc_sf;
+ struct mutex vcc_sf;
amb_tx_info txer[NUM_VCS];
struct atm_vcc * rxer[NUM_VCS];
unsigned int tx_avail;
diff --git a/drivers/base/base.h b/drivers/base/base.h
index c044414..2c9ae43 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -64,17 +64,6 @@
extern int sysdev_suspend(pm_message_t state);
extern int sysdev_resume(void);
-static inline struct class_device *to_class_dev(struct kobject *obj)
-{
- return container_of(obj, struct class_device, kobj);
-}
-
-static inline
-struct class_device_attribute *to_class_dev_attr(struct attribute *_attr)
-{
- return container_of(_attr, struct class_device_attribute, attr);
-}
-
extern char *make_class_name(const char *name, struct kobject *kobj);
extern int devres_release_all(struct device *dev);
diff --git a/drivers/base/class.c b/drivers/base/class.c
index b490179..0ef00e8 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -179,27 +179,13 @@
kfree(cls);
}
-static void class_device_create_release(struct class_device *class_dev)
-{
- pr_debug("%s called for %s\n", __func__, class_dev->class_id);
- kfree(class_dev);
-}
-
-/* needed to allow these devices to have parent class devices */
-static int class_device_create_uevent(struct class_device *class_dev,
- struct kobj_uevent_env *env)
-{
- pr_debug("%s called for %s\n", __func__, class_dev->class_id);
- return 0;
-}
-
/**
* class_create - create a struct class structure
* @owner: pointer to the module that is to "own" this struct class
* @name: pointer to a string for the name of this class.
*
* This is used to create a struct class pointer that can then be used
- * in calls to class_device_create().
+ * in calls to device_create().
*
* Note, the pointer created here is to be destroyed when finished by
* making a call to class_destroy().
@@ -218,7 +204,6 @@
cls->name = name;
cls->owner = owner;
cls->class_release = class_create_release;
- cls->release = class_device_create_release;
retval = class_register(cls);
if (retval)
@@ -246,113 +231,6 @@
class_unregister(cls);
}
-/* Class Device Stuff */
-
-int class_device_create_file(struct class_device *class_dev,
- const struct class_device_attribute *attr)
-{
- int error = -EINVAL;
- if (class_dev)
- error = sysfs_create_file(&class_dev->kobj, &attr->attr);
- return error;
-}
-
-void class_device_remove_file(struct class_device *class_dev,
- const struct class_device_attribute *attr)
-{
- if (class_dev)
- sysfs_remove_file(&class_dev->kobj, &attr->attr);
-}
-
-int class_device_create_bin_file(struct class_device *class_dev,
- struct bin_attribute *attr)
-{
- int error = -EINVAL;
- if (class_dev)
- error = sysfs_create_bin_file(&class_dev->kobj, attr);
- return error;
-}
-
-void class_device_remove_bin_file(struct class_device *class_dev,
- struct bin_attribute *attr)
-{
- if (class_dev)
- sysfs_remove_bin_file(&class_dev->kobj, attr);
-}
-
-static ssize_t class_device_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
-{
- struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
- struct class_device *cd = to_class_dev(kobj);
- ssize_t ret = 0;
-
- if (class_dev_attr->show)
- ret = class_dev_attr->show(cd, buf);
- return ret;
-}
-
-static ssize_t class_device_attr_store(struct kobject *kobj,
- struct attribute *attr,
- const char *buf, size_t count)
-{
- struct class_device_attribute *class_dev_attr = to_class_dev_attr(attr);
- struct class_device *cd = to_class_dev(kobj);
- ssize_t ret = 0;
-
- if (class_dev_attr->store)
- ret = class_dev_attr->store(cd, buf, count);
- return ret;
-}
-
-static struct sysfs_ops class_dev_sysfs_ops = {
- .show = class_device_attr_show,
- .store = class_device_attr_store,
-};
-
-static void class_dev_release(struct kobject *kobj)
-{
- struct class_device *cd = to_class_dev(kobj);
- struct class *cls = cd->class;
-
- pr_debug("device class '%s': release.\n", cd->class_id);
-
- if (cd->release)
- cd->release(cd);
- else if (cls->release)
- cls->release(cd);
- else {
- printk(KERN_ERR "Class Device '%s' does not have a release() "
- "function, it is broken and must be fixed.\n",
- cd->class_id);
- WARN_ON(1);
- }
-}
-
-static struct kobj_type class_device_ktype = {
- .sysfs_ops = &class_dev_sysfs_ops,
- .release = class_dev_release,
-};
-
-static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
-{
- struct kobj_type *ktype = get_ktype(kobj);
-
- if (ktype == &class_device_ktype) {
- struct class_device *class_dev = to_class_dev(kobj);
- if (class_dev->class)
- return 1;
- }
- return 0;
-}
-
-static const char *class_uevent_name(struct kset *kset, struct kobject *kobj)
-{
- struct class_device *class_dev = to_class_dev(kobj);
-
- return class_dev->class->name;
-}
-
#ifdef CONFIG_SYSFS_DEPRECATED
char *make_class_name(const char *name, struct kobject *kobj)
{
@@ -370,445 +248,8 @@
strcat(class_name, kobject_name(kobj));
return class_name;
}
-
-static int make_deprecated_class_device_links(struct class_device *class_dev)
-{
- char *class_name;
- int error;
-
- if (!class_dev->dev)
- return 0;
-
- class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- if (class_name)
- error = sysfs_create_link(&class_dev->dev->kobj,
- &class_dev->kobj, class_name);
- else
- error = -ENOMEM;
- kfree(class_name);
- return error;
-}
-
-static void remove_deprecated_class_device_links(struct class_device *class_dev)
-{
- char *class_name;
-
- if (!class_dev->dev)
- return;
-
- class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
- if (class_name)
- sysfs_remove_link(&class_dev->dev->kobj, class_name);
- kfree(class_name);
-}
-#else
-static inline int make_deprecated_class_device_links(struct class_device *cd)
-{ return 0; }
-static void remove_deprecated_class_device_links(struct class_device *cd)
-{ }
#endif
-static int class_uevent(struct kset *kset, struct kobject *kobj,
- struct kobj_uevent_env *env)
-{
- struct class_device *class_dev = to_class_dev(kobj);
- struct device *dev = class_dev->dev;
- int retval = 0;
-
- pr_debug("%s - name = %s\n", __func__, class_dev->class_id);
-
- if (MAJOR(class_dev->devt)) {
- add_uevent_var(env, "MAJOR=%u", MAJOR(class_dev->devt));
-
- add_uevent_var(env, "MINOR=%u", MINOR(class_dev->devt));
- }
-
- if (dev) {
- const char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
- if (path) {
- add_uevent_var(env, "PHYSDEVPATH=%s", path);
- kfree(path);
- }
-
- if (dev->bus)
- add_uevent_var(env, "PHYSDEVBUS=%s", dev->bus->name);
-
- if (dev->driver)
- add_uevent_var(env, "PHYSDEVDRIVER=%s",
- dev->driver->name);
- }
-
- if (class_dev->uevent) {
- /* have the class device specific function add its stuff */
- retval = class_dev->uevent(class_dev, env);
- if (retval)
- pr_debug("class_dev->uevent() returned %d\n", retval);
- } else if (class_dev->class->uevent) {
- /* have the class specific function add its stuff */
- retval = class_dev->class->uevent(class_dev, env);
- if (retval)
- pr_debug("class->uevent() returned %d\n", retval);
- }
-
- return retval;
-}
-
-static struct kset_uevent_ops class_uevent_ops = {
- .filter = class_uevent_filter,
- .name = class_uevent_name,
- .uevent = class_uevent,
-};
-
-/*
- * DO NOT copy how this is created, kset_create_and_add() should be
- * called, but this is a hold-over from the old-way and will be deleted
- * entirely soon.
- */
-static struct kset class_obj_subsys = {
- .uevent_ops = &class_uevent_ops,
-};
-
-static int class_device_add_attrs(struct class_device *cd)
-{
- int i;
- int error = 0;
- struct class *cls = cd->class;
-
- if (cls->class_dev_attrs) {
- for (i = 0; attr_name(cls->class_dev_attrs[i]); i++) {
- error = class_device_create_file(cd,
- &cls->class_dev_attrs[i]);
- if (error)
- goto err;
- }
- }
-done:
- return error;
-err:
- while (--i >= 0)
- class_device_remove_file(cd, &cls->class_dev_attrs[i]);
- goto done;
-}
-
-static void class_device_remove_attrs(struct class_device *cd)
-{
- int i;
- struct class *cls = cd->class;
-
- if (cls->class_dev_attrs) {
- for (i = 0; attr_name(cls->class_dev_attrs[i]); i++)
- class_device_remove_file(cd, &cls->class_dev_attrs[i]);
- }
-}
-
-static int class_device_add_groups(struct class_device *cd)
-{
- int i;
- int error = 0;
-
- if (cd->groups) {
- for (i = 0; cd->groups[i]; i++) {
- error = sysfs_create_group(&cd->kobj, cd->groups[i]);
- if (error) {
- while (--i >= 0)
- sysfs_remove_group(&cd->kobj,
- cd->groups[i]);
- goto out;
- }
- }
- }
-out:
- return error;
-}
-
-static void class_device_remove_groups(struct class_device *cd)
-{
- int i;
- if (cd->groups)
- for (i = 0; cd->groups[i]; i++)
- sysfs_remove_group(&cd->kobj, cd->groups[i]);
-}
-
-static ssize_t show_dev(struct class_device *class_dev, char *buf)
-{
- return print_dev_t(buf, class_dev->devt);
-}
-
-static struct class_device_attribute class_devt_attr =
- __ATTR(dev, S_IRUGO, show_dev, NULL);
-
-static ssize_t store_uevent(struct class_device *class_dev,
- const char *buf, size_t count)
-{
- kobject_uevent(&class_dev->kobj, KOBJ_ADD);
- return count;
-}
-
-static struct class_device_attribute class_uevent_attr =
- __ATTR(uevent, S_IWUSR, NULL, store_uevent);
-
-void class_device_initialize(struct class_device *class_dev)
-{
- class_dev->kobj.kset = &class_obj_subsys;
- kobject_init(&class_dev->kobj, &class_device_ktype);
- INIT_LIST_HEAD(&class_dev->node);
-}
-
-int class_device_add(struct class_device *class_dev)
-{
- struct class *parent_class = NULL;
- struct class_device *parent_class_dev = NULL;
- struct class_interface *class_intf;
- int error = -EINVAL;
-
- class_dev = class_device_get(class_dev);
- if (!class_dev)
- return -EINVAL;
-
- if (!strlen(class_dev->class_id))
- goto out1;
-
- parent_class = class_get(class_dev->class);
- if (!parent_class)
- goto out1;
-
- parent_class_dev = class_device_get(class_dev->parent);
-
- pr_debug("CLASS: registering class device: ID = '%s'\n",
- class_dev->class_id);
-
- /* first, register with generic layer. */
- if (parent_class_dev)
- class_dev->kobj.parent = &parent_class_dev->kobj;
- else
- class_dev->kobj.parent = &parent_class->subsys.kobj;
-
- error = kobject_add(&class_dev->kobj, class_dev->kobj.parent,
- "%s", class_dev->class_id);
- if (error)
- goto out2;
-
- /* add the needed attributes to this device */
- error = sysfs_create_link(&class_dev->kobj,
- &parent_class->subsys.kobj, "subsystem");
- if (error)
- goto out3;
-
- error = class_device_create_file(class_dev, &class_uevent_attr);
- if (error)
- goto out3;
-
- if (MAJOR(class_dev->devt)) {
- error = class_device_create_file(class_dev, &class_devt_attr);
- if (error)
- goto out4;
- }
-
- error = class_device_add_attrs(class_dev);
- if (error)
- goto out5;
-
- if (class_dev->dev) {
- error = sysfs_create_link(&class_dev->kobj,
- &class_dev->dev->kobj, "device");
- if (error)
- goto out6;
- }
-
- error = class_device_add_groups(class_dev);
- if (error)
- goto out7;
-
- error = make_deprecated_class_device_links(class_dev);
- if (error)
- goto out8;
-
- kobject_uevent(&class_dev->kobj, KOBJ_ADD);
-
- /* notify any interfaces this device is now here */
- down(&parent_class->sem);
- list_add_tail(&class_dev->node, &parent_class->children);
- list_for_each_entry(class_intf, &parent_class->interfaces, node) {
- if (class_intf->add)
- class_intf->add(class_dev, class_intf);
- }
- up(&parent_class->sem);
-
- goto out1;
-
- out8:
- class_device_remove_groups(class_dev);
- out7:
- if (class_dev->dev)
- sysfs_remove_link(&class_dev->kobj, "device");
- out6:
- class_device_remove_attrs(class_dev);
- out5:
- if (MAJOR(class_dev->devt))
- class_device_remove_file(class_dev, &class_devt_attr);
- out4:
- class_device_remove_file(class_dev, &class_uevent_attr);
- out3:
- kobject_del(&class_dev->kobj);
- out2:
- if (parent_class_dev)
- class_device_put(parent_class_dev);
- class_put(parent_class);
- out1:
- class_device_put(class_dev);
- return error;
-}
-
-int class_device_register(struct class_device *class_dev)
-{
- class_device_initialize(class_dev);
- return class_device_add(class_dev);
-}
-
-/**
- * class_device_create - creates a class device and registers it with sysfs
- * @cls: pointer to the struct class that this device should be registered to.
- * @parent: pointer to the parent struct class_device of this new device, if
- * any.
- * @devt: the dev_t for the char device to be added.
- * @device: a pointer to a struct device that is assiociated with this class
- * device.
- * @fmt: string for the class device's name
- *
- * This function can be used by char device classes. A struct
- * class_device will be created in sysfs, registered to the specified
- * class.
- * A "dev" file will be created, showing the dev_t for the device, if
- * the dev_t is not 0,0.
- * If a pointer to a parent struct class_device is passed in, the newly
- * created struct class_device will be a child of that device in sysfs.
- * The pointer to the struct class_device will be returned from the
- * call. Any further sysfs files that might be required can be created
- * using this pointer.
- *
- * Note: the struct class passed to this function must have previously
- * been created with a call to class_create().
- */
-struct class_device *class_device_create(struct class *cls,
- struct class_device *parent,
- dev_t devt,
- struct device *device,
- const char *fmt, ...)
-{
- va_list args;
- struct class_device *class_dev = NULL;
- int retval = -ENODEV;
-
- if (cls == NULL || IS_ERR(cls))
- goto error;
-
- class_dev = kzalloc(sizeof(*class_dev), GFP_KERNEL);
- if (!class_dev) {
- retval = -ENOMEM;
- goto error;
- }
-
- class_dev->devt = devt;
- class_dev->dev = device;
- class_dev->class = cls;
- class_dev->parent = parent;
- class_dev->release = class_device_create_release;
- class_dev->uevent = class_device_create_uevent;
-
- va_start(args, fmt);
- vsnprintf(class_dev->class_id, BUS_ID_SIZE, fmt, args);
- va_end(args);
- retval = class_device_register(class_dev);
- if (retval)
- goto error;
-
- return class_dev;
-
-error:
- kfree(class_dev);
- return ERR_PTR(retval);
-}
-
-void class_device_del(struct class_device *class_dev)
-{
- struct class *parent_class = class_dev->class;
- struct class_device *parent_device = class_dev->parent;
- struct class_interface *class_intf;
-
- if (parent_class) {
- down(&parent_class->sem);
- list_del_init(&class_dev->node);
- list_for_each_entry(class_intf, &parent_class->interfaces, node)
- if (class_intf->remove)
- class_intf->remove(class_dev, class_intf);
- up(&parent_class->sem);
- }
-
- if (class_dev->dev) {
- remove_deprecated_class_device_links(class_dev);
- sysfs_remove_link(&class_dev->kobj, "device");
- }
- sysfs_remove_link(&class_dev->kobj, "subsystem");
- class_device_remove_file(class_dev, &class_uevent_attr);
- if (MAJOR(class_dev->devt))
- class_device_remove_file(class_dev, &class_devt_attr);
- class_device_remove_attrs(class_dev);
- class_device_remove_groups(class_dev);
-
- kobject_uevent(&class_dev->kobj, KOBJ_REMOVE);
- kobject_del(&class_dev->kobj);
-
- class_device_put(parent_device);
- class_put(parent_class);
-}
-
-void class_device_unregister(struct class_device *class_dev)
-{
- pr_debug("CLASS: Unregistering class device. ID = '%s'\n",
- class_dev->class_id);
- class_device_del(class_dev);
- class_device_put(class_dev);
-}
-
-/**
- * class_device_destroy - removes a class device that was created with class_device_create()
- * @cls: the pointer to the struct class that this device was registered * with.
- * @devt: the dev_t of the device that was previously registered.
- *
- * This call unregisters and cleans up a class device that was created with a
- * call to class_device_create()
- */
-void class_device_destroy(struct class *cls, dev_t devt)
-{
- struct class_device *class_dev = NULL;
- struct class_device *class_dev_tmp;
-
- down(&cls->sem);
- list_for_each_entry(class_dev_tmp, &cls->children, node) {
- if (class_dev_tmp->devt == devt) {
- class_dev = class_dev_tmp;
- break;
- }
- }
- up(&cls->sem);
-
- if (class_dev)
- class_device_unregister(class_dev);
-}
-
-struct class_device *class_device_get(struct class_device *class_dev)
-{
- if (class_dev)
- return to_class_dev(kobject_get(&class_dev->kobj));
- return NULL;
-}
-
-void class_device_put(struct class_device *class_dev)
-{
- if (class_dev)
- kobject_put(&class_dev->kobj);
-}
-
/**
* class_for_each_device - device iterator
* @class: the class we're iterating
@@ -897,56 +338,9 @@
}
EXPORT_SYMBOL_GPL(class_find_device);
-/**
- * class_find_child - device iterator for locating a particular class_device
- * @class: the class we're iterating
- * @data: data for the match function
- * @match: function to check class_device
- *
- * This function returns a reference to a class_device that is 'found' for
- * later use, as determined by the @match callback.
- *
- * The callback should return 0 if the class_device doesn't match and non-zero
- * if it does. If the callback returns non-zero, this function will
- * return to the caller and not iterate over any more class_devices.
- *
- * Note, you will need to drop the reference with class_device_put() after use.
- *
- * We hold class->sem in this function, so it can not be
- * re-acquired in @match, otherwise it will self-deadlocking. For
- * example, calls to add or remove class members would be verboten.
- */
-struct class_device *class_find_child(struct class *class, void *data,
- int (*match)(struct class_device *, void *))
-{
- struct class_device *dev;
- int found = 0;
-
- if (!class)
- return NULL;
-
- down(&class->sem);
- list_for_each_entry(dev, &class->children, node) {
- dev = class_device_get(dev);
- if (dev) {
- if (match(dev, data)) {
- found = 1;
- break;
- } else
- class_device_put(dev);
- } else
- break;
- }
- up(&class->sem);
-
- return found ? dev : NULL;
-}
-EXPORT_SYMBOL_GPL(class_find_child);
-
int class_interface_register(struct class_interface *class_intf)
{
struct class *parent;
- struct class_device *class_dev;
struct device *dev;
if (!class_intf || !class_intf->class)
@@ -958,10 +352,6 @@
down(&parent->sem);
list_add_tail(&class_intf->node, &parent->interfaces);
- if (class_intf->add) {
- list_for_each_entry(class_dev, &parent->children, node)
- class_intf->add(class_dev, class_intf);
- }
if (class_intf->add_dev) {
list_for_each_entry(dev, &parent->devices, node)
class_intf->add_dev(dev, class_intf);
@@ -974,7 +364,6 @@
void class_interface_unregister(struct class_interface *class_intf)
{
struct class *parent = class_intf->class;
- struct class_device *class_dev;
struct device *dev;
if (!parent)
@@ -982,10 +371,6 @@
down(&parent->sem);
list_del_init(&class_intf->node);
- if (class_intf->remove) {
- list_for_each_entry(class_dev, &parent->children, node)
- class_intf->remove(class_dev, class_intf);
- }
if (class_intf->remove_dev) {
list_for_each_entry(dev, &parent->devices, node)
class_intf->remove_dev(dev, class_intf);
@@ -1000,13 +385,6 @@
class_kset = kset_create_and_add("class", NULL, NULL);
if (!class_kset)
return -ENOMEM;
-
- /* ick, this is ugly, the things we go through to keep from showing up
- * in sysfs... */
- kset_init(&class_obj_subsys);
- kobject_set_name(&class_obj_subsys.kobj, "class_obj");
- if (!class_obj_subsys.kobj.parent)
- class_obj_subsys.kobj.parent = &class_obj_subsys.kobj;
return 0;
}
@@ -1017,19 +395,5 @@
EXPORT_SYMBOL_GPL(class_create);
EXPORT_SYMBOL_GPL(class_destroy);
-EXPORT_SYMBOL_GPL(class_device_register);
-EXPORT_SYMBOL_GPL(class_device_unregister);
-EXPORT_SYMBOL_GPL(class_device_initialize);
-EXPORT_SYMBOL_GPL(class_device_add);
-EXPORT_SYMBOL_GPL(class_device_del);
-EXPORT_SYMBOL_GPL(class_device_get);
-EXPORT_SYMBOL_GPL(class_device_put);
-EXPORT_SYMBOL_GPL(class_device_create);
-EXPORT_SYMBOL_GPL(class_device_destroy);
-EXPORT_SYMBOL_GPL(class_device_create_file);
-EXPORT_SYMBOL_GPL(class_device_remove_file);
-EXPORT_SYMBOL_GPL(class_device_create_bin_file);
-EXPORT_SYMBOL_GPL(class_device_remove_bin_file);
-
EXPORT_SYMBOL_GPL(class_interface_register);
EXPORT_SYMBOL_GPL(class_interface_unregister);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 9248e09..be288b5 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -787,6 +787,10 @@
parent = get_device(dev->parent);
setup_parent(dev, parent);
+ /* use parent numa_node */
+ if (parent)
+ set_dev_node(dev, dev_to_node(parent));
+
/* first, register with generic layer. */
error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id);
if (error)
@@ -1306,8 +1310,11 @@
dev->parent = new_parent;
if (old_parent)
klist_remove(&dev->knode_parent);
- if (new_parent)
+ if (new_parent) {
klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+ set_dev_node(dev, dev_to_node(new_parent));
+ }
+
if (!dev->class)
goto out_put;
error = device_move_class_links(dev, old_parent, new_parent);
@@ -1317,9 +1324,12 @@
if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
if (new_parent)
klist_remove(&dev->knode_parent);
- if (old_parent)
+ dev->parent = old_parent;
+ if (old_parent) {
klist_add_tail(&dev->knode_parent,
&old_parent->klist_children);
+ set_dev_node(dev, dev_to_node(old_parent));
+ }
}
cleanup_glue_dir(dev, new_parent_kobj);
put_device(new_parent);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 6fe4174..e38dfed 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -18,7 +18,7 @@
};
EXPORT_SYMBOL(cpu_sysdev_class);
-static struct sys_device *cpu_sys_devices[NR_CPUS];
+static DEFINE_PER_CPU(struct sys_device *, cpu_sys_devices);
#ifdef CONFIG_HOTPLUG_CPU
static ssize_t show_online(struct sys_device *dev, char *buf)
@@ -68,7 +68,7 @@
sysdev_remove_file(&cpu->sysdev, &attr_online);
sysdev_unregister(&cpu->sysdev);
- cpu_sys_devices[logical_cpu] = NULL;
+ per_cpu(cpu_sys_devices, logical_cpu) = NULL;
return;
}
#else /* ... !CONFIG_HOTPLUG_CPU */
@@ -167,7 +167,7 @@
if (!error && cpu->hotpluggable)
register_cpu_control(cpu);
if (!error)
- cpu_sys_devices[num] = &cpu->sysdev;
+ per_cpu(cpu_sys_devices, num) = &cpu->sysdev;
if (!error)
register_cpu_under_node(num, cpu_to_node(num));
@@ -180,8 +180,8 @@
struct sys_device *get_cpu_sysdev(unsigned cpu)
{
- if (cpu < NR_CPUS)
- return cpu_sys_devices[cpu];
+ if (cpu < nr_cpu_ids && cpu_possible(cpu))
+ return per_cpu(cpu_sys_devices, cpu);
else
return NULL;
}
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 9a6537f..2ef5acf 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -217,12 +217,22 @@
int driver_register(struct device_driver *drv)
{
int ret;
+ struct device_driver *other;
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
+
+ other = driver_find(drv->name, drv->bus);
+ if (other) {
+ put_driver(other);
+ printk(KERN_ERR "Error: Driver '%s' is already registered, "
+ "aborting...\n", drv->name);
+ return -EEXIST;
+ }
+
ret = bus_add_driver(drv);
if (ret)
return ret;
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 1fef7df..9fd4a85 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -396,6 +396,8 @@
if (!firmware_p)
return -EINVAL;
+ printk(KERN_INFO "firmware: requesting %s\n", name);
+
*firmware_p = firmware = kzalloc(sizeof(*firmware), GFP_KERNEL);
if (!firmware) {
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
diff --git a/drivers/base/node.c b/drivers/base/node.c
index 12fde2d..39f3d1b 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -77,6 +77,7 @@
"Node %d PageTables: %8lu kB\n"
"Node %d NFS_Unstable: %8lu kB\n"
"Node %d Bounce: %8lu kB\n"
+ "Node %d WritebackTmp: %8lu kB\n"
"Node %d Slab: %8lu kB\n"
"Node %d SReclaimable: %8lu kB\n"
"Node %d SUnreclaim: %8lu kB\n",
@@ -99,6 +100,7 @@
nid, K(node_page_state(nid, NR_PAGETABLE)),
nid, K(node_page_state(nid, NR_UNSTABLE_NFS)),
nid, K(node_page_state(nid, NR_BOUNCE)),
+ nid, K(node_page_state(nid, NR_WRITEBACK_TEMP)),
nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE) +
node_page_state(nid, NR_SLAB_UNRECLAIMABLE)),
nid, K(node_page_state(nid, NR_SLAB_RECLAIMABLE)),
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 280e71e..5b4c6e6 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -195,7 +195,6 @@
struct aoedev *aoedev_by_aoeaddr(int maj, int min);
struct aoedev *aoedev_by_sysminor_m(ulong sysminor);
void aoedev_downdev(struct aoedev *d);
-int aoedev_isbusy(struct aoedev *d);
int aoedev_flush(const char __user *str, size_t size);
int aoenet_init(void);
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index d00293b..8fc429c 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -668,16 +668,16 @@
u16 n;
/* word 83: command set supported */
- n = le16_to_cpu(get_unaligned((__le16 *) &id[83<<1]));
+ n = get_unaligned_le16(&id[83 << 1]);
/* word 86: command set/feature enabled */
- n |= le16_to_cpu(get_unaligned((__le16 *) &id[86<<1]));
+ n |= get_unaligned_le16(&id[86 << 1]);
if (n & (1<<10)) { /* bit 10: LBA 48 */
d->flags |= DEVFL_EXT;
/* word 100: number lba48 sectors */
- ssize = le64_to_cpu(get_unaligned((__le64 *) &id[100<<1]));
+ ssize = get_unaligned_le64(&id[100 << 1]);
/* set as in ide-disk.c:init_idedisk_capacity */
d->geo.cylinders = ssize;
@@ -688,12 +688,12 @@
d->flags &= ~DEVFL_EXT;
/* number lba28 sectors */
- ssize = le32_to_cpu(get_unaligned((__le32 *) &id[60<<1]));
+ ssize = get_unaligned_le32(&id[60 << 1]);
/* NOTE: obsolete in ATA 6 */
- d->geo.cylinders = le16_to_cpu(get_unaligned((__le16 *) &id[54<<1]));
- d->geo.heads = le16_to_cpu(get_unaligned((__le16 *) &id[55<<1]));
- d->geo.sectors = le16_to_cpu(get_unaligned((__le16 *) &id[56<<1]));
+ d->geo.cylinders = get_unaligned_le16(&id[54 << 1]);
+ d->geo.heads = get_unaligned_le16(&id[55 << 1]);
+ d->geo.sectors = get_unaligned_le16(&id[56 << 1]);
}
if (d->ssize != ssize)
@@ -779,7 +779,7 @@
u16 aoemajor;
hin = (struct aoe_hdr *) skb_mac_header(skb);
- aoemajor = be16_to_cpu(get_unaligned(&hin->major));
+ aoemajor = get_unaligned_be16(&hin->major);
d = aoedev_by_aoeaddr(aoemajor, hin->minor);
if (d == NULL) {
snprintf(ebuf, sizeof ebuf, "aoecmd_ata_rsp: ata response "
@@ -791,7 +791,7 @@
spin_lock_irqsave(&d->lock, flags);
- n = be32_to_cpu(get_unaligned(&hin->tag));
+ n = get_unaligned_be32(&hin->tag);
t = gettgt(d, hin->src);
if (t == NULL) {
printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n",
@@ -806,9 +806,9 @@
snprintf(ebuf, sizeof ebuf,
"%15s e%d.%d tag=%08x@%08lx\n",
"unexpected rsp",
- be16_to_cpu(get_unaligned(&hin->major)),
+ get_unaligned_be16(&hin->major),
hin->minor,
- be32_to_cpu(get_unaligned(&hin->tag)),
+ get_unaligned_be32(&hin->tag),
jiffies);
aoechr_error(ebuf);
return;
@@ -873,7 +873,7 @@
printk(KERN_INFO
"aoe: unrecognized ata command %2.2Xh for %d.%d\n",
ahout->cmdstat,
- be16_to_cpu(get_unaligned(&hin->major)),
+ get_unaligned_be16(&hin->major),
hin->minor);
}
}
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index f9a1cd9..a1d813a 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -18,24 +18,6 @@
static struct aoedev *devlist;
static DEFINE_SPINLOCK(devlist_lock);
-int
-aoedev_isbusy(struct aoedev *d)
-{
- struct aoetgt **t, **te;
- struct frame *f, *e;
-
- t = d->targets;
- te = t + NTARGETS;
- for (; t < te && *t; t++) {
- f = (*t)->frames;
- e = f + (*t)->nframes;
- for (; f < e; f++)
- if (f->tag != FREETAG)
- return 1;
- }
- return 0;
-}
-
struct aoedev *
aoedev_by_aoeaddr(int maj, int min)
{
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index 18d243c..d625169 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -128,7 +128,7 @@
skb_push(skb, ETH_HLEN); /* (1) */
h = (struct aoe_hdr *) skb_mac_header(skb);
- n = be32_to_cpu(get_unaligned(&h->tag));
+ n = get_unaligned_be32(&h->tag);
if ((h->verfl & AOEFL_RSP) == 0 || (n & 1<<31))
goto exit;
@@ -140,7 +140,7 @@
printk(KERN_ERR
"%s%d.%d@%s; ecode=%d '%s'\n",
"aoe: error packet from ",
- be16_to_cpu(get_unaligned(&h->major)),
+ get_unaligned_be16(&h->major),
h->minor, skb->dev->name,
h->err, aoe_errlist[n]);
goto exit;
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index e8e38fa..a196ef7 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -387,10 +387,14 @@
*/
static int rd_nr;
int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
+static int max_part;
+static int part_shift;
module_param(rd_nr, int, 0);
MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices");
module_param(rd_size, int, 0);
MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
+module_param(max_part, int, 0);
+MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk");
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
@@ -435,11 +439,11 @@
blk_queue_max_sectors(brd->brd_queue, 1024);
blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
- disk = brd->brd_disk = alloc_disk(1);
+ disk = brd->brd_disk = alloc_disk(1 << part_shift);
if (!disk)
goto out_free_queue;
disk->major = RAMDISK_MAJOR;
- disk->first_minor = i;
+ disk->first_minor = i << part_shift;
disk->fops = &brd_fops;
disk->private_data = brd;
disk->queue = brd->brd_queue;
@@ -523,7 +527,12 @@
* themselves and have kernel automatically instantiate actual
* device on-demand.
*/
- if (rd_nr > 1UL << MINORBITS)
+
+ part_shift = 0;
+ if (max_part > 0)
+ part_shift = fls(max_part);
+
+ if (rd_nr > 1UL << (MINORBITS - part_shift))
return -EINVAL;
if (rd_nr) {
@@ -531,7 +540,7 @@
range = rd_nr;
} else {
nr = CONFIG_BLK_DEV_RAM_COUNT;
- range = 1UL << MINORBITS;
+ range = 1UL << (MINORBITS - part_shift);
}
if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
@@ -570,7 +579,7 @@
unsigned long range;
struct brd_device *brd, *next;
- range = rd_nr ? rd_nr : 1UL << MINORBITS;
+ range = rd_nr ? rd_nr : 1UL << (MINORBITS - part_shift);
list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
brd_del_one(brd);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index cf6083a..e336b05 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -425,16 +425,12 @@
struct proc_dir_entry *pde;
if (proc_cciss == NULL)
- proc_cciss = proc_mkdir("cciss", proc_root_driver);
+ proc_cciss = proc_mkdir("driver/cciss", NULL);
if (!proc_cciss)
return;
- pde = proc_create(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP |
+ pde = proc_create_data(hba[i]->devname, S_IWUSR | S_IRUSR | S_IRGRP |
S_IROTH, proc_cciss,
- &cciss_proc_fops);
- if (!pde)
- return;
-
- pde->data = hba[i];
+ &cciss_proc_fops, hba[i]);
}
#endif /* CONFIG_PROC_FS */
@@ -3700,7 +3696,7 @@
cciss_remove_one(hba[i]->pdev);
}
}
- remove_proc_entry("cciss", proc_root_driver);
+ remove_proc_entry("driver/cciss", NULL);
}
static void fail_all_cmds(unsigned long ctlr)
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 6919918..09c1434 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -214,7 +214,7 @@
static void __init ida_procinit(int i)
{
if (proc_array == NULL) {
- proc_array = proc_mkdir("cpqarray", proc_root_driver);
+ proc_array = proc_mkdir("driver/cpqarray", NULL);
if (!proc_array) return;
}
@@ -1796,7 +1796,7 @@
}
}
- remove_proc_entry("cpqarray", proc_root_driver);
+ remove_proc_entry("driver/cpqarray", NULL);
}
module_init(cpqarray_init)
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 7652e87d..395f8ea 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4526,14 +4526,15 @@
}
}
-int __init init_module(void)
+static int __init floppy_module_init(void)
{
if (floppy)
parse_floppy_cfg_string(floppy);
return floppy_init();
}
+module_init(floppy_module_init);
-void cleanup_module(void)
+static void __exit floppy_module_exit(void)
{
int drive;
@@ -4562,6 +4563,7 @@
/* eject disk, if any */
fd_eject(0);
}
+module_exit(floppy_module_exit);
module_param(floppy, charp, 0);
module_param(FLOPPY_IRQ, int, 0);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index f7f1635..d3a25b0 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -546,7 +546,7 @@
{
struct loop_device *lo = q->queuedata;
- clear_bit(QUEUE_FLAG_PLUGGED, &q->queue_flags);
+ queue_flag_clear_unlocked(QUEUE_FLAG_PLUGGED, q);
blk_run_address_space(lo->lo_backing_file->f_mapping);
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index 60cc543..ad98dda 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -29,6 +29,7 @@
#include <linux/kernel.h>
#include <net/sock.h>
#include <linux/net.h>
+#include <linux/kthread.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -55,6 +56,7 @@
static unsigned int nbds_max = 16;
static struct nbd_device *nbd_dev;
+static int max_part;
/*
* Use just one lock (or at most 1 per NIC). Two arguments for this:
@@ -337,7 +339,7 @@
}
req = nbd_find_request(lo, *(struct request **)reply.handle);
- if (unlikely(IS_ERR(req))) {
+ if (IS_ERR(req)) {
result = PTR_ERR(req);
if (result != -ENOENT)
goto harderror;
@@ -441,6 +443,85 @@
}
+static void nbd_handle_req(struct nbd_device *lo, struct request *req)
+{
+ if (!blk_fs_request(req))
+ goto error_out;
+
+ nbd_cmd(req) = NBD_CMD_READ;
+ if (rq_data_dir(req) == WRITE) {
+ nbd_cmd(req) = NBD_CMD_WRITE;
+ if (lo->flags & NBD_READ_ONLY) {
+ printk(KERN_ERR "%s: Write on read-only\n",
+ lo->disk->disk_name);
+ goto error_out;
+ }
+ }
+
+ req->errors = 0;
+
+ mutex_lock(&lo->tx_lock);
+ if (unlikely(!lo->sock)) {
+ mutex_unlock(&lo->tx_lock);
+ printk(KERN_ERR "%s: Attempted send on closed socket\n",
+ lo->disk->disk_name);
+ req->errors++;
+ nbd_end_request(req);
+ return;
+ }
+
+ lo->active_req = req;
+
+ if (nbd_send_req(lo, req) != 0) {
+ printk(KERN_ERR "%s: Request send failed\n",
+ lo->disk->disk_name);
+ req->errors++;
+ nbd_end_request(req);
+ } else {
+ spin_lock(&lo->queue_lock);
+ list_add(&req->queuelist, &lo->queue_head);
+ spin_unlock(&lo->queue_lock);
+ }
+
+ lo->active_req = NULL;
+ mutex_unlock(&lo->tx_lock);
+ wake_up_all(&lo->active_wq);
+
+ return;
+
+error_out:
+ req->errors++;
+ nbd_end_request(req);
+}
+
+static int nbd_thread(void *data)
+{
+ struct nbd_device *lo = data;
+ struct request *req;
+
+ set_user_nice(current, -20);
+ while (!kthread_should_stop() || !list_empty(&lo->waiting_queue)) {
+ /* wait for something to do */
+ wait_event_interruptible(lo->waiting_wq,
+ kthread_should_stop() ||
+ !list_empty(&lo->waiting_queue));
+
+ /* extract request */
+ if (list_empty(&lo->waiting_queue))
+ continue;
+
+ spin_lock_irq(&lo->queue_lock);
+ req = list_entry(lo->waiting_queue.next, struct request,
+ queuelist);
+ list_del_init(&req->queuelist);
+ spin_unlock_irq(&lo->queue_lock);
+
+ /* handle request */
+ nbd_handle_req(lo, req);
+ }
+ return 0;
+}
+
/*
* We always wait for result of write, for now. It would be nice to make it optional
* in future
@@ -456,65 +537,23 @@
struct nbd_device *lo;
blkdev_dequeue_request(req);
+
+ spin_unlock_irq(q->queue_lock);
+
dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
req->rq_disk->disk_name, req, req->cmd_type);
- if (!blk_fs_request(req))
- goto error_out;
-
lo = req->rq_disk->private_data;
BUG_ON(lo->magic != LO_MAGIC);
- nbd_cmd(req) = NBD_CMD_READ;
- if (rq_data_dir(req) == WRITE) {
- nbd_cmd(req) = NBD_CMD_WRITE;
- if (lo->flags & NBD_READ_ONLY) {
- printk(KERN_ERR "%s: Write on read-only\n",
- lo->disk->disk_name);
- goto error_out;
- }
- }
+ spin_lock_irq(&lo->queue_lock);
+ list_add_tail(&req->queuelist, &lo->waiting_queue);
+ spin_unlock_irq(&lo->queue_lock);
- req->errors = 0;
- spin_unlock_irq(q->queue_lock);
-
- mutex_lock(&lo->tx_lock);
- if (unlikely(!lo->sock)) {
- mutex_unlock(&lo->tx_lock);
- printk(KERN_ERR "%s: Attempted send on closed socket\n",
- lo->disk->disk_name);
- req->errors++;
- nbd_end_request(req);
- spin_lock_irq(q->queue_lock);
- continue;
- }
-
- lo->active_req = req;
-
- if (nbd_send_req(lo, req) != 0) {
- printk(KERN_ERR "%s: Request send failed\n",
- lo->disk->disk_name);
- req->errors++;
- nbd_end_request(req);
- } else {
- spin_lock(&lo->queue_lock);
- list_add(&req->queuelist, &lo->queue_head);
- spin_unlock(&lo->queue_lock);
- }
-
- lo->active_req = NULL;
- mutex_unlock(&lo->tx_lock);
- wake_up_all(&lo->active_wq);
+ wake_up(&lo->waiting_wq);
spin_lock_irq(q->queue_lock);
- continue;
-
-error_out:
- req->errors++;
- spin_unlock(q->queue_lock);
- nbd_end_request(req);
- spin_lock(q->queue_lock);
}
}
@@ -524,6 +563,7 @@
struct nbd_device *lo = inode->i_bdev->bd_disk->private_data;
int error;
struct request sreq ;
+ struct task_struct *thread;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -537,6 +577,7 @@
switch (cmd) {
case NBD_DISCONNECT:
printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
+ blk_rq_init(NULL, &sreq);
sreq.cmd_type = REQ_TYPE_SPECIAL;
nbd_cmd(&sreq) = NBD_CMD_DISC;
/*
@@ -571,10 +612,13 @@
error = -EINVAL;
file = fget(arg);
if (file) {
+ struct block_device *bdev = inode->i_bdev;
inode = file->f_path.dentry->d_inode;
if (S_ISSOCK(inode->i_mode)) {
lo->file = file;
lo->sock = SOCKET_I(inode);
+ if (max_part > 0)
+ bdev->bd_invalidated = 1;
error = 0;
} else {
fput(file);
@@ -606,7 +650,12 @@
case NBD_DO_IT:
if (!lo->file)
return -EINVAL;
+ thread = kthread_create(nbd_thread, lo, lo->disk->disk_name);
+ if (IS_ERR(thread))
+ return PTR_ERR(thread);
+ wake_up_process(thread);
error = nbd_do_it(lo);
+ kthread_stop(thread);
if (error)
return error;
sock_shutdown(lo, 1);
@@ -619,6 +668,8 @@
lo->bytesize = 0;
inode->i_bdev->bd_inode->i_size = 0;
set_capacity(lo->disk, 0);
+ if (max_part > 0)
+ ioctl_by_bdev(inode->i_bdev, BLKRRPART, 0);
return lo->harderror;
case NBD_CLEAR_QUE:
/*
@@ -652,6 +703,7 @@
{
int err = -ENOMEM;
int i;
+ int part_shift;
BUILD_BUG_ON(sizeof(struct nbd_request) != 28);
@@ -659,8 +711,17 @@
if (!nbd_dev)
return -ENOMEM;
+ if (max_part < 0) {
+ printk(KERN_CRIT "nbd: max_part must be >= 0\n");
+ return -EINVAL;
+ }
+
+ part_shift = 0;
+ if (max_part > 0)
+ part_shift = fls(max_part);
+
for (i = 0; i < nbds_max; i++) {
- struct gendisk *disk = alloc_disk(1);
+ struct gendisk *disk = alloc_disk(1 << part_shift);
elevator_t *old_e;
if (!disk)
goto out;
@@ -695,17 +756,18 @@
nbd_dev[i].file = NULL;
nbd_dev[i].magic = LO_MAGIC;
nbd_dev[i].flags = 0;
+ INIT_LIST_HEAD(&nbd_dev[i].waiting_queue);
spin_lock_init(&nbd_dev[i].queue_lock);
INIT_LIST_HEAD(&nbd_dev[i].queue_head);
mutex_init(&nbd_dev[i].tx_lock);
init_waitqueue_head(&nbd_dev[i].active_wq);
+ init_waitqueue_head(&nbd_dev[i].waiting_wq);
nbd_dev[i].blksize = 1024;
nbd_dev[i].bytesize = 0;
disk->major = NBD_MAJOR;
- disk->first_minor = i;
+ disk->first_minor = i << part_shift;
disk->fops = &nbd_fops;
disk->private_data = &nbd_dev[i];
- disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
sprintf(disk->disk_name, "nbd%d", i);
set_capacity(disk, 0);
add_disk(disk);
@@ -743,7 +805,9 @@
MODULE_LICENSE("GPL");
module_param(nbds_max, int, 0444);
-MODULE_PARM_DESC(nbds_max, "How many network block devices to initialize.");
+MODULE_PARM_DESC(nbds_max, "number of network block devices to initialize (default: 16)");
+module_param(max_part, int, 0444);
+MODULE_PARM_DESC(max_part, "number of partitions per device (default: 0)");
#ifndef NDEBUG
module_param(debugflags, int, 0644);
MODULE_PARM_DESC(debugflags, "flags for controlling debug output");
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index df819f8..570f3b7 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -716,10 +716,8 @@
struct request rq;
int err = 0;
- memset(&rq, 0, sizeof(rq));
- rq.errors = 0;
+ blk_rq_init(NULL, &rq);
rq.rq_disk = disk->gd;
- rq.ref_count = 1;
rq.end_io_data = &wait;
rq.end_io = blk_end_sync_rq;
blk_insert_request(disk->gd->queue, &rq, 0, func);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 18feb1c..3ba1df9 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -776,8 +776,6 @@
rq->cmd_len = COMMAND_SIZE(cgc->cmd[0]);
memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
- if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
- memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
rq->timeout = 60*HZ;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
@@ -2744,7 +2742,6 @@
int i;
int ret = 0;
char b[BDEVNAME_SIZE];
- struct proc_dir_entry *proc;
struct block_device *bdev;
if (pd->pkt_dev == dev) {
@@ -2788,11 +2785,7 @@
goto out_mem;
}
- proc = create_proc_entry(pd->name, 0, pkt_proc);
- if (proc) {
- proc->data = pd;
- proc->proc_fops = &pkt_proc_fops;
- }
+ proc_create_data(pd->name, 0, pkt_proc, &pkt_proc_fops, pd);
DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
return 0;
@@ -3101,7 +3094,7 @@
goto out_misc;
}
- pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver);
+ pkt_proc = proc_mkdir("driver/"DRIVER_NAME, NULL);
return 0;
@@ -3117,7 +3110,7 @@
static void __exit pkt_exit(void)
{
- remove_proc_entry(DRIVER_NAME, proc_root_driver);
+ remove_proc_entry("driver/"DRIVER_NAME, NULL);
misc_deregister(&pkt_misc);
pkt_debugfs_cleanup();
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c
index 7483f94..d797e20 100644
--- a/drivers/block/ps3disk.c
+++ b/drivers/block/ps3disk.c
@@ -102,8 +102,7 @@
dev_dbg(&dev->sbd.core,
"%s:%u: bio %u: %u segs %u sectors from %lu\n",
__func__, __LINE__, i, bio_segments(iter.bio),
- bio_sectors(iter.bio),
- (unsigned long)iter.bio->bi_sector);
+ bio_sectors(iter.bio), iter.bio->bi_sector);
size = bvec->bv_len;
buf = bvec_kmap_irq(bvec, &flags);
@@ -406,7 +405,6 @@
dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
- memset(req->cmd, 0, sizeof(req->cmd));
req->cmd_type = REQ_TYPE_FLUSH;
}
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index 27bfe72..3a281ef 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -205,6 +205,7 @@
unsigned char key, asc, ascq; /* May be valid if error==-EIO */
int stat_count; /* Retries getting status. */
+ unsigned int timeo; /* jiffies until rq->timeout changes */
unsigned int len; /* Requested length */
unsigned int current_sg;
@@ -318,6 +319,7 @@
int openc; /* protected by ub_lock! */
/* kref is too implicit for our taste */
int reset; /* Reset is running */
+ int bad_resid;
unsigned int tagcnt;
char name[12];
struct usb_device *dev;
@@ -764,6 +766,12 @@
cmd->cdb_len = rq->cmd_len;
cmd->len = rq->data_len;
+
+ /*
+ * To reapply this to every URB is not as incorrect as it looks.
+ * In return, we avoid any complicated tracking calculations.
+ */
+ cmd->timeo = rq->timeout;
}
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
@@ -785,10 +793,6 @@
scsi_status = 0;
} else {
if (cmd->act_len != cmd->len) {
- if ((cmd->key == MEDIUM_ERROR ||
- cmd->key == UNIT_ATTENTION) &&
- ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
- return;
scsi_status = SAM_STAT_CHECK_CONDITION;
} else {
scsi_status = 0;
@@ -804,7 +808,10 @@
else
scsi_status = DID_ERROR << 16;
} else {
- if (cmd->error == -EIO) {
+ if (cmd->error == -EIO &&
+ (cmd->key == 0 ||
+ cmd->key == MEDIUM_ERROR ||
+ cmd->key == UNIT_ATTENTION)) {
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
return;
}
@@ -1259,14 +1266,19 @@
return;
}
- len = le32_to_cpu(bcs->Residue);
- if (len != cmd->len - cmd->act_len) {
- /*
- * It is all right to transfer less, the caller has
- * to check. But it's not all right if the device
- * counts disagree with our counts.
- */
- goto Bad_End;
+ if (!sc->bad_resid) {
+ len = le32_to_cpu(bcs->Residue);
+ if (len != cmd->len - cmd->act_len) {
+ /*
+ * Only start ignoring if this cmd ended well.
+ */
+ if (cmd->len == cmd->act_len) {
+ printk(KERN_NOTICE "%s: "
+ "bad residual %d of %d, ignoring\n",
+ sc->name, len, cmd->len);
+ sc->bad_resid = 1;
+ }
+ }
}
switch (bcs->Status) {
@@ -1297,8 +1309,7 @@
ub_state_done(sc, cmd, -EIO);
} else {
- printk(KERN_WARNING "%s: "
- "wrong command state %d\n",
+ printk(KERN_WARNING "%s: wrong command state %d\n",
sc->name, cmd->state);
ub_state_done(sc, cmd, -EINVAL);
return;
@@ -1336,7 +1347,10 @@
return;
}
- sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
+ if (cmd->timeo)
+ sc->work_timer.expires = jiffies + cmd->timeo;
+ else
+ sc->work_timer.expires = jiffies + UB_DATA_TIMEOUT;
add_timer(&sc->work_timer);
cmd->state = UB_CMDST_DATA;
@@ -1376,7 +1390,10 @@
return -1;
}
- sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
+ if (cmd->timeo)
+ sc->work_timer.expires = jiffies + cmd->timeo;
+ else
+ sc->work_timer.expires = jiffies + UB_STAT_TIMEOUT;
add_timer(&sc->work_timer);
return 0;
}
@@ -1515,8 +1532,7 @@
return;
}
if (cmd->state != UB_CMDST_SENSE) {
- printk(KERN_WARNING "%s: "
- "sense done with bad cmd state %d\n",
+ printk(KERN_WARNING "%s: sense done with bad cmd state %d\n",
sc->name, cmd->state);
return;
}
@@ -1720,7 +1736,7 @@
}
/*
- * This is called once a new disk was seen by the block layer or by ub_probe().
+ * This is called by check_disk_change if we reported a media change.
* The main onjective here is to discover the features of the media such as
* the capacity, read-only status, etc. USB storage generally does not
* need to be spun up, but if we needed it, this would be the place.
@@ -2136,8 +2152,7 @@
}
if (ep_in == NULL || ep_out == NULL) {
- printk(KERN_NOTICE "%s: failed endpoint check\n",
- sc->name);
+ printk(KERN_NOTICE "%s: failed endpoint check\n", sc->name);
return -ENODEV;
}
@@ -2354,7 +2369,7 @@
spin_unlock_irqrestore(&ub_lock, flags);
/*
- * Fence stall clearnings, operations triggered by unlinkings and so on.
+ * Fence stall clearings, operations triggered by unlinkings and so on.
* We do not attempt to unlink any URBs, because we do not trust the
* unlink paths in HC drivers. Also, we get -84 upon disconnect anyway.
*/
@@ -2399,7 +2414,7 @@
del_gendisk(lun->disk);
/*
* I wish I could do:
- * set_bit(QUEUE_FLAG_DEAD, &q->queue_flags);
+ * queue_flag_set(QUEUE_FLAG_DEAD, q);
* As it is, we rely on our internal poisoning and let
* the upper levels to spin furiously failing all the I/O.
*/
@@ -2417,7 +2432,7 @@
spin_unlock_irqrestore(sc->lock, flags);
/*
- * There is virtually no chance that other CPU runs times so long
+ * There is virtually no chance that other CPU runs a timeout so long
* after ub_urb_complete should have called del_timer, but only if HCD
* didn't forget to deliver a callback on unlink.
*/
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index 0cfbe8c..84e064f 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -35,7 +35,7 @@
struct list_head list;
struct request *req;
struct virtio_blk_outhdr out_hdr;
- struct virtio_blk_inhdr in_hdr;
+ u8 status;
};
static void blk_done(struct virtqueue *vq)
@@ -48,7 +48,7 @@
spin_lock_irqsave(&vblk->lock, flags);
while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
int uptodate;
- switch (vbr->in_hdr.status) {
+ switch (vbr->status) {
case VIRTIO_BLK_S_OK:
uptodate = 1;
break;
@@ -101,7 +101,7 @@
sg_init_table(vblk->sg, VIRTIO_MAX_SG);
sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
- sg_set_buf(&vblk->sg[num+1], &vbr->in_hdr, sizeof(vbr->in_hdr));
+ sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
if (rq_data_dir(vbr->req) == WRITE) {
vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
@@ -157,10 +157,25 @@
/* We provide getgeo only to please some old bootloader/partitioning tools */
static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
{
- /* some standard values, similar to sd */
- geo->heads = 1 << 6;
- geo->sectors = 1 << 5;
- geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+ struct virtio_blk *vblk = bd->bd_disk->private_data;
+ struct virtio_blk_geometry vgeo;
+ int err;
+
+ /* see if the host passed in geometry config */
+ err = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_GEOMETRY,
+ offsetof(struct virtio_blk_config, geometry),
+ &vgeo);
+
+ if (!err) {
+ geo->heads = vgeo.heads;
+ geo->sectors = vgeo.sectors;
+ geo->cylinders = vgeo.cylinders;
+ } else {
+ /* some standard values, similar to sd */
+ geo->heads = 1 << 6;
+ geo->sectors = 1 << 5;
+ geo->cylinders = get_capacity(bd->bd_disk) >> 11;
+ }
return 0;
}
@@ -242,12 +257,12 @@
index++;
/* If barriers are supported, tell block layer that queue is ordered */
- if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER))
+ if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
/* Host must always specify the capacity. */
- __virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity),
- &cap);
+ vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
+ &cap, sizeof(cap));
/* If capacity is too big, truncate with warning. */
if ((sector_t)cap != cap) {
@@ -289,7 +304,6 @@
static void virtblk_remove(struct virtio_device *vdev)
{
struct virtio_blk *vblk = vdev->priv;
- int major = vblk->disk->major;
/* Nothing should be pending. */
BUG_ON(!list_empty(&vblk->reqs));
@@ -299,7 +313,6 @@
blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk);
- unregister_blkdev(major, "virtblk");
mempool_destroy(vblk->pool);
vdev->config->del_vq(vblk->vq);
kfree(vblk);
@@ -310,7 +323,14 @@
{ 0 },
};
+static unsigned int features[] = {
+ VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
+ VIRTIO_BLK_F_GEOMETRY,
+};
+
static struct virtio_driver virtio_blk = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index d771da8..f2fff57 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -137,7 +137,7 @@
schedule_work(&info->work);
}
-int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
+static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
{
/* We don't have real geometry info, but let's at least return
values consistent with the size of the device */
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 7e31d5f..e5cd856 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -143,7 +143,7 @@
int len;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- len = tty->driver->write(tty, skb->data, skb->len);
+ len = tty->ops->write(tty, skb->data, skb->len);
hdev->stat.byte_tx += len;
skb_pull(skb, len);
@@ -190,8 +190,7 @@
/* Flush any pending characters in the driver and discipline. */
tty_ldisc_flush(tty);
- if (tty->driver && tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
if (test_bit(HCI_UART_PROTO_SET, &hu->flags))
hu->proto->flush(hu);
@@ -285,9 +284,7 @@
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
-
- if (tty->driver && tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
return 0;
}
@@ -373,9 +370,7 @@
hu->hdev->stat.byte_rx += count;
spin_unlock(&hu->rx_lock);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
static int hci_uart_register_dev(struct hci_uart *hu)
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index ac382903..69f26eb 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -2194,7 +2194,6 @@
if (ret)
break;
- memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd[0] = GPCMD_READ_CD;
rq->cmd[1] = 1 << 2;
rq->cmd[2] = (lba >> 24) & 0xff;
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c
index b74b6c2..5245a4a 100644
--- a/drivers/cdrom/viocd.c
+++ b/drivers/cdrom/viocd.c
@@ -144,6 +144,7 @@
}
static const struct file_operations proc_viocd_operations = {
+ .owner = THIS_MODULE,
.open = proc_viocd_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -679,7 +680,6 @@
static int __init viocd_init(void)
{
- struct proc_dir_entry *e;
int ret = 0;
if (!firmware_has_feature(FW_FEATURE_ISERIES))
@@ -719,12 +719,8 @@
if (ret)
goto out_free_info;
- e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL);
- if (e) {
- e->owner = THIS_MODULE;
- e->proc_fops = &proc_viocd_operations;
- }
-
+ proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL,
+ &proc_viocd_operations);
return 0;
out_free_info:
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 929d4fa..5dce387 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -80,6 +80,15 @@
information. For framebuffer console users, please refer to
<file:Documentation/fb/fbcon.txt>.
+config DEVKMEM
+ bool "/dev/kmem virtual device support"
+ default y
+ help
+ Say Y here if you want to support the /dev/kmem device. The
+ /dev/kmem device is rarely used, but can be used for certain
+ kind of kernel debugging operations.
+ When in doubt, say "N".
+
config SERIAL_NONSTANDARD
bool "Non-standard serial port support"
depends on HAS_IOMEM
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index c69f795..99e6a40 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -35,7 +35,7 @@
//#define AGP_DEBUG 1
#ifdef AGP_DEBUG
-#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __FUNCTION__ , ## y)
+#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __func__ , ## y)
#else
#define DBG(x,y...) do { } while (0)
#endif
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 3d468f5..37457e5 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -832,33 +832,34 @@
local_irq_restore(flags);
}
-static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+static int rs_put_char(struct tty_struct *tty, unsigned char ch)
{
struct async_struct *info;
unsigned long flags;
if (!tty)
- return;
+ return 0;
info = tty->driver_data;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return;
+ return 0;
if (!info->xmit.buf)
- return;
+ return 0;
local_irq_save(flags);
if (CIRC_SPACE(info->xmit.head,
info->xmit.tail,
SERIAL_XMIT_SIZE) == 0) {
local_irq_restore(flags);
- return;
+ return 0;
}
info->xmit.buf[info->xmit.head++] = ch;
info->xmit.head &= SERIAL_XMIT_SIZE-1;
local_irq_restore(flags);
+ return 1;
}
static void rs_flush_chars(struct tty_struct *tty)
@@ -1074,6 +1075,7 @@
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
+ lock_kernel();
tmp.type = state->type;
tmp.line = state->line;
tmp.port = state->port;
@@ -1084,6 +1086,7 @@
tmp.close_delay = state->close_delay;
tmp.closing_wait = state->closing_wait;
tmp.custom_divisor = state->custom_divisor;
+ unlock_kernel();
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
return 0;
@@ -1099,13 +1102,17 @@
if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
+
+ lock_kernel();
state = info->state;
old_state = *state;
change_irq = new_serial.irq != state->irq;
change_port = (new_serial.port != state->port);
- if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size))
+ if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) {
+ unlock_kernel();
return -EINVAL;
+ }
if (!serial_isroot()) {
if ((new_serial.baud_base != state->baud_base) ||
@@ -1122,8 +1129,10 @@
goto check_and_exit;
}
- if (new_serial.baud_base < 9600)
+ if (new_serial.baud_base < 9600) {
+ unlock_kernel();
return -EINVAL;
+ }
/*
* OK, past this point, all the error checking has been done.
@@ -1157,6 +1166,7 @@
}
} else
retval = startup(info);
+ unlock_kernel();
return retval;
}
@@ -1496,8 +1506,7 @@
rs_wait_until_sent(tty, info->timeout);
}
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -1530,6 +1539,8 @@
return; /* Just in case.... */
orig_jiffies = jiffies;
+
+ lock_kernel();
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@@ -1570,6 +1581,7 @@
break;
}
__set_current_state(TASK_RUNNING);
+ unlock_kernel();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c
index 17d5431..cdd876d 100644
--- a/drivers/char/apm-emulation.c
+++ b/drivers/char/apm-emulation.c
@@ -14,6 +14,7 @@
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/miscdevice.h>
#include <linux/apm_bios.h>
#include <linux/capability.h>
@@ -493,11 +494,10 @@
* -1: Unknown
* 8) min = minutes; sec = seconds
*/
-static int apm_get_info(char *buf, char **start, off_t fpos, int length)
+static int proc_apm_show(struct seq_file *m, void *v)
{
struct apm_power_info info;
char *units;
- int ret;
info.ac_line_status = 0xff;
info.battery_status = 0xff;
@@ -515,14 +515,27 @@
case 1: units = "sec"; break;
}
- ret = sprintf(buf, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
+ seq_printf(m, "%s 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
driver_version, APM_32_BIT_SUPPORT,
info.ac_line_status, info.battery_status,
info.battery_flag, info.battery_life,
info.time, units);
- return ret;
+ return 0;
}
+
+static int proc_apm_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_apm_show, NULL);
+}
+
+static const struct file_operations apm_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_apm_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
static int kapmd(void *arg)
@@ -593,7 +606,7 @@
wake_up_process(kapmd_tsk);
#ifdef CONFIG_PROC_FS
- create_proc_info_entry("apm", 0, NULL, apm_get_info);
+ proc_create("apm", 0, NULL, &apm_proc_fops);
#endif
ret = misc_register(&apm_device);
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index a7c4990..31d08b6 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -199,7 +199,7 @@
if (pci_enable_device(dev))
return -EIO;
- RamIO = ioremap(pci_resource_start(dev, 0), LEN_RAM_IO);
+ RamIO = ioremap_nocache(pci_resource_start(dev, 0), LEN_RAM_IO);
if (!RamIO) {
printk(KERN_INFO "ac.o: Failed to ioremap PCI memory "
@@ -254,7 +254,7 @@
/* Now try the specified ISA cards */
for (i = 0; i < MAX_ISA_BOARD; i++) {
- RamIO = ioremap(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
+ RamIO = ioremap_nocache(mem + (LEN_RAM_IO * i), LEN_RAM_IO);
if (!RamIO) {
printk(KERN_INFO "ac.o: Failed to ioremap the ISA card's memory space (slot #%d)\n", i + 1);
diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c
index 6b104e4..4246b8e 100644
--- a/drivers/char/consolemap.c
+++ b/drivers/char/consolemap.c
@@ -277,6 +277,7 @@
return p->inverse_translations[m][glyph];
}
}
+EXPORT_SYMBOL_GPL(inverse_translate);
static void update_user_maps(void)
{
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index e4f579c..ef73e72 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -21,7 +21,6 @@
*
* This version supports shared IRQ's (only for PCI boards).
*
- * $Log: cyclades.c,v $
* Prevent users from opening non-existing Z ports.
*
* Revision 2.3.2.8 2000/07/06 18:14:16 ivan
@@ -62,7 +61,7 @@
* Driver now makes sure that the constant SERIAL_XMIT_SIZE is defined;
*
* Revision 2.3.2.2 1999/10/01 11:27:43 ivan
- * Fixed bug in cyz_poll that would make all ports but port 0
+ * Fixed bug in cyz_poll that would make all ports but port 0
* unable to transmit/receive data (Cyclades-Z only);
* Implemented logic to prevent the RX buffer from being stuck with data
* due to a driver / firmware race condition in interrupt op mode
@@ -83,25 +82,25 @@
* Revision 2.3.1.1 1999/07/15 16:45:53 ivan
* Removed CY_PROC conditional compilation;
* Implemented SMP-awareness for the driver;
- * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
+ * Implemented a new ISA IRQ autoprobe that uses the irq_probe_[on|off]
* functions;
* The driver now accepts memory addresses (maddr=0xMMMMM) and IRQs
* (irq=NN) as parameters (only for ISA boards);
- * Fixed bug in set_line_char that would prevent the Cyclades-Z
+ * Fixed bug in set_line_char that would prevent the Cyclades-Z
* ports from being configured at speeds above 115.2Kbps;
* Fixed bug in cy_set_termios that would prevent XON/XOFF flow control
* switching from working properly;
- * The driver now only prints IRQ info for the Cyclades-Z if it's
+ * The driver now only prints IRQ info for the Cyclades-Z if it's
* configured to work in interrupt mode;
*
* Revision 2.2.2.3 1999/06/28 11:13:29 ivan
* Added support for interrupt mode operation for the Z cards;
* Removed the driver inactivity control for the Z;
- * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
+ * Added a missing MOD_DEC_USE_COUNT in the cy_open function for when
* the Z firmware is not loaded yet;
- * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
+ * Replaced the "manual" Z Tx flush buffer by a call to a FW command of
* same functionality;
- * Implemented workaround for IRQ setting loss on the PCI configuration
+ * Implemented workaround for IRQ setting loss on the PCI configuration
* registers after a PCI bridge EEPROM reload (affects PLX9060 only);
*
* Revision 2.2.2.2 1999/05/14 17:18:15 ivan
@@ -112,22 +111,22 @@
* BREAK implementation changed in order to make use of the 'break_ctl'
* TTY facility;
* Fixed typo in TTY structure field 'driver_name';
- * Included a PCI bridge reset and EEPROM reload in the board
+ * Included a PCI bridge reset and EEPROM reload in the board
* initialization code (for both Y and Z series).
*
* Revision 2.2.2.1 1999/04/08 16:17:43 ivan
- * Fixed a bug in cy_wait_until_sent that was preventing the port to be
+ * Fixed a bug in cy_wait_until_sent that was preventing the port to be
* closed properly after a SIGINT;
* Module usage counter scheme revisited;
* Added support to the upcoming Y PCI boards (i.e., support to additional
* PCI Device ID's).
- *
+ *
* Revision 2.2.1.10 1999/01/20 16:14:29 ivan
* Removed all unnecessary page-alignement operations in ioremap calls
* (ioremap is currently safe for these operations).
*
* Revision 2.2.1.9 1998/12/30 18:18:30 ivan
- * Changed access to PLX PCI bridge registers from I/O to MMIO, in
+ * Changed access to PLX PCI bridge registers from I/O to MMIO, in
* order to make PLX9050-based boards work with certain motherboards.
*
* Revision 2.2.1.8 1998/11/13 12:46:20 ivan
@@ -148,7 +147,7 @@
* Fixed Cyclom-4Yo hardware detection bug.
*
* Revision 2.2.1.4 1998/08/04 11:02:50 ivan
- * /proc/cyclades implementation with great collaboration of
+ * /proc/cyclades implementation with great collaboration of
* Marc Lewis <marc@blarg.net>;
* cyy_interrupt was changed to avoid occurrence of kernel oopses
* during PPP operation.
@@ -157,7 +156,7 @@
* General code review in order to comply with 2.1 kernel standards;
* data loss prevention for slow devices revisited (cy_wait_until_sent
* was created);
- * removed conditional compilation for new/old PCI structure support
+ * removed conditional compilation for new/old PCI structure support
* (now the driver only supports the new PCI structure).
*
* Revision 2.2.1.1 1998/03/19 16:43:12 ivan
@@ -168,7 +167,7 @@
* cleaned up the data loss fix;
* fixed XON/XOFF handling once more (Cyclades-Z);
* general review of the driver routines;
- * introduction of a mechanism to prevent data loss with slow
+ * introduction of a mechanism to prevent data loss with slow
* printers, by forcing a delay before closing the port.
*
* Revision 2.1.1.2 1998/02/17 16:50:00 ivan
@@ -182,12 +181,12 @@
* Code review for the module cleanup routine;
* fixed RTS and DTR status report for new CD1400's in get_modem_info;
* includes anonymous changes regarding signal_pending.
- *
+ *
* Revision 2.1 1997/11/01 17:42:41 ivan
* Changes in the driver to support Alpha systems (except 8Zo V_1);
* BREAK fix for the Cyclades-Z boards;
* driver inactivity control by FW implemented;
- * introduction of flag that allows driver to take advantage of
+ * introduction of flag that allows driver to take advantage of
* a special CD1400 feature related to HW flow control;
* added support for the CD1400 rev. J (Cyclom-Y boards);
* introduction of ioctls to:
@@ -196,17 +195,17 @@
* - adjust the polling interval (Cyclades-Z);
*
* Revision 1.36.4.33 1997/06/27 19:00:00 ivan
- * Fixes related to kernel version conditional
+ * Fixes related to kernel version conditional
* compilation.
- *
+ *
* Revision 1.36.4.32 1997/06/14 19:30:00 ivan
- * Compatibility issues between kernels 2.0.x and
+ * Compatibility issues between kernels 2.0.x and
* 2.1.x (mainly related to clear_bit function).
- *
+ *
* Revision 1.36.4.31 1997/06/03 15:30:00 ivan
- * Changes to define the memory window according to the
+ * Changes to define the memory window according to the
* board type.
- *
+ *
* Revision 1.36.4.30 1997/05/16 15:30:00 daniel
* Changes to support new cycladesZ boards.
*
@@ -624,7 +623,7 @@
#undef CY_PCI_DEBUG
/*
- * Include section
+ * Include section
*/
#include <linux/module.h>
#include <linux/errno.h>
@@ -649,9 +648,9 @@
#include <linux/firmware.h>
#include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -668,10 +667,10 @@
((readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
-#define ISZLOADED(card) (((ZO_V1==readl(&((struct RUNTIME_9060 __iomem *) \
+#define ISZLOADED(card) (((ZO_V1 == readl(&((struct RUNTIME_9060 __iomem *) \
((card).ctl_addr))->mail_box_0)) || \
Z_FPGA_CHECK(card)) && \
- (ZFIRM_ID==readl(&((struct FIRM_ID __iomem *) \
+ (ZFIRM_ID == readl(&((struct FIRM_ID __iomem *) \
((card).base_addr+ID_ADDRESS))->signature)))
#ifndef SERIAL_XMIT_SIZE
@@ -809,12 +808,12 @@
/*
* The Cyclades driver implements HW flow control as any serial driver.
- * The cyclades_port structure member rflow and the vector rflow_thr
- * allows us to take advantage of a special feature in the CD1400 to avoid
- * data loss even when the system interrupt latency is too high. These flags
- * are to be used only with very special applications. Setting these flags
- * requires the use of a special cable (DTR and RTS reversed). In the new
- * CD1400-based boards (rev. 6.00 or later), there is no need for special
+ * The cyclades_port structure member rflow and the vector rflow_thr
+ * allows us to take advantage of a special feature in the CD1400 to avoid
+ * data loss even when the system interrupt latency is too high. These flags
+ * are to be used only with very special applications. Setting these flags
+ * requires the use of a special cable (DTR and RTS reversed). In the new
+ * CD1400-based boards (rev. 6.00 or later), there is no need for special
* cables.
*/
@@ -841,14 +840,22 @@
#ifdef CONFIG_PCI
static struct pci_device_id cy_pci_dev_id[] __devinitdata = {
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) }, /* PCI < 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) }, /* PCI > 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) }, /* 4Y PCI < 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) }, /* 4Y PCI > 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) }, /* 8Y PCI < 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) }, /* 8Y PCI > 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) }, /* Z PCI < 1Mb */
- { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) }, /* Z PCI > 1Mb */
+ /* PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Lo) },
+ /* PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Y_Hi) },
+ /* 4Y PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Lo) },
+ /* 4Y PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_4Y_Hi) },
+ /* 8Y PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Lo) },
+ /* 8Y PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_8Y_Hi) },
+ /* Z PCI < 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Lo) },
+ /* Z PCI > 1Mb */
+ { PCI_DEVICE(PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_CYCLOM_Z_Hi) },
{ } /* end of table */
};
MODULE_DEVICE_TABLE(pci, cy_pci_dev_id);
@@ -905,15 +912,14 @@
This function is only called from inside spinlock-protected code.
*/
-static int cyy_issue_cmd(void __iomem * base_addr, u_char cmd, int index)
+static int cyy_issue_cmd(void __iomem *base_addr, u_char cmd, int index)
{
unsigned int i;
/* Check to see that the previous command has completed */
for (i = 0; i < 100; i++) {
- if (readb(base_addr + (CyCCR << index)) == 0) {
+ if (readb(base_addr + (CyCCR << index)) == 0)
break;
- }
udelay(10L);
}
/* if the CCR never cleared, the previous command
@@ -929,7 +935,7 @@
#ifdef CONFIG_ISA
/* ISA interrupt detection code */
-static unsigned detect_isa_irq(void __iomem * address)
+static unsigned detect_isa_irq(void __iomem *address)
{
int irq;
unsigned long irqs, flags;
@@ -1038,7 +1044,7 @@
if (info->flags & ASYNC_SAK)
do_SAK(tty);
} else if (data & CyFRAME) {
- tty_insert_flip_char( tty,
+ tty_insert_flip_char(tty,
readb(base_addr + (CyRDSR <<
index)), TTY_FRAME);
info->icount.rx++;
@@ -1320,7 +1326,8 @@
if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",irq);
+ printk(KERN_DEBUG "cyy_interrupt: spurious interrupt %d\n",
+ irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
@@ -1375,12 +1382,12 @@
/***********************************************************/
/********* End of block of Cyclom-Y specific code **********/
-/******** Start of block of Cyclades-Z specific code *********/
+/******** Start of block of Cyclades-Z specific code *******/
/***********************************************************/
static int
cyz_fetch_msg(struct cyclades_card *cinfo,
- __u32 * channel, __u8 * cmd, __u32 * param)
+ __u32 *channel, __u8 *cmd, __u32 *param)
{
struct FIRM_ID __iomem *firm_id;
struct ZFW_CTRL __iomem *zfw_ctrl;
@@ -1388,9 +1395,8 @@
unsigned long loc_doorbell;
firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)) {
+ if (!ISZLOADED(*cinfo))
return -1;
- }
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
@@ -1418,9 +1424,9 @@
unsigned int index;
firm_id = cinfo->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*cinfo)) {
+ if (!ISZLOADED(*cinfo))
return -1;
- }
+
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
@@ -1428,9 +1434,8 @@
pci_doorbell =
&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
while ((readl(pci_doorbell) & 0xff) != 0) {
- if (index++ == 1000) {
+ if (index++ == 1000)
return (int)(readl(pci_doorbell) & 0xff);
- }
udelay(50L);
}
cy_writel(&board_ctrl->hcmd_channel, channel);
@@ -1504,7 +1509,8 @@
while (len--) {
data = readb(cinfo->base_addr + rx_bufaddr +
new_rx_get);
- new_rx_get = (new_rx_get + 1)& (rx_bufsize - 1);
+ new_rx_get = (new_rx_get + 1) &
+ (rx_bufsize - 1);
tty_insert_flip_char(tty, data, TTY_NORMAL);
info->idle_stats.recv_bytes++;
info->icount.rx++;
@@ -1636,7 +1642,8 @@
special_count = 0;
delta_count = 0;
info = &cinfo->ports[channel];
- if ((tty = info->tty) == NULL)
+ tty = info->tty;
+ if (tty == NULL)
continue;
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
@@ -1732,7 +1739,8 @@
if (unlikely(cinfo == NULL)) {
#ifdef CY_DEBUG_INTERRUPTS
- printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);
+ printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",
+ irq);
#endif
return IRQ_NONE; /* spurious interrupt */
}
@@ -1851,9 +1859,8 @@
}
if (!info->type) {
- if (info->tty) {
+ if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
free_page(page);
goto errout;
}
@@ -1904,9 +1911,8 @@
readb(base_addr + (CySRER << index)) | CyRxData);
info->flags |= ASYNC_INITIALIZED;
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
info->breakon = info->breakoff = 0;
memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
@@ -1925,9 +1931,8 @@
base_addr = card->base_addr;
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(*card)) {
+ if (!ISZLOADED(*card))
return -ENODEV;
- }
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -1990,9 +1995,8 @@
/* enable send, recv, modem !!! */
info->flags |= ASYNC_INITIALIZED;
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
info->breakon = info->breakoff = 0;
memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));
@@ -2061,9 +2065,8 @@
void __iomem *base_addr;
int chip, channel, index;
- if (!(info->flags & ASYNC_INITIALIZED)) {
+ if (!(info->flags & ASYNC_INITIALIZED))
return;
- }
card = info->card;
channel = info->line - card->first_line;
@@ -2105,9 +2108,8 @@
/* it may be appropriate to clear _XMIT at
some later date (after testing)!!! */
- if (info->tty) {
+ if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
@@ -2124,9 +2126,8 @@
#endif
firm_id = base_addr + ID_ADDRESS;
- if (!ISZLOADED(*card)) {
+ if (!ISZLOADED(*card))
return;
- }
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -2157,9 +2158,8 @@
#endif
}
- if (info->tty) {
+ if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- }
info->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&card->card_lock, flags);
@@ -2204,7 +2204,8 @@
* If non-blocking mode is set, then make the check up front
* and then exit.
*/
- if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {
+ if ((filp->f_flags & O_NONBLOCK) ||
+ (tty->flags & (1 << TTY_IO_ERROR))) {
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
}
@@ -2301,7 +2302,8 @@
return -EINVAL;
}
- zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)& 0xfffff);
+ zfw_ctrl = base_addr + (readl(&firm_id->zfwctrl_addr)
+ & 0xfffff);
board_ctrl = &zfw_ctrl->board_ctrl;
ch_ctrl = zfw_ctrl->ch_ctrl;
@@ -2378,9 +2380,9 @@
int retval;
line = tty->index;
- if ((tty->index < 0) || (NR_PORTS <= line)) {
+ if (tty->index < 0 || NR_PORTS <= line)
return -ENODEV;
- }
+
for (i = 0; i < NR_CARDS; i++)
if (line < cy_card[i].first_line + cy_card[i].nports &&
line >= cy_card[i].first_line)
@@ -2388,9 +2390,8 @@
if (i >= NR_CARDS)
return -ENODEV;
info = &cy_card[i].ports[line - cy_card[i].first_line];
- if (info->line < 0) {
+ if (info->line < 0)
return -ENODEV;
- }
/* If the card's firmware hasn't been loaded,
treat it as absent from the system. This
@@ -2456,9 +2457,9 @@
#endif
tty->driver_data = info;
info->tty = tty;
- if (serial_paranoia_check(info, tty->name, "cy_open")) {
+ if (serial_paranoia_check(info, tty->name, "cy_open"))
return -ENODEV;
- }
+
#ifdef CY_DEBUG_OPEN
printk(KERN_DEBUG "cyc:cy_open ttyC%d, count = %d\n", info->line,
info->count);
@@ -2482,9 +2483,8 @@
* Start up serial port
*/
retval = startup(info);
- if (retval) {
+ if (retval)
return retval;
- }
retval = block_til_ready(tty, filp, info);
if (retval) {
@@ -2522,6 +2522,7 @@
return; /* Just in case.... */
orig_jiffies = jiffies;
+ lock_kernel();
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@@ -2573,11 +2574,47 @@
}
/* Run one more char cycle */
msleep_interruptible(jiffies_to_msecs(char_time * 5));
+ unlock_kernel();
#ifdef CY_DEBUG_WAIT_UNTIL_SENT
printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies);
#endif
}
+static void cy_flush_buffer(struct tty_struct *tty)
+{
+ struct cyclades_port *info = tty->driver_data;
+ struct cyclades_card *card;
+ int channel, retval;
+ unsigned long flags;
+
+#ifdef CY_DEBUG_IO
+ printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
+#endif
+
+ if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
+ return;
+
+ card = info->card;
+ channel = info->line - card->first_line;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+ spin_unlock_irqrestore(&card->card_lock, flags);
+
+ if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
+ buffers as well */
+ spin_lock_irqsave(&card->card_lock, flags);
+ retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
+ if (retval != 0) {
+ printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
+ "was %x\n", info->line, retval);
+ }
+ spin_unlock_irqrestore(&card->card_lock, flags);
+ }
+ tty_wakeup(tty);
+} /* cy_flush_buffer */
+
+
/*
* This routine is called when a particular tty device is closed.
*/
@@ -2591,9 +2628,8 @@
printk(KERN_DEBUG "cyc:cy_close ttyC%d\n", info->line);
#endif
- if (!info || serial_paranoia_check(info, tty->name, "cy_close")) {
+ if (!info || serial_paranoia_check(info, tty->name, "cy_close"))
return;
- }
card = info->card;
@@ -2641,9 +2677,9 @@
*/
tty->closing = 1;
spin_unlock_irqrestore(&card->card_lock, flags);
- if (info->closing_wait != CY_CLOSING_WAIT_NONE) {
+ if (info->closing_wait != CY_CLOSING_WAIT_NONE)
tty_wait_until_sent(tty, info->closing_wait);
- }
+
spin_lock_irqsave(&card->card_lock, flags);
if (!IS_CYC_Z(*card)) {
@@ -2657,15 +2693,16 @@
cy_writeb(base_addr + (CySRER << index),
readb(base_addr + (CySRER << index)) & ~CyRxData);
if (info->flags & ASYNC_INITIALIZED) {
- /* Waiting for on-board buffers to be empty before closing
- the port */
+ /* Waiting for on-board buffers to be empty before
+ closing the port */
spin_unlock_irqrestore(&card->card_lock, flags);
cy_wait_until_sent(tty, info->timeout);
spin_lock_irqsave(&card->card_lock, flags);
}
} else {
#ifdef Z_WAKE
- /* Waiting for on-board buffers to be empty before closing the port */
+ /* Waiting for on-board buffers to be empty before closing
+ the port */
void __iomem *base_addr = card->base_addr;
struct FIRM_ID __iomem *firm_id = base_addr + ID_ADDRESS;
struct ZFW_CTRL __iomem *zfw_ctrl =
@@ -2689,8 +2726,7 @@
spin_unlock_irqrestore(&card->card_lock, flags);
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ cy_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&card->card_lock, flags);
@@ -2738,17 +2774,16 @@
printk(KERN_DEBUG "cyc:cy_write ttyC%d\n", info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_write")) {
+ if (serial_paranoia_check(info, tty->name, "cy_write"))
return 0;
- }
if (!info->xmit_buf)
return 0;
spin_lock_irqsave(&info->card->card_lock, flags);
while (1) {
- c = min(count, min((int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1),
- (int)(SERIAL_XMIT_SIZE - info->xmit_head)));
+ c = min(count, (int)(SERIAL_XMIT_SIZE - info->xmit_cnt - 1));
+ c = min(c, (int)(SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0)
break;
@@ -2766,9 +2801,9 @@
info->idle_stats.xmit_bytes += ret;
info->idle_stats.xmit_idle = jiffies;
- if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+ if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped)
start_xmit(info);
- }
+
return ret;
} /* cy_write */
@@ -2779,7 +2814,7 @@
* done stuffing characters into the driver. If there is no room
* in the queue, the character is ignored.
*/
-static void cy_put_char(struct tty_struct *tty, unsigned char ch)
+static int cy_put_char(struct tty_struct *tty, unsigned char ch)
{
struct cyclades_port *info = tty->driver_data;
unsigned long flags;
@@ -2789,15 +2824,15 @@
#endif
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
- return;
+ return 0;
if (!info->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->card->card_lock, flags);
if (info->xmit_cnt >= (int)(SERIAL_XMIT_SIZE - 1)) {
spin_unlock_irqrestore(&info->card->card_lock, flags);
- return;
+ return 0;
}
info->xmit_buf[info->xmit_head++] = ch;
@@ -2806,11 +2841,12 @@
info->idle_stats.xmit_bytes++;
info->idle_stats.xmit_idle = jiffies;
spin_unlock_irqrestore(&info->card->card_lock, flags);
+ return 1;
} /* cy_put_char */
/*
* This routine is called by the kernel after it has written a
- * series of characters to the tty device using put_char().
+ * series of characters to the tty device using put_char().
*/
static void cy_flush_chars(struct tty_struct *tty)
{
@@ -2882,6 +2918,7 @@
int char_count;
__u32 tx_put, tx_get, tx_bufsize;
+ lock_kernel();
firm_id = card->base_addr + ID_ADDRESS;
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -2899,6 +2936,7 @@
printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
info->line, info->xmit_cnt + char_count);
#endif
+ unlock_kernel();
return info->xmit_cnt + char_count;
}
#endif /* Z_EXT_CHARS_IN_BUFFER */
@@ -2950,12 +2988,12 @@
int baud, baud_rate = 0;
int i;
- if (!info->tty || !info->tty->termios) {
+ if (!info->tty || !info->tty->termios)
return;
- }
- if (info->line == -1) {
+
+ if (info->line == -1)
return;
- }
+
cflag = info->tty->termios->c_cflag;
iflag = info->tty->termios->c_iflag;
@@ -2994,13 +3032,11 @@
}
/* find the baud index */
for (i = 0; i < 20; i++) {
- if (baud == baud_table[i]) {
+ if (baud == baud_table[i])
break;
- }
}
- if (i == 20) {
+ if (i == 20)
i = 19; /* CD1400_MAX_SPEED */
- }
if (baud == 38400 && (info->flags & ASYNC_SPD_MASK) ==
ASYNC_SPD_CUST) {
@@ -3059,18 +3095,16 @@
info->cor1 = Cy_8_BITS;
break;
}
- if (cflag & CSTOPB) {
+ if (cflag & CSTOPB)
info->cor1 |= Cy_2_STOP;
- }
+
if (cflag & PARENB) {
- if (cflag & PARODD) {
+ if (cflag & PARODD)
info->cor1 |= CyPARITY_O;
- } else {
+ else
info->cor1 |= CyPARITY_E;
- }
- } else {
+ } else
info->cor1 |= CyPARITY_NONE;
- }
/* CTS flow control flag */
if (cflag & CRTSCTS) {
@@ -3123,7 +3157,8 @@
cyy_issue_cmd(base_addr, CyCOR_CHANGE | CyCOR1ch | CyCOR2ch |
CyCOR3ch, index);
- cy_writeb(base_addr + (CyCAR << index), (u_char) channel); /* !!! Is this needed? */
+ /* !!! Is this needed? */
+ cy_writeb(base_addr + (CyCAR << index), (u_char) channel);
cy_writeb(base_addr + (CyRTPR << index),
(info->default_timeout ? info->default_timeout : 0x02));
/* 10ms rx timeout */
@@ -3191,9 +3226,8 @@
#endif
}
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
spin_unlock_irqrestore(&card->card_lock, flags);
} else {
@@ -3206,9 +3240,8 @@
int retval;
firm_id = card->base_addr + ID_ADDRESS;
- if (!ISZLOADED(*card)) {
+ if (!ISZLOADED(*card))
return;
- }
zfw_ctrl = card->base_addr +
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
@@ -3268,14 +3301,12 @@
readl(&ch_ctrl->comm_data_l) | C_DL_1STOP);
}
if (cflag & PARENB) {
- if (cflag & PARODD) {
+ if (cflag & PARODD)
cy_writel(&ch_ctrl->comm_parity, C_PR_ODD);
- } else {
+ else
cy_writel(&ch_ctrl->comm_parity, C_PR_EVEN);
- }
- } else {
+ } else
cy_writel(&ch_ctrl->comm_parity, C_PR_NONE);
- }
/* CTS flow control flag */
if (cflag & CRTSCTS) {
@@ -3305,11 +3336,10 @@
}
/* CD sensitivity */
- if (cflag & CLOCAL) {
+ if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
- } else {
+ else
info->flags |= ASYNC_CHECK_CD;
- }
if (baud == 0) { /* baud rate is zero, turn off line */
cy_writel(&ch_ctrl->rs_control,
@@ -3325,21 +3355,20 @@
#endif
}
- retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM,0L);
+ retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);
if (retval != 0) {
printk(KERN_ERR "cyc:set_line_char(2) retval on ttyC%d "
"was %x\n", info->line, retval);
}
- if (info->tty) {
+ if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
- }
}
} /* set_line_char */
static int
get_serial_info(struct cyclades_port *info,
- struct serial_struct __user * retinfo)
+ struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
struct cyclades_card *cinfo = info->card;
@@ -3363,7 +3392,7 @@
static int
set_serial_info(struct cyclades_port *info,
- struct serial_struct __user * new_info)
+ struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
struct cyclades_port old_info;
@@ -3417,7 +3446,7 @@
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct cyclades_port *info, unsigned int __user * value)
+static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
{
struct cyclades_card *card;
int chip, channel, index;
@@ -3461,9 +3490,11 @@
struct BOARD_CTRL __iomem *board_ctrl;
struct CH_CTRL __iomem *ch_ctrl;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
+ lock_kernel();
+
card = info->card;
channel = info->line - card->first_line;
if (!IS_CYC_Z(*card)) {
@@ -3506,10 +3537,12 @@
((lstatus & C_RS_CTS) ? TIOCM_CTS : 0);
} else {
result = 0;
+ unlock_kernel();
return -ENODEV;
}
}
+ unlock_kernel();
return result;
} /* cy_tiomget */
@@ -3528,7 +3561,7 @@
struct CH_CTRL __iomem *ch_ctrl;
int retval;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
card = info->card;
@@ -3727,8 +3760,8 @@
spin_unlock_irqrestore(&card->card_lock, flags);
} /* cy_break */
-static int
-get_mon_info(struct cyclades_port *info, struct cyclades_monitor __user * mon)
+static int get_mon_info(struct cyclades_port *info,
+ struct cyclades_monitor __user *mon)
{
if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
@@ -3767,8 +3800,8 @@
return 0;
} /* set_threshold */
-static int
-get_threshold(struct cyclades_port *info, unsigned long __user * value)
+static int get_threshold(struct cyclades_port *info,
+ unsigned long __user *value)
{
struct cyclades_card *card;
void __iomem *base_addr;
@@ -3789,15 +3822,15 @@
return 0;
} /* get_threshold */
-static int
-set_default_threshold(struct cyclades_port *info, unsigned long value)
+static int set_default_threshold(struct cyclades_port *info,
+ unsigned long value)
{
info->default_threshold = value & 0x0f;
return 0;
} /* set_default_threshold */
-static int
-get_default_threshold(struct cyclades_port *info, unsigned long __user * value)
+static int get_default_threshold(struct cyclades_port *info,
+ unsigned long __user *value)
{
return put_user(info->default_threshold, value);
} /* get_default_threshold */
@@ -3824,7 +3857,8 @@
return 0;
} /* set_timeout */
-static int get_timeout(struct cyclades_port *info, unsigned long __user * value)
+static int get_timeout(struct cyclades_port *info,
+ unsigned long __user *value)
{
struct cyclades_card *card;
void __iomem *base_addr;
@@ -3851,8 +3885,8 @@
return 0;
} /* set_default_timeout */
-static int
-get_default_timeout(struct cyclades_port *info, unsigned long __user * value)
+static int get_default_timeout(struct cyclades_port *info,
+ unsigned long __user *value)
{
return put_user(info->default_timeout, value);
} /* get_default_timeout */
@@ -3880,6 +3914,7 @@
printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n",
info->line, cmd, arg);
#endif
+ lock_kernel();
switch (cmd) {
case CYGETMON:
@@ -3936,7 +3971,7 @@
break;
#endif /* CONFIG_CYZ_INTR */
case CYSETWAIT:
- info->closing_wait = (unsigned short)arg *HZ / 100;
+ info->closing_wait = (unsigned short)arg * HZ / 100;
ret_val = 0;
break;
case CYGETWAIT:
@@ -3988,47 +4023,47 @@
p_cuser = argp;
ret_val = put_user(cnow.cts, &p_cuser->cts);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.dsr, &p_cuser->dsr);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.rng, &p_cuser->rng);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.dcd, &p_cuser->dcd);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.rx, &p_cuser->rx);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.tx, &p_cuser->tx);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.frame, &p_cuser->frame);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.overrun, &p_cuser->overrun);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.parity, &p_cuser->parity);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.brk, &p_cuser->brk);
if (ret_val)
- return ret_val;
+ break;
ret_val = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
if (ret_val)
- return ret_val;
+ break;
ret_val = 0;
break;
default:
ret_val = -ENOIOCTLCMD;
}
+ unlock_kernel();
#ifdef CY_DEBUG_OTHER
printk(KERN_DEBUG "cyc:cy_ioctl done\n");
#endif
-
return ret_val;
} /* cy_ioctl */
@@ -4113,9 +4148,8 @@
tty->ldisc.chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_throttle")) {
+ if (serial_paranoia_check(info, tty->name, "cy_throttle"))
return;
- }
card = info->card;
@@ -4169,12 +4203,11 @@
char buf[64];
printk(KERN_DEBUG "cyc:unthrottle %s: %ld...ttyC%d\n",
- tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty),info->line);
+ tty_name(tty, buf), tty_chars_in_buffer(tty), info->line);
#endif
- if (serial_paranoia_check(info, tty->name, "cy_unthrottle")) {
+ if (serial_paranoia_check(info, tty->name, "cy_unthrottle"))
return;
- }
if (I_IXOFF(tty)) {
if (info->x_char)
@@ -4269,47 +4302,14 @@
base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
spin_lock_irqsave(&cinfo->card_lock, flags);
- cy_writeb(base_addr + (CyCAR << index), (u_char) (channel & 0x0003)); /* index channel */
+ cy_writeb(base_addr + (CyCAR << index),
+ (u_char) (channel & 0x0003)); /* index channel */
cy_writeb(base_addr + (CySRER << index),
readb(base_addr + (CySRER << index)) | CyTxRdy);
spin_unlock_irqrestore(&cinfo->card_lock, flags);
}
} /* cy_start */
-static void cy_flush_buffer(struct tty_struct *tty)
-{
- struct cyclades_port *info = tty->driver_data;
- struct cyclades_card *card;
- int channel, retval;
- unsigned long flags;
-
-#ifdef CY_DEBUG_IO
- printk(KERN_DEBUG "cyc:cy_flush_buffer ttyC%d\n", info->line);
-#endif
-
- if (serial_paranoia_check(info, tty->name, "cy_flush_buffer"))
- return;
-
- card = info->card;
- channel = info->line - card->first_line;
-
- spin_lock_irqsave(&card->card_lock, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- spin_unlock_irqrestore(&card->card_lock, flags);
-
- if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
- buffers as well */
- spin_lock_irqsave(&card->card_lock, flags);
- retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
- if (retval != 0) {
- printk(KERN_ERR "cyc: flush_buffer retval on ttyC%d "
- "was %x\n", info->line, retval);
- }
- spin_unlock_irqrestore(&card->card_lock, flags);
- }
- tty_wakeup(tty);
-} /* cy_flush_buffer */
-
/*
* cy_hangup() --- called by tty_hangup() when a hangup is signaled.
*/
@@ -4406,10 +4406,11 @@
info->cor3 = 0x08; /* _very_ small rcv threshold */
chip_number = (port - cinfo->first_line) / 4;
- if ((info->chip_rev = readb(cinfo->base_addr +
- (cy_chip_offset[chip_number] <<
- index) + (CyGFRCR << index))) >=
- CD1400_REV_J) {
+ info->chip_rev = readb(cinfo->base_addr +
+ (cy_chip_offset[chip_number] << index) +
+ (CyGFRCR << index));
+
+ if (info->chip_rev >= CD1400_REV_J) {
/* It is a CD1400 rev. J or later */
info->tbpr = baud_bpr_60[13]; /* Tx BPR */
info->tco = baud_co_60[13]; /* Tx CO */
@@ -4454,7 +4455,8 @@
/* Cy_ClrIntr is 0x1800 */
udelay(500L);
- for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD; chip_number++) {
+ for (chip_number = 0; chip_number < CyMAX_CHIPS_PER_CARD;
+ chip_number++) {
base_addr =
true_base_addr + (cy_chip_offset[chip_number] << index);
mdelay(1);
@@ -4555,12 +4557,11 @@
/* scan the address table probing for Cyclom-Y/ISA boards */
for (i = 0; i < NR_ISA_ADDRS; i++) {
unsigned int isa_address = cy_isa_addresses[i];
- if (isa_address == 0x0000) {
+ if (isa_address == 0x0000)
return nboard;
- }
/* probe for CD1400... */
- cy_isa_address = ioremap(isa_address, CyISA_Ywin);
+ cy_isa_address = ioremap_nocache(isa_address, CyISA_Ywin);
if (cy_isa_address == NULL) {
printk(KERN_ERR "Cyclom-Y/ISA: can't remap base "
"address\n");
@@ -4847,12 +4848,10 @@
if (mailbox != 0) {
/* set window to last 512K of RAM */
cy_writel(&ctl_addr->loc_addr_base, WIN_RAM + RAM_SIZE);
- //sleep(1);
for (tmp = base_addr; tmp < base_addr + RAM_SIZE; tmp++)
cy_writeb(tmp, 255);
/* set window to beginning of RAM */
cy_writel(&ctl_addr->loc_addr_base, WIN_RAM);
- //sleep(1);
}
retval = __cyz_load_fw(fw, "Cyclom-Z", mailbox, base_addr, NULL);
@@ -5382,7 +5381,8 @@
del_timer_sync(&cyz_timerlist);
#endif /* CONFIG_CYZ_INTR */
- if ((e1 = tty_unregister_driver(cy_serial_driver)))
+ e1 = tty_unregister_driver(cy_serial_driver);
+ if (e1)
printk(KERN_ERR "failed to unregister Cyclades serial "
"driver(%d)\n", e1);
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index ecee354..213b3ca 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -160,7 +160,7 @@
* \param arg arguments
*/
#define DRM_ERROR(fmt, arg...) \
- printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __FUNCTION__ , ##arg)
+ printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __func__ , ##arg)
/**
* Memory error output.
@@ -170,7 +170,7 @@
* \param arg arguments
*/
#define DRM_MEM_ERROR(area, fmt, arg...) \
- printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __FUNCTION__, \
+ printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __func__, \
drm_mem_stats[area].name , ##arg)
#define DRM_INFO(fmt, arg...) printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
@@ -187,7 +187,7 @@
if ( drm_debug ) \
printk(KERN_DEBUG \
"[" DRM_NAME ":%s] " fmt , \
- __FUNCTION__ , ##arg); \
+ __func__ , ##arg); \
} while (0)
#else
#define DRM_DEBUG(fmt, arg...) do { } while (0)
@@ -238,7 +238,7 @@
if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || \
dev->lock.file_priv != file_priv ) { \
DRM_ERROR( "%s called without lock held, held %d owner %p %p\n",\
- __FUNCTION__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
+ __func__, _DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ),\
dev->lock.file_priv, file_priv ); \
return -EINVAL; \
} \
diff --git a/drivers/char/drm/drm_sysfs.c b/drivers/char/drm/drm_sysfs.c
index 7a1d9a7..9a32169 100644
--- a/drivers/char/drm/drm_sysfs.c
+++ b/drivers/char/drm/drm_sysfs.c
@@ -34,7 +34,7 @@
struct drm_minor *drm_minor = to_drm_minor(dev);
struct drm_device *drm_dev = drm_minor->dev;
- printk(KERN_ERR "%s\n", __FUNCTION__);
+ printk(KERN_ERR "%s\n", __func__);
if (drm_dev->driver->suspend)
return drm_dev->driver->suspend(drm_dev, state);
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 60c9376..a86ab30 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -692,7 +692,7 @@
drm_i830_sarea_t *sarea_priv = dev_priv->sarea_priv;
unsigned int dirty = sarea_priv->dirty;
- DRM_DEBUG("%s %x\n", __FUNCTION__, dirty);
+ DRM_DEBUG("%s %x\n", __func__, dirty);
if (dirty & I830_UPLOAD_BUFFERS) {
i830EmitDestVerified(dev, sarea_priv->BufferState);
@@ -1043,7 +1043,7 @@
RING_LOCALS;
DRM_DEBUG("%s: page=%d pfCurrentPage=%d\n",
- __FUNCTION__,
+ __func__,
dev_priv->current_page,
dev_priv->sarea_priv->pf_current_page);
@@ -1206,7 +1206,7 @@
OUT_RING(0);
ADVANCE_LP_RING();
- i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
}
static int i830_flush_queue(struct drm_device * dev)
@@ -1223,7 +1223,7 @@
OUT_RING(0);
ADVANCE_LP_RING();
- i830_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ i830_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
for (i = 0; i < dma->buf_count; i++) {
struct drm_buf *buf = dma->buflist[i];
@@ -1344,7 +1344,7 @@
{
drm_i830_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
dev_priv->page_flipping = 1;
dev_priv->current_page = 0;
dev_priv->sarea_priv->pf_current_page = dev_priv->current_page;
@@ -1354,7 +1354,7 @@
{
drm_i830_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
if (dev_priv->current_page != 0)
i830_dma_dispatch_flip(dev);
@@ -1367,7 +1367,7 @@
{
drm_i830_private_t *dev_priv = dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
LOCK_TEST_WITH_RETURN(dev, file_priv);
@@ -1437,7 +1437,7 @@
int value;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
@@ -1464,7 +1464,7 @@
drm_i830_setparam_t *param = data;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index 4caba8c..b5bf8cc 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -158,7 +158,7 @@
if (I830_VERBOSE) \
printk("BEGIN_LP_RING(%d)\n", (n)); \
if (dev_priv->ring.space < n*4) \
- i830_wait_ring(dev, n*4, __FUNCTION__); \
+ i830_wait_ring(dev, n*4, __func__); \
outcount = 0; \
outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \
diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c
index a33db5f..91ec2bb 100644
--- a/drivers/char/drm/i830_irq.c
+++ b/drivers/char/drm/i830_irq.c
@@ -58,7 +58,7 @@
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
atomic_inc(&dev_priv->irq_emitted);
@@ -77,7 +77,7 @@
unsigned long end = jiffies + HZ * 3;
int ret = 0;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
if (atomic_read(&dev_priv->irq_received) >= irq_nr)
return 0;
@@ -124,7 +124,7 @@
LOCK_TEST_WITH_RETURN(dev, file_priv);
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
@@ -147,7 +147,7 @@
drm_i830_irq_wait_t *irqwait = data;
if (!dev_priv) {
- DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ DRM_ERROR("%s called with no initialization\n", __func__);
return -EINVAL;
}
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index ef7bf14..f47e46e 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -194,7 +194,7 @@
{
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
- DRM_DEBUG("%s\n", __FUNCTION__);
+ DRM_DEBUG("%s\n", __func__);
if (!dev_priv->sarea) {
DRM_ERROR("can not find sarea!\n");
@@ -609,7 +609,7 @@
drm_i915_private_t *dev_priv = dev->dev_private;
i915_kernel_lost_context(dev);
- return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
+ return i915_wait_ring(dev, dev_priv->ring.Size - 8, __func__);
}
static int i915_flush_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index c614d78..db7001f 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -272,7 +272,7 @@
if (I915_VERBOSE) \
DRM_DEBUG("BEGIN_LP_RING(%d)\n", (n)); \
if (dev_priv->ring.space < (n)*4) \
- i915_wait_ring(dev, (n)*4, __FUNCTION__); \
+ i915_wait_ring(dev, (n)*4, __func__); \
outcount = 0; \
outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 9072e4a..f6f6c92 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -894,7 +894,7 @@
#if RADEON_FIFO_DEBUG
static void radeon_status(drm_radeon_private_t * dev_priv)
{
- printk("%s:\n", __FUNCTION__);
+ printk("%s:\n", __func__);
printk("RBBM_STATUS = 0x%08x\n",
(unsigned int)RADEON_READ(RADEON_RBBM_STATUS));
printk("CP_RB_RTPR = 0x%08x\n",
diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c
index 59146e3..ea35ab2 100644
--- a/drivers/char/ds1286.c
+++ b/drivers/char/ds1286.c
@@ -39,6 +39,7 @@
#include <linux/spinlock.h>
#include <linux/bcd.h>
#include <linux/proc_fs.h>
+#include <linux/jiffies.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -451,7 +452,7 @@
*/
if (ds1286_is_updating() != 0)
- while (jiffies - uip_watchdog < 2*HZ/100)
+ while (time_before(jiffies, uip_watchdog + 2*HZ/100))
barrier();
/*
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index ffd747c..60a4df7 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -38,8 +38,8 @@
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
#include "digiPCI.h"
@@ -73,7 +73,8 @@
*/
static DEFINE_SPINLOCK(epca_lock);
-/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted to 7 below. */
+/* MAXBOARDS is typically 12, but ISA and EISA cards are restricted
+ to 7 below. */
static struct board_info boards[MAXBOARDS];
static struct tty_driver *pc_driver;
@@ -157,13 +158,12 @@
static void pc_close(struct tty_struct *, struct file *);
static void shutdown(struct channel *);
static void pc_hangup(struct tty_struct *);
-static void pc_put_char(struct tty_struct *, unsigned char);
static int pc_write_room(struct tty_struct *);
static int pc_chars_in_buffer(struct tty_struct *);
static void pc_flush_buffer(struct tty_struct *);
static void pc_flush_chars(struct tty_struct *);
static int block_til_ready(struct tty_struct *, struct file *,
- struct channel *);
+ struct channel *);
static int pc_open(struct tty_struct *, struct file *);
static void post_fep_init(unsigned int crd);
static void epcapoll(unsigned long);
@@ -175,18 +175,18 @@
static void epcaparam(struct tty_struct *, struct channel *);
static void receive_data(struct channel *);
static int pc_ioctl(struct tty_struct *, struct file *,
- unsigned int, unsigned long);
+ unsigned int, unsigned long);
static int info_ioctl(struct tty_struct *, struct file *,
- unsigned int, unsigned long);
+ unsigned int, unsigned long);
static void pc_set_termios(struct tty_struct *, struct ktermios *);
static void do_softint(struct work_struct *work);
static void pc_stop(struct tty_struct *);
static void pc_start(struct tty_struct *);
-static void pc_throttle(struct tty_struct * tty);
+static void pc_throttle(struct tty_struct *tty);
static void pc_unthrottle(struct tty_struct *tty);
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 *);
+static void epca_setup(char *, int *);
static int pc_write(struct tty_struct *, const unsigned char *, int);
static int pc_init(void);
@@ -243,7 +243,7 @@
/* PCXEM windowing is the same as that used in the PCXR and CX series cards. */
static void pcxem_memwinon(struct board_info *b, unsigned int win)
{
- outb_p(FEPWIN|win, b->port + 1);
+ outb_p(FEPWIN | win, b->port + 1);
}
static void pcxem_memwinoff(struct board_info *b, unsigned int win)
@@ -253,7 +253,7 @@
static void pcxem_globalwinon(struct channel *ch)
{
- outb_p( FEPWIN, (int)ch->board->port + 1);
+ outb_p(FEPWIN, (int)ch->board->port + 1);
}
static void pcxem_rxwinon(struct channel *ch)
@@ -394,7 +394,7 @@
*/
if (tty) {
struct channel *ch = (struct channel *)tty->driver_data;
- if ((ch >= &digi_channels[0]) && (ch < &digi_channels[nbdevs])) {
+ if (ch >= &digi_channels[0] && ch < &digi_channels[nbdevs]) {
if (ch->magic == EPCA_MAGIC)
return ch;
}
@@ -414,7 +414,7 @@
static void epca_error(int line, char *msg)
{
- printk(KERN_ERR "epca_error (Digi): line = %d %s\n",line,msg);
+ printk(KERN_ERR "epca_error (Digi): line = %d %s\n", line, msg);
}
static void pc_close(struct tty_struct *tty, struct file *filp)
@@ -425,7 +425,8 @@
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
if (tty_hung_up_p(filp)) {
spin_unlock_irqrestore(&epca_lock, flags);
@@ -440,7 +441,6 @@
spin_unlock_irqrestore(&epca_lock, flags);
return;
}
-
/* Port open only once go ahead with shutdown & reset */
BUG_ON(ch->count < 0);
@@ -455,12 +455,13 @@
spin_unlock_irqrestore(&epca_lock, flags);
if (ch->asyncflags & ASYNC_INITIALIZED) {
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the
+ transmit buffer empties */
setup_empty_event(tty, ch);
- tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
+ /* 30 seconds timeout */
+ tty_wait_until_sent(tty, 3000);
}
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ pc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
@@ -477,7 +478,7 @@
wake_up_interruptible(&ch->open_wait);
}
ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED |
- ASYNC_CLOSING);
+ ASYNC_CLOSING);
wake_up_interruptible(&ch->close_wait);
}
}
@@ -524,16 +525,15 @@
static void pc_hangup(struct tty_struct *tty)
{
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) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
unsigned long flags;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ pc_flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(ch);
@@ -548,7 +548,7 @@
}
static int pc_write(struct tty_struct *tty,
- const unsigned char *buf, int bytesAvailable)
+ const unsigned char *buf, int bytesAvailable)
{
unsigned int head, tail;
int dataLen;
@@ -572,7 +572,8 @@
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) == NULL)
+ ch = verifyChannel(tty);
+ if (ch == NULL)
return 0;
/* Make a pointer to the channel data structure found on the board. */
@@ -645,26 +646,19 @@
return amountCopied;
}
-static void pc_put_char(struct tty_struct *tty, unsigned char c)
-{
- pc_write(tty, &c, 1);
-}
-
static int pc_write_room(struct tty_struct *tty)
{
- int remain;
+ int remain = 0;
struct channel *ch;
unsigned long flags;
unsigned int head, tail;
struct board_chan __iomem *bc;
-
- remain = 0;
-
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
@@ -676,8 +670,8 @@
tail = readw(&bc->tout);
/* Wrap tail if necessary */
tail &= (ch->txbufsize - 1);
-
- if ((remain = tail - head - 1) < 0 )
+ remain = tail - head - 1;
+ if (remain < 0)
remain += ch->txbufsize;
if (remain && (ch->statusflags & LOWWAIT) == 0) {
@@ -699,12 +693,12 @@
unsigned long flags;
struct channel *ch;
struct board_chan __iomem *bc;
-
/*
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) == NULL)
+ ch = verifyChannel(tty);
+ if (ch == NULL)
return 0;
spin_lock_irqsave(&epca_lock, flags);
@@ -715,7 +709,8 @@
head = readw(&bc->tin);
ctail = readw(&ch->mailbox->cout);
- if (tail == head && readw(&ch->mailbox->cin) == ctail && readb(&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 = readw(&bc->tin) & (ch->txbufsize - 1);
@@ -725,7 +720,8 @@
* 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 = tail - head - 1;
+ if (remain < 0)
remain += ch->txbufsize;
chars = (int)(ch->txbufsize - remain);
/*
@@ -736,7 +732,7 @@
* transmit buffer empties.
*/
if (!(ch->statusflags & EMPTYWAIT))
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
} /* End if some space on the card has been used */
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
@@ -754,7 +750,8 @@
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) == NULL)
+ ch = verifyChannel(tty);
+ if (ch == NULL)
return;
spin_lock_irqsave(&epca_lock, flags);
@@ -775,23 +772,25 @@
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
unsigned long flags;
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);
+ if ((ch->statusflags & TXBUSY) &&
+ !(ch->statusflags & EMPTYWAIT))
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
}
}
static int block_til_ready(struct tty_struct *tty,
- struct file *filp, struct channel *ch)
+ struct file *filp, struct channel *ch)
{
- DECLARE_WAITQUEUE(wait,current);
+ DECLARE_WAITQUEUE(wait, current);
int retval, do_clocal = 0;
unsigned long flags;
@@ -839,8 +838,7 @@
while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (tty_hung_up_p(filp) ||
- !(ch->asyncflags & ASYNC_INITIALIZED))
- {
+ !(ch->asyncflags & ASYNC_INITIALIZED)) {
if (ch->asyncflags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
@@ -880,7 +878,7 @@
return 0;
}
-static int pc_open(struct tty_struct *tty, struct file * filp)
+static int pc_open(struct tty_struct *tty, struct file *filp)
{
struct channel *ch;
unsigned long flags;
@@ -923,7 +921,8 @@
return(-ENODEV);
}
- if ((bc = ch->brdchan) == 0) {
+ bc = ch->brdchan;
+ if (bc == NULL) {
tty->driver_data = NULL;
return -ENODEV;
}
@@ -964,7 +963,7 @@
* The below routine generally sets up parity, baud, flow control
* issues, etc.... It effect both control flags and input flags.
*/
- epcaparam(tty,ch);
+ epcaparam(tty, ch);
ch->asyncflags |= ASYNC_INITIALIZED;
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
@@ -1002,8 +1001,8 @@
del_timer_sync(&epca_timer);
- if (tty_unregister_driver(pc_driver) || tty_unregister_driver(pc_info))
- {
+ if (tty_unregister_driver(pc_driver) ||
+ tty_unregister_driver(pc_info)) {
printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");
return;
}
@@ -1034,7 +1033,6 @@
.flush_buffer = pc_flush_buffer,
.chars_in_buffer = pc_chars_in_buffer,
.flush_chars = pc_flush_chars,
- .put_char = pc_put_char,
.ioctl = pc_ioctl,
.set_termios = pc_set_termios,
.stop = pc_stop,
@@ -1044,7 +1042,7 @@
.hangup = pc_hangup,
};
-static int info_open(struct tty_struct *tty, struct file * filp)
+static int info_open(struct tty_struct *tty, struct file *filp)
{
return 0;
}
@@ -1099,7 +1097,7 @@
* Set up interrupt, we will worry about memory allocation in
* post_fep_init.
*/
- printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);
+ printk(KERN_INFO "DIGI epca driver version %s loaded.\n", VERSION);
/*
* NOTE : This code assumes that the number of ports found in the
@@ -1252,7 +1250,7 @@
if ((board_id & 0x30) == 0x30)
bd->memory_seg = 0x8000;
} else
- printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);
+ printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n", (int)bd->port);
break;
}
}
@@ -1326,12 +1324,12 @@
*/
/* 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");
+ epcaassert(bd->numports <= 64, "PCI returned a invalid number of ports");
nbdevs += (bd->numports);
} else {
/* Fix up the mappings for ISA/EISA etc */
/* FIXME: 64K - can we be smarter ? */
- bd->re_map_membase = ioremap(bd->membase, 0x10000);
+ bd->re_map_membase = ioremap_nocache(bd->membase, 0x10000);
}
if (crd != 0)
@@ -1362,7 +1360,8 @@
* 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) && (readw(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]))
@@ -1461,10 +1460,12 @@
case PCXEVE:
case PCXE:
- ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4) & 0x1fff);
+ ch->txptr = memaddr + (((tseg - bd->memory_seg) << 4)
+ & 0x1fff);
ch->txwin = FEPWIN | ((tseg - bd->memory_seg) >> 9);
- ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4) & 0x1fff);
- ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >>9 );
+ ch->rxptr = memaddr + (((rseg - bd->memory_seg) << 4)
+ & 0x1fff);
+ ch->rxwin = FEPWIN | ((rseg - bd->memory_seg) >> 9);
break;
case PCXI:
@@ -1518,8 +1519,9 @@
}
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);
+ "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);
memwinoff(bd, 0);
}
@@ -1527,7 +1529,7 @@
{
unsigned long flags;
int crd;
- volatile unsigned int head, tail;
+ unsigned int head, tail;
struct channel *ch;
struct board_info *bd;
@@ -1593,7 +1595,9 @@
chan0 = card_ptr[crd];
epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");
assertgwinon(chan0);
- while ((tail = readw(&chan0->mailbox->eout)) != (head = readw(&chan0->mailbox->ein))) { /* Begin while something in event queue */
+ while ((tail = readw(&chan0->mailbox->eout)) !=
+ (head = readw(&chan0->mailbox->ein))) {
+ /* Begin while something in event queue */
assertgwinon(chan0);
eventbuf = bd->re_map_membase + tail + ISTART;
/* Get the channel the event occurred on */
@@ -1617,7 +1621,8 @@
goto next;
}
- if ((bc = ch->brdchan) == NULL)
+ bc = ch->brdchan;
+ if (bc == NULL)
goto next;
if (event & DATA_IND) { /* Begin DATA_IND */
@@ -1629,10 +1634,11 @@
/* A modem signal change has been indicated */
ch->imodem = mstat;
if (ch->asyncflags & ASYNC_CHECK_CD) {
- if (mstat & ch->dcd) /* We are now receiving dcd */
+ /* We are now receiving dcd */
+ if (mstat & ch->dcd)
wake_up_interruptible(&ch->open_wait);
- else
- pc_sched_event(ch, EPCA_EVENT_HANGUP); /* No dcd; hangup */
+ else /* No dcd; hangup */
+ pc_sched_event(ch, EPCA_EVENT_HANGUP);
}
}
tty = ch->tty;
@@ -1647,7 +1653,8 @@
tty_wakeup(tty);
}
} else if (event & EMPTYTX_IND) {
- /* This event is generated by setup_empty_event */
+ /* This event is generated by
+ setup_empty_event */
ch->statusflags &= ~TXBUSY;
if (ch->statusflags & EMPTYWAIT) {
ch->statusflags &= ~EMPTYWAIT;
@@ -1655,7 +1662,7 @@
}
}
}
- next:
+next:
globalwinon(ch);
BUG_ON(!bc);
writew(1, &bc->idata);
@@ -1665,7 +1672,7 @@
}
static void fepcmd(struct channel *ch, int cmd, int word_or_byte,
- int byte2, int ncmds, int bytecmd)
+ int byte2, int ncmds, int bytecmd)
{
unchar __iomem *memaddr;
unsigned int head, cmdTail, cmdStart, cmdMax;
@@ -1690,8 +1697,10 @@
memaddr = ch->board->re_map_membase;
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);
+ 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) {
@@ -1770,7 +1779,7 @@
static unsigned termios2digi_i(struct channel *ch, unsigned iflag)
{
unsigned res = iflag & (IGNBRK | BRKINT | IGNPAR | PARMRK |
- INPCK | ISTRIP|IXON|IXANY|IXOFF);
+ INPCK | ISTRIP | IXON | IXANY | IXOFF);
if (ch->digiext.digi_flags & DIGI_AIXON)
res |= IAIXON;
return res;
@@ -1838,7 +1847,7 @@
unsigned mval, hflow, cflag, iflag;
bc = ch->brdchan;
- epcaassert(bc !=0, "bc out of range");
+ epcaassert(bc != NULL, "bc out of range");
assertgwinon(ch);
ts = tty->termios;
@@ -1884,8 +1893,10 @@
* 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
*/
- /* break handling, parity handling, input stripping, flow control chars */
fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);
}
/*
@@ -1981,7 +1992,7 @@
return;
/* 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)) {
writew(head, &bc->rout);
return;
}
@@ -1991,18 +2002,21 @@
if (readb(&bc->orun)) {
writeb(0, &bc->orun);
- printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",tty->name);
+ printk(KERN_WARNING "epca; overrun! DigiBoard device %s\n",
+ tty->name);
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
}
rxwinon(ch);
- 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;
+ dataToRead = (wrapgap < bytesAvailable) ? wrapgap
+ : bytesAvailable;
/* Make sure we don't overflow the buffer */
dataToRead = tty_prepare_flip_string(tty, &rptr, dataToRead);
if (dataToRead == 0)
@@ -2153,14 +2167,14 @@
* The below routine generally sets up parity, baud, flow control
* issues, etc.... It effect both control flags and input flags.
*/
- epcaparam(tty,ch);
+ epcaparam(tty, ch);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
return 0;
}
-static int pc_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
+static int pc_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
digiflow_t dflow;
int retval;
@@ -2175,7 +2189,6 @@
bc = ch->brdchan;
else
return -EINVAL;
-
/*
* For POSIX compliance we need to add more ioctls. See tty_ioctl.c in
* /usr/src/linux/drivers/char for a good example. In particular think
@@ -2186,9 +2199,10 @@
retval = tty_check_change(tty);
if (retval)
return retval;
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the transmit
+ buffer empties */
spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
if (!arg)
@@ -2198,29 +2212,14 @@
retval = tty_check_change(tty);
if (retval)
return retval;
-
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the transmit buffer
+ empties */
spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
+ 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;
-
- if (get_user(value, (unsigned __user *)argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (value ? CLOCAL : 0));
- return 0;
- }
case TIOCMODG:
mflag = pc_tiocmget(tty, file);
if (put_user(mflag, (unsigned long __user *)argp))
@@ -2253,10 +2252,12 @@
break;
case DIGI_SETAW:
case DIGI_SETAF:
+ lock_kernel();
if (cmd == DIGI_SETAW) {
- /* Setup an event to indicate when the transmit buffer empties */
+ /* Setup an event to indicate when the transmit
+ buffer empties */
spin_lock_irqsave(&epca_lock, flags);
- setup_empty_event(tty,ch);
+ setup_empty_event(tty, ch);
spin_unlock_irqrestore(&epca_lock, flags);
tty_wait_until_sent(tty, 0);
} else {
@@ -2264,6 +2265,7 @@
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
}
+ unlock_kernel();
/* Fall Thru */
case DIGI_SETA:
if (copy_from_user(&ch->digiext, argp, sizeof(digi_t)))
@@ -2285,7 +2287,7 @@
* control issues, etc.... It effect both control flags and
* input flags.
*/
- epcaparam(tty,ch);
+ epcaparam(tty, ch);
memoff(ch);
spin_unlock_irqrestore(&epca_lock, flags);
break;
@@ -2321,18 +2323,21 @@
if (copy_from_user(&dflow, argp, sizeof(dflow)))
return -EFAULT;
- if (dflow.startc != startc || dflow.stopc != stopc) { /* Begin if setflow toggled */
+ if (dflow.startc != startc || dflow.stopc != stopc) {
+ /* Begin if setflow toggled */
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
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);
+ fepcmd(ch, SONOFFC, ch->fepstartc,
+ ch->fepstopc, 0, 1);
} else {
ch->fepstartca = ch->startca = dflow.startc;
ch->fepstopca = ch->stopca = dflow.stopc;
- fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);
+ fepcmd(ch, SAUXONOFFC, ch->fepstartca,
+ ch->fepstopca, 0, 1);
}
if (ch->statusflags & TXSTOPPED)
@@ -2356,7 +2361,9 @@
* 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 */
+ ch = verifyChannel(tty);
+
+ if (ch != NULL) { /* Begin if channel valid */
spin_lock_irqsave(&epca_lock, flags);
globalwinon(ch);
epcaparam(tty, ch);
@@ -2383,7 +2390,7 @@
if (tty && tty->driver_data) {
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
- tty_hangup(tty); /* FIXME: module removal race here - AKPM */
+ tty_hangup(tty);
wake_up_interruptible(&ch->open_wait);
ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
}
@@ -2403,9 +2410,11 @@
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
- if ((ch->statusflags & TXSTOPPED) == 0) { /* Begin if transmit stop requested */
+ if ((ch->statusflags & TXSTOPPED) == 0) {
+ /* Begin if transmit stop requested */
globalwinon(ch);
/* STOP transmitting now !! */
fepcmd(ch, PAUSETX, 0, 0, 0, 0);
@@ -2423,11 +2432,14 @@
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
unsigned long flags;
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 */
+ /* Just in case output was resumed because of a change
+ in Digi-flow */
+ if (ch->statusflags & TXSTOPPED) {
+ /* Begin transmit resume requested */
struct board_chan __iomem *bc;
globalwinon(ch);
bc = ch->brdchan;
@@ -2457,7 +2469,8 @@
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
spin_lock_irqsave(&epca_lock, flags);
if ((ch->statusflags & RXSTOPPED) == 0) {
globalwinon(ch);
@@ -2477,8 +2490,10 @@
* verifyChannel returns the channel from the tty struct if it is
* valid. This serves as a sanity check.
*/
- if ((ch = verifyChannel(tty)) != NULL) {
- /* Just in case output was resumed because of a change in Digi-flow */
+ ch = verifyChannel(tty);
+ if (ch != NULL) {
+ /* Just in case output was resumed because of a change
+ in Digi-flow */
spin_lock_irqsave(&epca_lock, flags);
if (ch->statusflags & RXSTOPPED) {
globalwinon(ch);
@@ -2490,7 +2505,7 @@
}
}
-void digi_send_break(struct channel *ch, int msec)
+static void digi_send_break(struct channel *ch, int msec)
{
unsigned long flags;
@@ -2523,7 +2538,7 @@
memoff(ch);
}
-void epca_setup(char *str, int *ints)
+static void epca_setup(char *str, int *ints)
{
struct board_info board;
int index, loop, last;
@@ -2552,14 +2567,16 @@
* 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 "epca_setup: Invalid board status 0x%x\n", board.status);
+ printk(KERN_ERR "epca_setup: Invalid board status 0x%x\n",
+ board.status);
invalid_lilo_config = 1;
setup_error_code |= INVALID_BOARD_STATUS;
return;
@@ -2613,7 +2630,8 @@
case 6:
board.membase = ints[index];
if (ints[index] <= 0) {
- printk(KERN_ERR "epca_setup: Invalid memory base 0x%x\n",(unsigned int)board.membase);
+ 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;
@@ -2744,7 +2762,7 @@
t2++;
if (*t2) {
- printk(KERN_ERR "epca_setup: Invalid memory base %s\n",str);
+ printk(KERN_ERR "epca_setup: Invalid memory base %s\n", str);
invalid_lilo_config = 1;
setup_error_code |= INVALID_MEM_BASE;
return;
@@ -2766,7 +2784,7 @@
/* I should REALLY validate the stuff here */
/* Copies our local copy of board into boards */
- memcpy((void *)&boards[num_cards],(void *)&board, sizeof(board));
+ 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],
@@ -2807,9 +2825,9 @@
if (board_idx >= MAXBOARDS)
goto err_out;
- addr = pci_resource_start (pdev, epca_info_tbl[info_idx].bar_idx);
+ addr = pci_resource_start(pdev, epca_info_tbl[info_idx].bar_idx);
if (!addr) {
- printk (KERN_ERR PFX "PCI region #%d not available (size 0)\n",
+ printk(KERN_ERR PFX "PCI region #%d not available (size 0)\n",
epca_info_tbl[info_idx].bar_idx);
goto err_out;
}
@@ -2820,28 +2838,29 @@
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",
+ if (!request_mem_region(addr + PCI_IO_OFFSET, 0x200000, "epca")) {
+ printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
0x200000, addr + PCI_IO_OFFSET);
goto err_out;
}
- boards[board_idx].re_map_port = ioremap(addr + PCI_IO_OFFSET, 0x200000);
+ boards[board_idx].re_map_port = ioremap_nocache(addr + PCI_IO_OFFSET,
+ 0x200000);
if (!boards[board_idx].re_map_port) {
- printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
+ printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
0x200000, addr + PCI_IO_OFFSET);
goto err_out_free_pciio;
}
- if (!request_mem_region (addr, 0x200000, "epca")) {
- printk (KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
+ if (!request_mem_region(addr, 0x200000, "epca")) {
+ printk(KERN_ERR PFX "resource 0x%x @ 0x%lx unavailable\n",
0x200000, addr);
goto err_out_free_iounmap;
}
- boards[board_idx].re_map_membase = ioremap(addr, 0x200000);
+ boards[board_idx].re_map_membase = ioremap_nocache(addr, 0x200000);
if (!boards[board_idx].re_map_membase) {
- printk (KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
+ printk(KERN_ERR PFX "cannot map 0x%x @ 0x%lx\n",
0x200000, addr + PCI_IO_OFFSET);
goto err_out_free_memregion;
}
@@ -2858,11 +2877,11 @@
return 0;
err_out_free_memregion:
- release_mem_region (addr, 0x200000);
+ release_mem_region(addr, 0x200000);
err_out_free_iounmap:
- iounmap (boards[board_idx].re_map_port);
+ iounmap(boards[board_idx].re_map_port);
err_out_free_pciio:
- release_mem_region (addr + PCI_IO_OFFSET, 0x200000);
+ release_mem_region(addr + PCI_IO_OFFSET, 0x200000);
err_out:
return -ENODEV;
}
@@ -2878,9 +2897,9 @@
MODULE_DEVICE_TABLE(pci, epca_pci_tbl);
-int __init init_PCI (void)
+static int __init init_PCI(void)
{
- memset (&epca_driver, 0, sizeof (epca_driver));
+ memset(&epca_driver, 0, sizeof(epca_driver));
epca_driver.name = "epca";
epca_driver.id_table = epca_pci_tbl;
epca_driver.probe = epca_init_one;
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index f3fe620..84840ba 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -8,7 +8,7 @@
* Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now
* much more extensible to support other serial cards based on the
* 16450/16550A UART's. Added support for the AST FourPort and the
- * Accent Async board.
+ * Accent Async board.
*
* set_serial_info fixed to set the flags, custom divisor, and uart
* type fields. Fix suggested by Michael K. Johnson 12/12/92.
@@ -61,11 +61,11 @@
#include <linux/bitops.h>
#include <asm/system.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/dma.h>
#include <linux/slab.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/hayesesp.h>
@@ -127,8 +127,10 @@
#undef SERIAL_DEBUG_FLOW
#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- tty->name, (info->flags), serial_driver.refcount,info->count,tty->count,s)
+#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ tty->name, info->flags, \
+ serial_driver.refcount, \
+ info->count, tty->count, s)
#else
#define DBG_CNT(s)
#endif
@@ -189,7 +191,7 @@
*/
static void rs_stop(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_stop"))
@@ -206,12 +208,12 @@
static void rs_start(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_start"))
return;
-
+
spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
info->IER |= UART_IER_THRI;
@@ -233,7 +235,7 @@
* rs_interrupt() should try to keep the interrupt handler as fast as
* possible. After you are done making modifications, it is not a bad
* idea to do:
- *
+ *
* gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
*
* and look at the resulting assemble code in serial.s.
@@ -290,7 +292,7 @@
}
status_mask = (info->read_status_mask >> 2) & 0x07;
-
+
for (i = 0; i < num_bytes - 1; i += 2) {
*((unsigned short *)(pio_buf->data + i)) =
inw(info->port + UART_ESI_RX);
@@ -325,8 +327,7 @@
flag = TTY_BREAK;
if (info->flags & ASYNC_SAK)
do_SAK(tty);
- }
- else if (err_buf->data[i] & 0x02)
+ } else if (err_buf->data[i] & 0x02)
flag = TTY_FRAME;
else if (err_buf->data[i] & 0x01)
flag = TTY_PARITY;
@@ -341,23 +342,29 @@
release_pio_buffer(err_buf);
}
-static inline void receive_chars_dma(struct esp_struct *info, int num_bytes)
+static void program_isa_dma(int dma, int dir, unsigned long addr, int len)
{
unsigned long flags;
+
+ flags = claim_dma_lock();
+ disable_dma(dma);
+ clear_dma_ff(dma);
+ set_dma_mode(dma, dir);
+ set_dma_addr(dma, addr);
+ set_dma_count(dma, len);
+ enable_dma(dma);
+ release_dma_lock(flags);
+}
+
+static void receive_chars_dma(struct esp_struct *info, int num_bytes)
+{
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
dma_bytes = num_bytes;
info->stat_flags |= ESP_STAT_DMA_RX;
-
- flags=claim_dma_lock();
- disable_dma(dma);
- clear_dma_ff(dma);
- set_dma_mode(dma, DMA_MODE_READ);
- set_dma_addr(dma, isa_virt_to_bus(dma_buffer));
- set_dma_count(dma, dma_bytes);
- enable_dma(dma);
- release_dma_lock(flags);
-
- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
+
+ program_isa_dma(dma, DMA_MODE_READ, isa_virt_to_bus(dma_buffer),
+ dma_bytes);
+ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX);
}
static inline void receive_chars_dma_done(struct esp_struct *info,
@@ -366,22 +373,22 @@
struct tty_struct *tty = info->tty;
int num_bytes;
unsigned long flags;
-
- flags=claim_dma_lock();
+
+ flags = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
info->stat_flags &= ~ESP_STAT_DMA_RX;
num_bytes = dma_bytes - get_dma_residue(dma);
release_dma_lock(flags);
-
+
info->icount.rx += num_bytes;
if (num_bytes > 0) {
tty_insert_flip_string(tty, dma_buffer, num_bytes - 1);
status &= (0x1c & info->read_status_mask);
-
+
/* Is the status significant or do we throw the last byte ? */
if (!(status & info->ignore_status_mask)) {
int statflag = 0;
@@ -393,13 +400,13 @@
do_SAK(tty);
} else if (status & 0x08) {
statflag = TTY_FRAME;
- (info->icount.frame)++;
- }
- else if (status & 0x04) {
+ info->icount.frame++;
+ } else if (status & 0x04) {
statflag = TTY_PARITY;
- (info->icount.parity)++;
+ info->icount.parity++;
}
- tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag);
+ tty_insert_flip_char(tty, dma_buffer[num_bytes - 1],
+ statflag);
}
tty_schedule_flip(tty);
}
@@ -484,8 +491,6 @@
/* Caller must hold info->lock */
static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes)
{
- unsigned long flags;
-
dma_bytes = num_bytes;
if (info->xmit_tail + dma_bytes <= ESP_XMIT_SIZE) {
@@ -517,26 +522,18 @@
}
info->stat_flags |= ESP_STAT_DMA_TX;
-
- flags=claim_dma_lock();
- disable_dma(dma);
- clear_dma_ff(dma);
- set_dma_mode(dma, DMA_MODE_WRITE);
- set_dma_addr(dma, isa_virt_to_bus(dma_buffer));
- set_dma_count(dma, dma_bytes);
- enable_dma(dma);
- release_dma_lock(flags);
-
- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
+
+ program_isa_dma(dma, DMA_MODE_WRITE, isa_virt_to_bus(dma_buffer),
+ dma_bytes);
+ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
}
static inline void transmit_chars_dma_done(struct esp_struct *info)
{
int num_bytes;
unsigned long flags;
-
- flags=claim_dma_lock();
+ flags = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
@@ -547,27 +544,21 @@
if (dma_bytes != num_bytes) {
dma_bytes -= num_bytes;
memmove(dma_buffer, dma_buffer + num_bytes, dma_bytes);
-
- flags=claim_dma_lock();
- disable_dma(dma);
- clear_dma_ff(dma);
- set_dma_mode(dma, DMA_MODE_WRITE);
- set_dma_addr(dma, isa_virt_to_bus(dma_buffer));
- set_dma_count(dma, dma_bytes);
- enable_dma(dma);
- release_dma_lock(flags);
-
- serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
+
+ program_isa_dma(dma, DMA_MODE_WRITE,
+ isa_virt_to_bus(dma_buffer), dma_bytes);
+
+ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX);
} else {
dma_bytes = 0;
info->stat_flags &= ~ESP_STAT_DMA_TX;
}
}
-static inline void check_modem_status(struct esp_struct *info)
+static void check_modem_status(struct esp_struct *info)
{
int status;
-
+
serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT);
status = serial_in(info, UART_ESI_STAT2);
@@ -588,7 +579,7 @@
#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
printk("ttys%d CD now %s...", info->line,
(status & UART_MSR_DCD) ? "on" : "off");
-#endif
+#endif
if (status & UART_MSR_DCD)
wake_up_interruptible(&info->open_wait);
else {
@@ -605,7 +596,7 @@
*/
static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
{
- struct esp_struct * info;
+ struct esp_struct *info;
unsigned err_status;
unsigned int scratch;
@@ -617,7 +608,7 @@
scratch = serial_in(info, UART_ESI_SID);
spin_lock(&info->lock);
-
+
if (!info->tty) {
spin_unlock(&info->lock);
return IRQ_NONE;
@@ -637,7 +628,7 @@
if (err_status & 0x80) /* Start break */
wake_up_interruptible(&info->break_wait);
}
-
+
if ((scratch & 0x88) || /* DMA completed or timed out */
(err_status & 0x1c) /* receive error */) {
if (info->stat_flags & ESP_STAT_DMA_RX)
@@ -667,7 +658,7 @@
receive_chars_dma(info, num_bytes);
}
}
-
+
if (!(info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) &&
(scratch & 0x02) && (info->IER & UART_IER_THRI)) {
if ((info->xmit_cnt <= 0) || info->tty->stopped) {
@@ -722,11 +713,11 @@
* ---------------------------------------------------------------
*/
-static inline void esp_basic_init(struct esp_struct * info)
+static void esp_basic_init(struct esp_struct *info)
{
/* put ESPC in enhanced mode */
serial_out(info, UART_ESI_CMD1, ESI_SET_MODE);
-
+
if (info->stat_flags & ESP_STAT_NEVER_DMA)
serial_out(info, UART_ESI_CMD2, 0x01);
else
@@ -783,13 +774,13 @@
serial_out(info, UART_ESI_CMD2, 0xff);
}
-static int startup(struct esp_struct * info)
+static int startup(struct esp_struct *info)
{
unsigned long flags;
- int retval=0;
- unsigned int num_chars;
+ int retval = 0;
+ unsigned int num_chars;
- spin_lock_irqsave(&info->lock, flags);
+ spin_lock_irqsave(&info->lock, flags);
if (info->flags & ASYNC_INITIALIZED)
goto out;
@@ -802,7 +793,8 @@
}
#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttys%d (irq %d)...", info->line, info->irq);
+ printk(KERN_DEBUG "starting up ttys%d (irq %d)...",
+ info->line, info->irq);
#endif
/* Flush the RX buffer. Using the ESI flush command may cause */
@@ -863,7 +855,7 @@
dma_buffer = NULL;
info->stat_flags |= ESP_STAT_USE_PIO;
}
-
+
}
info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2;
@@ -872,7 +864,7 @@
serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);
serial_out(info, UART_ESI_CMD2, UART_MCR);
serial_out(info, UART_ESI_CMD2, info->MCR);
-
+
/*
* Finally, enable interrupts
*/
@@ -881,7 +873,7 @@
UART_IER_DMA_TC;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
serial_out(info, UART_ESI_CMD2, info->IER);
-
+
if (info->tty)
clear_bit(TTY_IO_ERROR, &info->tty->flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
@@ -900,7 +892,7 @@
if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
info->tty->alt_speed = 460800;
}
-
+
/*
* set the speed of the serial port
*/
@@ -918,7 +910,7 @@
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
*/
-static void shutdown(struct esp_struct * info)
+static void shutdown(struct esp_struct *info)
{
unsigned long flags, f;
@@ -929,7 +921,7 @@
printk("Shutting down serial port %d (irq %d)....", info->line,
info->irq);
#endif
-
+
spin_lock_irqsave(&info->lock, flags);
/*
* clear delta_msr_wait queue to avoid mem leaks: we may free the irq
@@ -941,14 +933,14 @@
/* stop a DMA transfer on the port being closed */
/* DMA lock is higher priority always */
if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {
- f=claim_dma_lock();
+ f = claim_dma_lock();
disable_dma(dma);
clear_dma_ff(dma);
release_dma_lock(f);
-
+
dma_bytes = 0;
}
-
+
/*
* Free the IRQ
*/
@@ -970,7 +962,7 @@
free_pages((unsigned long)dma_buffer,
get_order(DMA_BUFFER_SZ));
dma_buffer = NULL;
- }
+ }
}
if (info->xmit_buf) {
@@ -992,7 +984,7 @@
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
-
+
info->flags &= ~ASYNC_INITIALIZED;
spin_unlock_irqrestore(&info->lock, flags);
}
@@ -1005,7 +997,7 @@
{
unsigned short port;
int quot = 0;
- unsigned cflag,cval;
+ unsigned cflag, cval;
int baud, bits;
unsigned char flow1 = 0, flow2 = 0;
unsigned long flags;
@@ -1014,14 +1006,14 @@
return;
cflag = info->tty->termios->c_cflag;
port = info->port;
-
+
/* byte size and parity */
switch (cflag & CSIZE) {
- case CS5: cval = 0x00; bits = 7; break;
- case CS6: cval = 0x01; bits = 8; break;
- case CS7: cval = 0x02; bits = 9; break;
- case CS8: cval = 0x03; bits = 10; break;
- default: cval = 0x00; bits = 7; break;
+ case CS5: cval = 0x00; bits = 7; break;
+ case CS6: cval = 0x01; bits = 8; break;
+ case CS7: cval = 0x02; bits = 9; break;
+ case CS8: cval = 0x03; bits = 10; break;
+ default: cval = 0x00; bits = 7; break;
}
if (cflag & CSTOPB) {
cval |= 0x04;
@@ -1037,14 +1029,12 @@
if (cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
-
baud = tty_get_baud_rate(info->tty);
if (baud == 38400 &&
- ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
+ ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
quot = info->custom_divisor;
else {
- if (baud == 134)
- /* Special case since 134 is really 134.5 */
+ if (baud == 134) /* Special case since 134 is really 134.5 */
quot = (2*BASE_BAUD / 269);
else if (baud)
quot = BASE_BAUD / baud;
@@ -1052,7 +1042,12 @@
/* If the quotient is ever zero, default to 9600 bps */
if (!quot)
quot = BASE_BAUD / 9600;
-
+
+ if (baud) {
+ /* Actual rate */
+ baud = BASE_BAUD/quot;
+ tty_encode_baud_rate(info->tty, baud, baud);
+ }
info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50);
/* CTS flow control flag and modem status interrupts */
@@ -1066,10 +1061,8 @@
info->flags &= ~ASYNC_CTS_FLOW;
if (cflag & CLOCAL)
info->flags &= ~ASYNC_CHECK_CD;
- else {
+ else
info->flags |= ASYNC_CHECK_CD;
- /* info->IER |= UART_IER_MSI; */
- }
/*
* Set up parity check flag
@@ -1079,7 +1072,7 @@
info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
info->read_status_mask |= UART_LSR_BI;
-
+
info->ignore_status_mask = 0;
#if 0
/* This should be safe, but for some broken bits of hardware... */
@@ -1092,7 +1085,7 @@
info->ignore_status_mask |= UART_LSR_BI;
info->read_status_mask |= UART_LSR_BI;
/*
- * If we're ignore parity and break indicators, ignore
+ * If we're ignore parity and break indicators, ignore
* overruns too. (For real raw support).
*/
if (I_IGNPAR(info->tty)) {
@@ -1130,19 +1123,19 @@
serial_out(info, UART_ESI_CMD2, 0x10);
serial_out(info, UART_ESI_CMD2, 0x21);
switch (cflag & CSIZE) {
- case CS5:
- serial_out(info, UART_ESI_CMD2, 0x1f);
- break;
- case CS6:
- serial_out(info, UART_ESI_CMD2, 0x3f);
- break;
- case CS7:
- case CS8:
- serial_out(info, UART_ESI_CMD2, 0x7f);
- break;
- default:
- serial_out(info, UART_ESI_CMD2, 0xff);
- break;
+ case CS5:
+ serial_out(info, UART_ESI_CMD2, 0x1f);
+ break;
+ case CS6:
+ serial_out(info, UART_ESI_CMD2, 0x3f);
+ break;
+ case CS7:
+ case CS8:
+ serial_out(info, UART_ESI_CMD2, 0x7f);
+ break;
+ default:
+ serial_out(info, UART_ESI_CMD2, 0xff);
+ break;
}
}
@@ -1156,31 +1149,34 @@
spin_unlock_irqrestore(&info->lock, flags);
}
-static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+static int rs_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
+ int ret = 0;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return;
+ return 0;
if (!info->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock, flags);
if (info->xmit_cnt < ESP_XMIT_SIZE - 1) {
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= ESP_XMIT_SIZE-1;
info->xmit_cnt++;
+ ret = 1;
}
spin_unlock_irqrestore(&info->lock, flags);
+ return ret;
}
static void rs_flush_chars(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
return;
@@ -1198,11 +1194,11 @@
spin_unlock_irqrestore(&info->lock, flags);
}
-static int rs_write(struct tty_struct * tty,
+static int rs_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
int c, t, ret = 0;
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (serial_paranoia_check(info, tty->name, "rs_write"))
@@ -1210,19 +1206,19 @@
if (!info->xmit_buf)
return 0;
-
+
while (1) {
/* Thanks to R. Wolff for suggesting how to do this with */
/* interrupts enabled */
c = count;
t = ESP_XMIT_SIZE - info->xmit_cnt - 1;
-
+
if (t < c)
c = t;
t = ESP_XMIT_SIZE - info->xmit_head;
-
+
if (t < c)
c = t;
@@ -1252,10 +1248,10 @@
static int rs_write_room(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
int ret;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_write_room"))
return 0;
@@ -1270,8 +1266,8 @@
static int rs_chars_in_buffer(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
-
+ struct esp_struct *info = tty->driver_data;
+
if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
return 0;
return info->xmit_cnt;
@@ -1279,9 +1275,9 @@
static void rs_flush_buffer(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
return;
spin_lock_irqsave(&info->lock, flags);
@@ -1293,20 +1289,20 @@
/*
* ------------------------------------------------------------
* rs_throttle()
- *
+ *
* This routine is called by the upper-layer tty layer to signal that
* incoming characters should be throttled.
* ------------------------------------------------------------
*/
-static void rs_throttle(struct tty_struct * tty)
+static void rs_throttle(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
-
+
printk("throttle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
+ tty_chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_throttle"))
@@ -1321,20 +1317,20 @@
spin_unlock_irqrestore(&info->lock, flags);
}
-static void rs_unthrottle(struct tty_struct * tty)
+static void rs_unthrottle(struct tty_struct *tty)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
#ifdef SERIAL_DEBUG_THROTTLE
char buf[64];
-
- printk("unthrottle %s: %d....\n", tty_name(tty, buf),
- tty->ldisc.chars_in_buffer(tty));
+
+ printk(KERN_DEBUG "unthrottle %s: %d....\n", tty_name(tty, buf),
+ tty_chars_in_buffer(tty));
#endif
if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
return;
-
+
spin_lock_irqsave(&info->lock, flags);
info->IER |= UART_IER_RDI;
serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);
@@ -1350,11 +1346,12 @@
* ------------------------------------------------------------
*/
-static int get_serial_info(struct esp_struct * info,
+static int get_serial_info(struct esp_struct *info,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
-
+
+ lock_kernel();
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_16550A;
tmp.line = info->line;
@@ -1367,20 +1364,22 @@
tmp.closing_wait = info->closing_wait;
tmp.custom_divisor = info->custom_divisor;
tmp.hub6 = 0;
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
+ unlock_kernel();
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
}
-static int get_esp_config(struct esp_struct * info,
+static int get_esp_config(struct esp_struct *info,
struct hayes_esp_config __user *retinfo)
{
struct hayes_esp_config tmp;
-
+
if (!retinfo)
return -EFAULT;
memset(&tmp, 0, sizeof(tmp));
+ lock_kernel();
tmp.rx_timeout = info->config.rx_timeout;
tmp.rx_trigger = info->config.rx_trigger;
tmp.tx_trigger = info->config.tx_trigger;
@@ -1388,11 +1387,12 @@
tmp.flow_on = info->config.flow_on;
tmp.pio_threshold = info->config.pio_threshold;
tmp.dma_channel = (info->stat_flags & ESP_STAT_NEVER_DMA ? 0 : dma);
+ unlock_kernel();
return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
}
-static int set_serial_info(struct esp_struct * info,
+static int set_serial_info(struct esp_struct *info,
struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
@@ -1401,7 +1401,7 @@
int retval = 0;
struct esp_struct *current_async;
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
old_info = *info;
@@ -1422,7 +1422,7 @@
return -EINVAL;
if (!capable(CAP_SYS_ADMIN)) {
- if (change_irq ||
+ if (change_irq ||
(new_serial.close_delay != info->close_delay) ||
((new_serial.flags & ~ASYNC_USR_MASK) !=
(info->flags & ~ASYNC_USR_MASK)))
@@ -1507,8 +1507,8 @@
return retval;
}
-static int set_esp_config(struct esp_struct * info,
- struct hayes_esp_config __user * new_info)
+static int set_esp_config(struct esp_struct *info,
+ struct hayes_esp_config __user *new_info)
{
struct hayes_esp_config new_config;
unsigned int change_dma;
@@ -1550,7 +1550,6 @@
if (new_config.dma_channel) {
/* PIO mode to DMA mode transition OR */
/* change current DMA channel */
-
current_async = ports;
while (current_async) {
@@ -1559,16 +1558,15 @@
return -EBUSY;
} else if (current_async->count)
return -EBUSY;
-
- current_async =
- current_async->next_port;
+
+ current_async = current_async->next_port;
}
shutdown(info);
dma = new_config.dma_channel;
info->stat_flags &= ~ESP_STAT_NEVER_DMA;
-
- /* all ports must use the same DMA channel */
+
+ /* all ports must use the same DMA channel */
spin_lock_irqsave(&info->lock, flags);
current_async = ports;
@@ -1580,7 +1578,6 @@
spin_unlock_irqrestore(&info->lock, flags);
} else {
/* DMA mode to PIO mode only */
-
if (info->count > 1)
return -EBUSY;
@@ -1596,8 +1593,6 @@
if ((new_config.flow_off != info->config.flow_off) ||
(new_config.flow_on != info->config.flow_on)) {
- unsigned long flags;
-
info->config.flow_off = new_config.flow_off;
info->config.flow_on = new_config.flow_on;
@@ -1612,8 +1607,6 @@
if ((new_config.rx_trigger != info->config.rx_trigger) ||
(new_config.tx_trigger != info->config.tx_trigger)) {
- unsigned long flags;
-
info->config.rx_trigger = new_config.rx_trigger;
info->config.tx_trigger = new_config.tx_trigger;
spin_lock_irqsave(&info->lock, flags);
@@ -1628,8 +1621,6 @@
}
if (new_config.rx_timeout != info->config.rx_timeout) {
- unsigned long flags;
-
info->config.rx_timeout = new_config.rx_timeout;
spin_lock_irqsave(&info->lock, flags);
@@ -1657,9 +1648,9 @@
* release the bus after transmitting. This must be done when
* the transmit shift register is empty, not be done when the
* transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
+ * allows an RS485 driver to be written in user space.
*/
-static int get_lsr_info(struct esp_struct * info, unsigned int __user *value)
+static int get_lsr_info(struct esp_struct *info, unsigned int __user *value)
{
unsigned char status;
unsigned int result;
@@ -1670,17 +1661,17 @@
status = serial_in(info, UART_ESI_STAT1);
spin_unlock_irqrestore(&info->lock, flags);
result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result,value);
+ return put_user(result, value);
}
static int esp_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned char control, status;
unsigned long flags;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1703,10 +1694,10 @@
static int esp_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
@@ -1736,9 +1727,9 @@
*/
static void esp_break(struct tty_struct *tty, int break_state)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
-
+
if (serial_paranoia_check(info, tty->name, "esp_break"))
return;
@@ -1758,14 +1749,15 @@
}
}
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
+static int rs_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
struct async_icount cprev, cnow; /* kernel counter temps */
struct serial_icounter_struct __user *p_cuser; /* user space */
void __user *argp = (void __user *)arg;
unsigned long flags;
+ int ret;
if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
return -ENODEV;
@@ -1778,97 +1770,93 @@
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
}
-
+
switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(info, argp);
- case TIOCSSERIAL:
- return set_serial_info(info, argp);
- case TIOCSERCONFIG:
- /* do not reconfigure after initial configuration */
- return 0;
-
- case TIOCSERGWILD:
- return put_user(0L, (unsigned long __user *)argp);
-
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, argp);
-
- case TIOCSERSWILD:
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- return 0;
-
- /*
- * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
- * - mask passed in arg for lines of interest
- * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
- * Caller should use TIOCGICOUNT to see which one it was
- */
- case TIOCMIWAIT:
+ case TIOCGSERIAL:
+ return get_serial_info(info, argp);
+ case TIOCSSERIAL:
+ lock_kernel();
+ ret = set_serial_info(info, argp);
+ unlock_kernel();
+ return ret;
+ case TIOCSERGWILD:
+ return put_user(0L, (unsigned long __user *)argp);
+ case TIOCSERGETLSR: /* Get line status register */
+ return get_lsr_info(info, argp);
+ case TIOCSERSWILD:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ return 0;
+ /*
+ * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+ * - mask passed in arg for lines of interest
+ * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+ * Caller should use TIOCGICOUNT to see which one it was
+ */
+ case TIOCMIWAIT:
+ spin_lock_irqsave(&info->lock, flags);
+ cprev = info->icount; /* note the counters on entry */
+ spin_unlock_irqrestore(&info->lock, flags);
+ while (1) {
+ /* FIXME: convert to new style wakeup */
+ interruptible_sleep_on(&info->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
spin_lock_irqsave(&info->lock, flags);
- cprev = info->icount; /* note the counters on entry */
+ cnow = info->icount; /* atomic copy */
spin_unlock_irqrestore(&info->lock, flags);
- while (1) {
- /* FIXME: convert to new style wakeup */
- interruptible_sleep_on(&info->delta_msr_wait);
- /* see if a signal did it */
- if (signal_pending(current))
- return -ERESTARTSYS;
- spin_lock_irqsave(&info->lock, flags);
- cnow = info->icount; /* atomic copy */
- spin_unlock_irqrestore(&info->lock, flags);
- if (cnow.rng == cprev.rng &&
- cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd &&
- cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
- if (((arg & TIOCM_RNG) &&
- (cnow.rng != cprev.rng)) ||
- ((arg & TIOCM_DSR) &&
- (cnow.dsr != cprev.dsr)) ||
- ((arg & TIOCM_CD) &&
- (cnow.dcd != cprev.dcd)) ||
- ((arg & TIOCM_CTS) &&
- (cnow.cts != cprev.cts)) ) {
- return 0;
- }
- cprev = cnow;
+ if (cnow.rng == cprev.rng &&
+ cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd &&
+ cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if (((arg & TIOCM_RNG) &&
+ (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) &&
+ (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) &&
+ (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) &&
+ (cnow.cts != cprev.cts))) {
+ return 0;
}
- /* NOTREACHED */
-
- /*
- * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
- * Return: write counters to the user passed counter struct
- * NB: both 1->0 and 0->1 transitions are counted except for
- * RI where only 0->1 is counted.
- */
- case TIOCGICOUNT:
- spin_lock_irqsave(&info->lock, flags);
- cnow = info->icount;
- spin_unlock_irqrestore(&info->lock, flags);
- p_cuser = argp;
- if (put_user(cnow.cts, &p_cuser->cts) ||
- put_user(cnow.dsr, &p_cuser->dsr) ||
- put_user(cnow.rng, &p_cuser->rng) ||
- put_user(cnow.dcd, &p_cuser->dcd))
- return -EFAULT;
-
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+ /*
+ * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+ * Return: write counters to the user passed counter struct
+ * NB: both 1->0 and 0->1 transitions are counted except for
+ * RI where only 0->1 is counted.
+ */
+ case TIOCGICOUNT:
+ spin_lock_irqsave(&info->lock, flags);
+ cnow = info->icount;
+ spin_unlock_irqrestore(&info->lock, flags);
+ p_cuser = argp;
+ if (put_user(cnow.cts, &p_cuser->cts) ||
+ put_user(cnow.dsr, &p_cuser->dsr) ||
+ put_user(cnow.rng, &p_cuser->rng) ||
+ put_user(cnow.dcd, &p_cuser->dcd))
+ return -EFAULT;
return 0;
case TIOCGHAYESESP:
return get_esp_config(info, argp);
case TIOCSHAYESESP:
- return set_esp_config(info, argp);
-
- default:
- return -ENOIOCTLCMD;
- }
+ lock_kernel();
+ ret = set_esp_config(info, argp);
+ unlock_kernel();
+ return ret;
+ default:
+ return -ENOIOCTLCMD;
+ }
return 0;
}
static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
change_speed(info);
@@ -1905,32 +1893,33 @@
/*
* ------------------------------------------------------------
* rs_close()
- *
+ *
* This routine is called when the serial port gets closed. First, we
* wait for the last remaining data to be sent. Then, we unlink its
* async structure from the interrupt chain if necessary, and we free
* that IRQ if nothing is left in the chain.
* ------------------------------------------------------------
*/
-static void rs_close(struct tty_struct *tty, struct file * filp)
+static void rs_close(struct tty_struct *tty, struct file *filp)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long flags;
if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
return;
-
+
spin_lock_irqsave(&info->lock, flags);
-
+
if (tty_hung_up_p(filp)) {
DBG_CNT("before DEC-hung");
goto out;
}
-
+
#ifdef SERIAL_DEBUG_OPEN
- printk("rs_close ttys%d, count = %d\n", info->line, info->count);
+ printk(KERN_DEBUG "rs_close ttys%d, count = %d\n",
+ info->line, info->count);
#endif
- if ((tty->count == 1) && (info->count != 1)) {
+ if (tty->count == 1 && info->count != 1) {
/*
* Uh, oh. tty->count is 1, which means that the tty
* structure will be freed. Info->count should always
@@ -1938,12 +1927,11 @@
* one, we've got real problems, since it means the
* serial port won't be shutdown.
*/
- printk("rs_close: bad serial port count; tty->count is 1, "
- "info->count is %d\n", info->count);
+ printk(KERN_DEBUG "rs_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count);
info->count = 1;
}
if (--info->count < 0) {
- printk("rs_close: bad serial port count for ttys%d: %d\n",
+ printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n",
info->line, info->count);
info->count = 0;
}
@@ -1955,7 +1943,7 @@
spin_unlock_irqrestore(&info->lock, flags);
/*
- * Now we wait for the transmit buffer to clear; and we notify
+ * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
@@ -1990,16 +1978,14 @@
rs_wait_until_sent(tty, info->timeout);
}
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
info->tty = NULL;
if (info->blocked_open) {
- if (info->close_delay) {
+ if (info->close_delay)
msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
wake_up_interruptible(&info->open_wait);
}
info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
@@ -2012,7 +1998,7 @@
static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
{
- struct esp_struct *info = (struct esp_struct *)tty->driver_data;
+ struct esp_struct *info = tty->driver_data;
unsigned long orig_jiffies, char_time;
unsigned long flags;
@@ -2036,10 +2022,10 @@
msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
- break;
+ return;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
+ return;
spin_lock_irqsave(&info->lock, flags);
serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND);
@@ -2054,11 +2040,11 @@
*/
static void esp_hangup(struct tty_struct *tty)
{
- struct esp_struct * info = (struct esp_struct *)tty->driver_data;
-
+ struct esp_struct *info = tty->driver_data;
+
if (serial_paranoia_check(info, tty->name, "esp_hangup"))
return;
-
+
rs_flush_buffer(tty);
shutdown(info);
info->count = 0;
@@ -2072,7 +2058,7 @@
* esp_open() and friends
* ------------------------------------------------------------
*/
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
struct esp_struct *info)
{
DECLARE_WAITQUEUE(wait, current);
@@ -2121,11 +2107,11 @@
retval = 0;
add_wait_queue(&info->open_wait, &wait);
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready before block: ttys%d, count = %d\n",
+ printk(KERN_DEBUG "block_til_ready before block: ttys%d, count = %d\n",
info->line, info->count);
#endif
spin_lock_irqsave(&info->lock, flags);
- if (!tty_hung_up_p(filp))
+ if (!tty_hung_up_p(filp))
info->count--;
info->blocked_open++;
while (1) {
@@ -2147,7 +2133,7 @@
if (info->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
+ retval = -ERESTARTSYS;
#else
retval = -EAGAIN;
#endif
@@ -2166,7 +2152,7 @@
break;
}
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready blocking: ttys%d, count = %d\n",
+ printk(KERN_DEBUG "block_til_ready blocking: ttys%d, count = %d\n",
info->line, info->count);
#endif
spin_unlock_irqrestore(&info->lock, flags);
@@ -2180,14 +2166,14 @@
info->blocked_open--;
spin_unlock_irqrestore(&info->lock, flags);
#ifdef SERIAL_DEBUG_OPEN
- printk("block_til_ready after blocking: ttys%d, count = %d\n",
+ printk(KERN_DEBUG "block_til_ready after blocking: ttys%d, count = %d\n",
info->line, info->count);
#endif
if (retval)
return retval;
info->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
-}
+}
/*
* This routine is called whenever a serial port is opened. It
@@ -2195,7 +2181,7 @@
* the IRQ chain. It also performs the serial-specific
* initialization for the tty structure.
*/
-static int esp_open(struct tty_struct *tty, struct file * filp)
+static int esp_open(struct tty_struct *tty, struct file *filp)
{
struct esp_struct *info;
int retval, line;
@@ -2218,7 +2204,7 @@
}
#ifdef SERIAL_DEBUG_OPEN
- printk("esp_open %s, count = %d\n", tty->name, info->count);
+ printk(KERN_DEBUG "esp_open %s, count = %d\n", tty->name, info->count);
#endif
spin_lock_irqsave(&info->lock, flags);
info->count++;
@@ -2226,7 +2212,7 @@
info->tty = tty;
spin_unlock_irqrestore(&info->lock, flags);
-
+
/*
* Start up serial port
*/
@@ -2237,14 +2223,13 @@
retval = block_til_ready(tty, filp, info);
if (retval) {
#ifdef SERIAL_DEBUG_OPEN
- printk("esp_open returning after block_til_ready with %d\n",
+ printk(KERN_DEBUG "esp_open returning after block_til_ready with %d\n",
retval);
#endif
return retval;
}
-
#ifdef SERIAL_DEBUG_OPEN
- printk("esp_open %s successful...", tty->name);
+ printk(KERN_DEBUG "esp_open %s successful...", tty->name);
#endif
return 0;
}
@@ -2262,10 +2247,10 @@
* number, and identifies which options were configured into this
* driver.
*/
-
-static inline void show_serial_version(void)
+
+static void show_serial_version(void)
{
- printk(KERN_INFO "%s version %s (DMA %u)\n",
+ printk(KERN_INFO "%s version %s (DMA %u)\n",
serial_name, serial_version, dma);
}
@@ -2273,7 +2258,7 @@
* This routine is called by espserial_init() to initialize a specific serial
* port.
*/
-static inline int autoconfig(struct esp_struct * info)
+static int autoconfig(struct esp_struct *info)
{
int port_detected = 0;
unsigned long flags;
@@ -2349,14 +2334,14 @@
static int __init espserial_init(void)
{
int i, offset;
- struct esp_struct * info;
+ struct esp_struct *info;
struct esp_struct *last_primary = NULL;
- int esp[] = {0x100,0x140,0x180,0x200,0x240,0x280,0x300,0x380};
+ int esp[] = { 0x100, 0x140, 0x180, 0x200, 0x240, 0x280, 0x300, 0x380 };
esp_driver = alloc_tty_driver(NR_PORTS);
if (!esp_driver)
return -ENOMEM;
-
+
for (i = 0; i < NR_PRIMARY; i++) {
if (irq[i] != 0) {
if ((irq[i] < 2) || (irq[i] > 15) || (irq[i] == 6) ||
@@ -2378,20 +2363,20 @@
if ((flow_off < 1) || (flow_off > 1023))
flow_off = 1016;
-
+
if ((flow_on < 1) || (flow_on > 1023))
flow_on = 944;
if ((rx_timeout < 0) || (rx_timeout > 255))
rx_timeout = 128;
-
+
if (flow_on >= flow_off)
flow_on = flow_off - 1;
show_serial_version();
/* Initialize the tty_driver structure */
-
+
esp_driver->owner = THIS_MODULE;
esp_driver->name = "ttyP";
esp_driver->major = ESP_IN_MAJOR;
@@ -2401,10 +2386,11 @@
esp_driver->init_termios = tty_std_termios;
esp_driver->init_termios.c_cflag =
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ esp_driver->init_termios.c_ispeed = 9600;
+ esp_driver->init_termios.c_ospeed = 9600;
esp_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(esp_driver, &esp_ops);
- if (tty_register_driver(esp_driver))
- {
+ if (tty_register_driver(esp_driver)) {
printk(KERN_ERR "Couldn't register esp serial driver");
put_tty_driver(esp_driver);
return 1;
@@ -2412,8 +2398,7 @@
info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
- if (!info)
- {
+ if (!info) {
printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
tty_unregister_driver(esp_driver);
put_tty_driver(esp_driver);
@@ -2476,10 +2461,8 @@
info->stat_flags |= ESP_STAT_NEVER_DMA;
info = kzalloc(sizeof(struct esp_struct), GFP_KERNEL);
- if (!info)
- {
- printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
-
+ if (!info) {
+ printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n");
/* allow use of the already detected ports */
return 0;
}
@@ -2503,22 +2486,20 @@
return 0;
}
-static void __exit espserial_exit(void)
+static void __exit espserial_exit(void)
{
int e1;
struct esp_struct *temp_async;
struct esp_pio_buffer *pio_buf;
- /* printk("Unloading %s: version %s\n", serial_name, serial_version); */
- if ((e1 = tty_unregister_driver(esp_driver)))
- printk("SERIAL: failed to unregister serial driver (%d)\n",
- e1);
+ e1 = tty_unregister_driver(esp_driver);
+ if (e1)
+ printk(KERN_ERR "esp: failed to unregister driver (%d)\n", e1);
put_tty_driver(esp_driver);
while (ports) {
- if (ports->port) {
+ if (ports->port)
release_region(ports->port, REGION_SIZE);
- }
temp_async = ports->next_port;
kfree(ports);
ports = temp_async;
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 7ed7da1..252f73e 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -40,27 +40,27 @@
#define gs_dprintk(f, str...) /* nothing */
#endif
-#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__)
-#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __FUNCTION__)
+#define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __func__)
+#define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __func__)
#define RS_EVENT_WRITE_WAKEUP 1
module_param(gs_debug, int, 0644);
-void gs_put_char(struct tty_struct * tty, unsigned char ch)
+int gs_put_char(struct tty_struct * tty, unsigned char ch)
{
struct gs_port *port;
func_enter ();
- if (!tty) return;
+ if (!tty) return 0;
port = tty->driver_data;
- if (!port) return;
+ if (!port) return 0;
- if (! (port->flags & ASYNC_INITIALIZED)) return;
+ if (! (port->flags & ASYNC_INITIALIZED)) return 0;
/* Take a lock on the serial tranmit buffer! */
mutex_lock(& port->port_write_mutex);
@@ -68,7 +68,7 @@
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
/* Sorry, buffer is full, drop character. Update statistics???? -- REW */
mutex_unlock(&port->port_write_mutex);
- return;
+ return 0;
}
port->xmit_buf[port->xmit_head++] = ch;
@@ -77,6 +77,7 @@
mutex_unlock(&port->port_write_mutex);
func_exit ();
+ return 1;
}
@@ -586,8 +587,7 @@
port->flags &= ~GS_ACTIVE;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ gs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 1399971..e7fb0bc 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -308,7 +308,7 @@
if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
PAGE_SIZE, vma->vm_page_prot)) {
printk(KERN_ERR "%s: io_remap_pfn_range failed\n",
- __FUNCTION__);
+ __func__);
return -EAGAIN;
}
@@ -748,7 +748,7 @@
*/
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: duplicate HPET ignored\n",
- __FUNCTION__);
+ __func__);
return 0;
}
@@ -869,7 +869,7 @@
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: 0x%lx is busy\n",
- __FUNCTION__, hdp->hd_phys_address);
+ __func__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
return AE_ALREADY_EXISTS;
}
@@ -886,7 +886,7 @@
if (hpet_is_known(hdp)) {
printk(KERN_DEBUG "%s: 0x%lx is busy\n",
- __FUNCTION__, hdp->hd_phys_address);
+ __func__, hdp->hd_phys_address);
iounmap(hdp->hd_address);
return AE_ALREADY_EXISTS;
}
@@ -925,7 +925,7 @@
return -ENODEV;
if (!data.hd_address || !data.hd_nirqs) {
- printk("%s: no address or irqs in _CRS\n", __FUNCTION__);
+ printk("%s: no address or irqs in _CRS\n", __func__);
return -ENODEV;
}
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index d5a752d..59c6f9a 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -246,7 +246,7 @@
{
int remaining = (int)(hp->inbuf_end - read_to);
- pr_debug("%s: %i chars remain\n", __FUNCTION__, remaining);
+ pr_debug("%s: %i chars remain\n", __func__, remaining);
if (read_to != hp->inbuf)
memmove(hp->inbuf, read_to, remaining);
@@ -365,7 +365,7 @@
packet.u.version = HVSI_VERSION;
packet.query_seqno = query_seqno+1;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -437,7 +437,7 @@
return NULL;
if (overflow > 0) {
- pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __FUNCTION__);
+ pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __func__);
datalen = TTY_THRESHOLD_THROTTLE;
}
@@ -448,7 +448,7 @@
* we still have more data to deliver, so we need to save off the
* overflow and send it later
*/
- pr_debug("%s: deferring overflow\n", __FUNCTION__);
+ pr_debug("%s: deferring overflow\n", __func__);
memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow);
hp->n_throttle = overflow;
}
@@ -474,11 +474,11 @@
chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ);
if (chunklen == 0) {
- pr_debug("%s: 0-length read\n", __FUNCTION__);
+ pr_debug("%s: 0-length read\n", __func__);
return 0;
}
- pr_debug("%s: got %i bytes\n", __FUNCTION__, chunklen);
+ pr_debug("%s: got %i bytes\n", __func__, chunklen);
dbg_dump_hex(hp->inbuf_end, chunklen);
hp->inbuf_end += chunklen;
@@ -495,7 +495,7 @@
continue;
}
- pr_debug("%s: handling %i-byte packet\n", __FUNCTION__,
+ pr_debug("%s: handling %i-byte packet\n", __func__,
len_packet(packet));
dbg_dump_packet(packet);
@@ -526,7 +526,7 @@
packet += len_packet(packet);
if (*hangup || *handshake) {
- pr_debug("%s: hangup or handshake\n", __FUNCTION__);
+ pr_debug("%s: hangup or handshake\n", __func__);
/*
* we need to send the hangup now before receiving any more data.
* If we get "data, hangup, data", we can't deliver the second
@@ -543,7 +543,7 @@
static void hvsi_send_overflow(struct hvsi_struct *hp)
{
- pr_debug("%s: delivering %i bytes overflow\n", __FUNCTION__,
+ pr_debug("%s: delivering %i bytes overflow\n", __func__,
hp->n_throttle);
hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle);
@@ -563,7 +563,7 @@
unsigned long flags;
int again = 1;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
while (again) {
spin_lock_irqsave(&hp->lock, flags);
@@ -647,7 +647,7 @@
packet.seqno = atomic_inc_return(&hp->seqno);
packet.verb = verb;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -674,7 +674,7 @@
return ret;
}
- pr_debug("%s: mctrl 0x%x\n", __FUNCTION__, hp->mctrl);
+ pr_debug("%s: mctrl 0x%x\n", __func__, hp->mctrl);
return 0;
}
@@ -694,7 +694,7 @@
if (mctrl & TIOCM_DTR)
packet.word = HVSI_TSDTR;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -790,7 +790,7 @@
packet.len = 6;
packet.verb = VSV_CLOSE_PROTOCOL;
- pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len);
+ pr_debug("%s: sending %i bytes\n", __func__, packet.len);
dbg_dump_hex((uint8_t*)&packet, packet.len);
hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);
@@ -803,7 +803,7 @@
int line = tty->index;
int ret;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
if (line < 0 || line >= hvsi_count)
return -ENODEV;
@@ -868,7 +868,7 @@
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
if (tty_hung_up_p(filp))
return;
@@ -920,7 +920,7 @@
struct hvsi_struct *hp = tty->driver_data;
unsigned long flags;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags);
@@ -942,7 +942,7 @@
n = hvsi_put_chars(hp, hp->outbuf, hp->n_outbuf);
if (n > 0) {
/* success */
- pr_debug("%s: wrote %i chars\n", __FUNCTION__, n);
+ pr_debug("%s: wrote %i chars\n", __func__, n);
hp->n_outbuf = 0;
} else if (n == -EIO) {
__set_state(hp, HVSI_FSP_DIED);
@@ -965,7 +965,7 @@
spin_lock_irqsave(&hp->lock, flags);
- pr_debug("%s: %i chars in buffer\n", __FUNCTION__, hp->n_outbuf);
+ pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
if (!is_open(hp)) {
/*
@@ -983,7 +983,7 @@
schedule_delayed_work(&hp->writer, 10);
else {
#ifdef DEBUG
- pr_debug("%s: outbuf emptied after %li jiffies\n", __FUNCTION__,
+ pr_debug("%s: outbuf emptied after %li jiffies\n", __func__,
jiffies - start_j);
start_j = 0;
#endif /* DEBUG */
@@ -1020,11 +1020,11 @@
spin_lock_irqsave(&hp->lock, flags);
- pr_debug("%s: %i chars in buffer\n", __FUNCTION__, hp->n_outbuf);
+ pr_debug("%s: %i chars in buffer\n", __func__, hp->n_outbuf);
if (!is_open(hp)) {
/* we're either closing or not yet open; don't accept data */
- pr_debug("%s: not open\n", __FUNCTION__);
+ pr_debug("%s: not open\n", __func__);
goto out;
}
@@ -1058,7 +1058,7 @@
spin_unlock_irqrestore(&hp->lock, flags);
if (total != origcount)
- pr_debug("%s: wanted %i, only wrote %i\n", __FUNCTION__, origcount,
+ pr_debug("%s: wanted %i, only wrote %i\n", __func__, origcount,
total);
return total;
@@ -1072,7 +1072,7 @@
{
struct hvsi_struct *hp = (struct hvsi_struct *)tty->driver_data;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
h_vio_signal(hp->vtermno, VIO_IRQ_DISABLE);
}
@@ -1083,7 +1083,7 @@
unsigned long flags;
int shouldflip = 0;
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s\n", __func__);
spin_lock_irqsave(&hp->lock, flags);
if (hp->n_throttle) {
@@ -1302,7 +1302,7 @@
hp->virq = irq_create_mapping(NULL, irq[0]);
if (hp->virq == NO_IRQ) {
printk(KERN_ERR "%s: couldn't create irq mapping for 0x%x\n",
- __FUNCTION__, irq[0]);
+ __func__, irq[0]);
continue;
}
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index 8609b82..b60d425 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -77,11 +77,16 @@
module_param(power_status, bool, 0600);
MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
+static int fan_mult = I8K_FAN_MULT;
+module_param(fan_mult, int, 0);
+MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
+
static int i8k_open_fs(struct inode *inode, struct file *file);
static int i8k_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
static const struct file_operations i8k_fops = {
+ .owner = THIS_MODULE,
.open = i8k_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -238,7 +243,7 @@
struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
regs.ebx = fan & 0xff;
- return i8k_smm(®s) ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
+ return i8k_smm(®s) ? : (regs.eax & 0xffff) * fan_mult;
}
/*
@@ -554,13 +559,10 @@
return -ENODEV;
/* Register the proc entry */
- proc_i8k = create_proc_entry("i8k", 0, NULL);
+ proc_i8k = proc_create("i8k", 0, NULL, &i8k_fops);
if (!proc_i8k)
return -ENOENT;
- proc_i8k->proc_fops = &i8k_fops;
- proc_i8k->owner = THIS_MODULE;
-
printk(KERN_INFO
"Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
I8K_VERSION);
diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c
index 61ef013..3601017 100644
--- a/drivers/char/ip2/i2ellis.c
+++ b/drivers/char/ip2/i2ellis.c
@@ -53,7 +53,7 @@
static int iiDelayed; // Set when the iiResetDelay function is
// called. Cleared when ANY board is reset.
-static rwlock_t Dl_spinlock;
+static DEFINE_RWLOCK(Dl_spinlock);
//********
//* Code *
@@ -82,7 +82,6 @@
static void
iiEllisInit(void)
{
- LOCK_INIT(&Dl_spinlock);
}
//******************************************************************************
@@ -132,7 +131,7 @@
|| (address & 0x7)
)
{
- COMPLETE(pB,I2EE_BADADDR);
+ I2_COMPLETE(pB, I2EE_BADADDR);
}
// Initialize accelerators
@@ -152,7 +151,7 @@
pB->i2eValid = I2E_MAGIC;
pB->i2eState = II_STATE_COLD;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -177,12 +176,12 @@
// Magic number should be set, else even the address is suspect
if (pB->i2eValid != I2E_MAGIC)
{
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
- OUTB(pB->i2eBase + FIFO_RESET, 0); // Any data will do
+ outb(0, pB->i2eBase + FIFO_RESET); /* Any data will do */
iiDelay(pB, 50); // Pause between resets
- OUTB(pB->i2eBase + FIFO_RESET, 0); // Second reset
+ outb(0, pB->i2eBase + FIFO_RESET); /* Second reset */
// We must wait before even attempting to read anything from the FIFO: the
// board's P.O.S.T may actually attempt to read and write its end of the
@@ -203,7 +202,7 @@
// Ensure anything which would have been of use to standard loadware is
// blanked out, since board has now forgotten everything!.
- pB->i2eUsingIrq = IRQ_UNDEFINED; // Not set up to use an interrupt yet
+ pB->i2eUsingIrq = I2_IRQ_UNDEFINED; /* to not use an interrupt so far */
pB->i2eWaitingForEmptyFifo = 0;
pB->i2eOutMailWaiting = 0;
pB->i2eChannelPtr = NULL;
@@ -215,7 +214,7 @@
pB->i2eFatalTrap = NULL;
pB->i2eFatal = 0;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -235,14 +234,14 @@
iiResetDelay(i2eBordStrPtr pB)
{
if (pB->i2eValid != I2E_MAGIC) {
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
if (pB->i2eState != II_STATE_RESET) {
- COMPLETE(pB, I2EE_BADSTATE);
+ I2_COMPLETE(pB, I2EE_BADSTATE);
}
iiDelay(pB,2000); /* Now we wait for two seconds. */
iiDelayed = 1; /* Delay has been called: ok to initialize */
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -273,12 +272,12 @@
if (pB->i2eValid != I2E_MAGIC)
{
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
if (pB->i2eState != II_STATE_RESET || !iiDelayed)
{
- COMPLETE(pB, I2EE_BADSTATE);
+ I2_COMPLETE(pB, I2EE_BADSTATE);
}
// In case there is a failure short of our completely reading the power-up
@@ -291,13 +290,12 @@
for (itemp = 0; itemp < sizeof(porStr); itemp++)
{
// We expect the entire message is ready.
- if (HAS_NO_INPUT(pB))
- {
+ if (!I2_HAS_INPUT(pB)) {
pB->i2ePomSize = itemp;
- COMPLETE(pB, I2EE_PORM_SHORT);
+ I2_COMPLETE(pB, I2EE_PORM_SHORT);
}
- pB->i2ePom.c[itemp] = c = BYTE_FROM(pB);
+ pB->i2ePom.c[itemp] = c = inb(pB->i2eData);
// We check the magic numbers as soon as they are supposed to be read
// (rather than after) to minimize effect of reading something we
@@ -306,22 +304,22 @@
(itemp == POR_2_INDEX && c != POR_MAGIC_2))
{
pB->i2ePomSize = itemp+1;
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
}
pB->i2ePomSize = itemp;
// Ensure that this was all the data...
- if (HAS_INPUT(pB))
- COMPLETE(pB, I2EE_PORM_LONG);
+ if (I2_HAS_INPUT(pB))
+ I2_COMPLETE(pB, I2EE_PORM_LONG);
// For now, we'll fail to initialize if P.O.S.T reports bad chip mapper:
// Implying we will not be able to download any code either: That's ok: the
// condition is pretty explicit.
if (pB->i2ePom.e.porDiag1 & POR_BAD_MAPPER)
{
- COMPLETE(pB, I2EE_POSTERR);
+ I2_COMPLETE(pB, I2EE_POSTERR);
}
// Determine anything which must be done differently depending on the family
@@ -332,7 +330,7 @@
pB->i2eFifoStyle = FIFO_II;
pB->i2eFifoSize = 512; // 512 bytes, always
- pB->i2eDataWidth16 = NO;
+ pB->i2eDataWidth16 = false;
pB->i2eMaxIrq = 15; // Because board cannot tell us it is in an 8-bit
// slot, we do allow it to be done (documentation!)
@@ -354,7 +352,7 @@
// should always be consistent for IntelliPort-II. Ditto below...
if (pB->i2ePom.e.porPorts1 != 4)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
break;
@@ -364,7 +362,7 @@
pB->i2eChannelMap[0] = 0xff; // Eight port
if (pB->i2ePom.e.porPorts1 != 8)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
break;
@@ -373,7 +371,7 @@
pB->i2eChannelMap[0] = 0x3f; // Six Port
if (pB->i2ePom.e.porPorts1 != 6)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
break;
}
@@ -402,7 +400,7 @@
if (itemp < 8 || itemp > 15)
{
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
pB->i2eFifoSize = (1 << itemp);
@@ -450,26 +448,26 @@
switch (pB->i2ePom.e.porBus & (POR_BUS_SLOT16 | POR_BUS_DIP16) )
{
case POR_BUS_SLOT16 | POR_BUS_DIP16:
- pB->i2eDataWidth16 = YES;
+ pB->i2eDataWidth16 = true;
pB->i2eMaxIrq = 15;
break;
case POR_BUS_SLOT16:
- pB->i2eDataWidth16 = NO;
+ pB->i2eDataWidth16 = false;
pB->i2eMaxIrq = 15;
break;
case 0:
case POR_BUS_DIP16: // In an 8-bit slot, DIP switch don't care.
default:
- pB->i2eDataWidth16 = NO;
+ pB->i2eDataWidth16 = false;
pB->i2eMaxIrq = 7;
break;
}
break; // POR_ID_FIIEX case
default: // Unknown type of board
- COMPLETE(pB, I2EE_BAD_FAMILY);
+ I2_COMPLETE(pB, I2EE_BAD_FAMILY);
break;
} // End the switch based on family
@@ -483,17 +481,14 @@
{
case POR_BUS_T_ISA:
case POR_BUS_T_UNK: // If the type of bus is undeclared, assume ok.
- pB->i2eChangeIrq = YES;
- break;
case POR_BUS_T_MCA:
case POR_BUS_T_EISA:
- pB->i2eChangeIrq = NO;
break;
default:
- COMPLETE(pB, I2EE_BADBUS);
+ I2_COMPLETE(pB, I2EE_BADBUS);
}
- if (pB->i2eDataWidth16 == YES)
+ if (pB->i2eDataWidth16)
{
pB->i2eWriteBuf = iiWriteBuf16;
pB->i2eReadBuf = iiReadBuf16;
@@ -529,7 +524,7 @@
break;
default:
- COMPLETE(pB, I2EE_INCONSIST);
+ I2_COMPLETE(pB, I2EE_INCONSIST);
}
// Initialize state information.
@@ -549,7 +544,7 @@
// Everything is ok now, return with good status/
pB->i2eValid = I2E_MAGIC;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -658,7 +653,7 @@
while(mseconds--) {
int i = ii2DelValue;
while ( i-- ) {
- INB ( ii2Safe );
+ inb(ii2Safe);
}
}
}
@@ -709,11 +704,11 @@
{
// Rudimentary sanity checking here.
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- OUTSW ( pB->i2eData, address, count);
+ I2_OUTSW(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -738,11 +733,11 @@
{
/* Rudimentary sanity checking here */
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- OUTSB ( pB->i2eData, address, count );
+ I2_OUTSB(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -767,11 +762,11 @@
{
// Rudimentary sanity checking here.
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- INSW ( pB->i2eData, address, count);
+ I2_INSW(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -796,11 +791,11 @@
{
// Rudimentary sanity checking here.
if (pB->i2eValid != I2E_MAGIC)
- COMPLETE(pB, I2EE_INVALID);
+ I2_COMPLETE(pB, I2EE_INVALID);
- INSB ( pB->i2eData, address, count);
+ I2_INSB(pB->i2eData, address, count);
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
//******************************************************************************
@@ -820,7 +815,7 @@
static unsigned short
iiReadWord16(i2eBordStrPtr pB)
{
- return (unsigned short)( INW(pB->i2eData) );
+ return inw(pB->i2eData);
}
//******************************************************************************
@@ -842,9 +837,9 @@
{
unsigned short urs;
- urs = INB ( pB->i2eData );
+ urs = inb(pB->i2eData);
- return ( ( INB ( pB->i2eData ) << 8 ) | urs );
+ return (inb(pB->i2eData) << 8) | urs;
}
//******************************************************************************
@@ -865,7 +860,7 @@
static void
iiWriteWord16(i2eBordStrPtr pB, unsigned short value)
{
- WORD_TO(pB, (int)value);
+ outw((int)value, pB->i2eData);
}
//******************************************************************************
@@ -886,8 +881,8 @@
static void
iiWriteWord8(i2eBordStrPtr pB, unsigned short value)
{
- BYTE_TO(pB, (char)value);
- BYTE_TO(pB, (char)(value >> 8) );
+ outb((char)value, pB->i2eData);
+ outb((char)(value >> 8), pB->i2eData);
}
//******************************************************************************
@@ -939,30 +934,30 @@
// interrupts of any kind.
- WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags)
- OUTB(pB->i2ePointer, SEL_COMMAND);
- OUTB(pB->i2ePointer, SEL_CMD_SH);
+ write_lock_irqsave(&Dl_spinlock, flags);
+ outb(SEL_COMMAND, pB->i2ePointer);
+ outb(SEL_CMD_SH, pB->i2ePointer);
- itemp = INB(pB->i2eStatus);
+ itemp = inb(pB->i2eStatus);
- OUTB(pB->i2ePointer, SEL_COMMAND);
- OUTB(pB->i2ePointer, SEL_CMD_UNSH);
+ outb(SEL_COMMAND, pB->i2ePointer);
+ outb(SEL_CMD_UNSH, pB->i2ePointer);
if (itemp & ST_IN_EMPTY)
{
- UPDATE_FIFO_ROOM(pB);
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
- COMPLETE(pB, I2EE_GOOD);
+ I2_UPDATE_FIFO_ROOM(pB);
+ write_unlock_irqrestore(&Dl_spinlock, flags);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+ write_unlock_irqrestore(&Dl_spinlock, flags);
if (mSdelay-- == 0)
break;
iiDelay(pB, 1); /* 1 mS granularity on checking condition */
}
- COMPLETE(pB, I2EE_TXE_TIME);
+ I2_COMPLETE(pB, I2EE_TXE_TIME);
}
//******************************************************************************
@@ -1002,21 +997,21 @@
// you will generally not want to service interrupts or in any way
// disrupt the assumptions implicit in the larger context.
- WRITE_LOCK_IRQSAVE(&Dl_spinlock,flags)
+ write_lock_irqsave(&Dl_spinlock, flags);
- if (INB(pB->i2eStatus) & STE_OUT_MT) {
- UPDATE_FIFO_ROOM(pB);
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
- COMPLETE(pB, I2EE_GOOD);
+ if (inb(pB->i2eStatus) & STE_OUT_MT) {
+ I2_UPDATE_FIFO_ROOM(pB);
+ write_unlock_irqrestore(&Dl_spinlock, flags);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
- WRITE_UNLOCK_IRQRESTORE(&Dl_spinlock,flags)
+ write_unlock_irqrestore(&Dl_spinlock, flags);
if (mSdelay-- == 0)
break;
iiDelay(pB, 1); // 1 mS granularity on checking condition
}
- COMPLETE(pB, I2EE_TXE_TIME);
+ I2_COMPLETE(pB, I2EE_TXE_TIME);
}
//******************************************************************************
@@ -1038,8 +1033,8 @@
iiTxMailEmptyII(i2eBordStrPtr pB)
{
int port = pB->i2ePointer;
- OUTB ( port, SEL_OUTMAIL );
- return ( INB(port) == 0 );
+ outb(SEL_OUTMAIL, port);
+ return inb(port) == 0;
}
//******************************************************************************
@@ -1060,7 +1055,7 @@
static int
iiTxMailEmptyIIEX(i2eBordStrPtr pB)
{
- return !(INB(pB->i2eStatus) & STE_OUT_MAIL);
+ return !(inb(pB->i2eStatus) & STE_OUT_MAIL);
}
//******************************************************************************
@@ -1084,10 +1079,10 @@
{
int port = pB->i2ePointer;
- OUTB(port, SEL_OUTMAIL);
- if (INB(port) == 0) {
- OUTB(port, SEL_OUTMAIL);
- OUTB(port, mail);
+ outb(SEL_OUTMAIL, port);
+ if (inb(port) == 0) {
+ outb(SEL_OUTMAIL, port);
+ outb(mail, port);
return 1;
}
return 0;
@@ -1112,10 +1107,9 @@
static int
iiTrySendMailIIEX(i2eBordStrPtr pB, unsigned char mail)
{
- if(INB(pB->i2eStatus) & STE_OUT_MAIL) {
+ if (inb(pB->i2eStatus) & STE_OUT_MAIL)
return 0;
- }
- OUTB(pB->i2eXMail, mail);
+ outb(mail, pB->i2eXMail);
return 1;
}
@@ -1136,9 +1130,9 @@
static unsigned short
iiGetMailII(i2eBordStrPtr pB)
{
- if (HAS_MAIL(pB)) {
- OUTB(pB->i2ePointer, SEL_INMAIL);
- return INB(pB->i2ePointer);
+ if (I2_HAS_MAIL(pB)) {
+ outb(SEL_INMAIL, pB->i2ePointer);
+ return inb(pB->i2ePointer);
} else {
return NO_MAIL_HERE;
}
@@ -1161,11 +1155,10 @@
static unsigned short
iiGetMailIIEX(i2eBordStrPtr pB)
{
- if (HAS_MAIL(pB)) {
- return INB(pB->i2eXMail);
- } else {
+ if (I2_HAS_MAIL(pB))
+ return inb(pB->i2eXMail);
+ else
return NO_MAIL_HERE;
- }
}
//******************************************************************************
@@ -1184,8 +1177,8 @@
static void
iiEnableMailIrqII(i2eBordStrPtr pB)
{
- OUTB(pB->i2ePointer, SEL_MASK);
- OUTB(pB->i2ePointer, ST_IN_MAIL);
+ outb(SEL_MASK, pB->i2ePointer);
+ outb(ST_IN_MAIL, pB->i2ePointer);
}
//******************************************************************************
@@ -1204,7 +1197,7 @@
static void
iiEnableMailIrqIIEX(i2eBordStrPtr pB)
{
- OUTB(pB->i2eXMask, MX_IN_MAIL);
+ outb(MX_IN_MAIL, pB->i2eXMask);
}
//******************************************************************************
@@ -1223,8 +1216,8 @@
static void
iiWriteMaskII(i2eBordStrPtr pB, unsigned char value)
{
- OUTB(pB->i2ePointer, SEL_MASK);
- OUTB(pB->i2ePointer, value);
+ outb(SEL_MASK, pB->i2ePointer);
+ outb(value, pB->i2ePointer);
}
//******************************************************************************
@@ -1243,7 +1236,7 @@
static void
iiWriteMaskIIEX(i2eBordStrPtr pB, unsigned char value)
{
- OUTB(pB->i2eXMask, value);
+ outb(value, pB->i2eXMask);
}
//******************************************************************************
@@ -1354,9 +1347,8 @@
// immediately and be harmless, though not strictly necessary.
itemp = MAX_DLOAD_ACK_TIME/10;
while (--itemp) {
- if (HAS_INPUT(pB)) {
- switch(BYTE_FROM(pB))
- {
+ if (I2_HAS_INPUT(pB)) {
+ switch (inb(pB->i2eData)) {
case LOADWARE_OK:
pB->i2eState =
isStandard ? II_STATE_STDLOADED :II_STATE_LOADED;
diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h
index 4333050..c88a64e 100644
--- a/drivers/char/ip2/i2ellis.h
+++ b/drivers/char/ip2/i2ellis.h
@@ -185,10 +185,6 @@
// The highest allowable IRQ, based on the
// slot size.
- unsigned char i2eChangeIrq;
- // Whether tis valid to change IRQ's
- // ISA = ok, EISA, MicroChannel, no
-
// Accelerators for various addresses on the board
int i2eBase; // I/O Address of the Board
int i2eData; // From here data transfers happen
@@ -431,12 +427,6 @@
// Manifests for i2eBordStr:
//-------------------------------------------
-#define YES 1
-#define NO 0
-
-#define NULLFUNC (void (*)(void))0
-#define NULLPTR (void *)0
-
typedef void (*delayFunc_t)(unsigned int);
// i2eValid
@@ -494,8 +484,8 @@
// i2eUsingIrq
//
-#define IRQ_UNDEFINED 0x1352 // No valid irq (or polling = 0) can ever
- // promote to this!
+#define I2_IRQ_UNDEFINED 0x1352 /* No valid irq (or polling = 0) can
+ * ever promote to this! */
//------------------------------------------
// Handy Macros for i2ellis.c and others
// Note these are common to -II and -IIEX
@@ -504,41 +494,14 @@
// Given a pointer to the board structure, does the input FIFO have any data or
// not?
//
-#define HAS_INPUT(pB) !(INB(pB->i2eStatus) & ST_IN_EMPTY)
-#define HAS_NO_INPUT(pB) (INB(pB->i2eStatus) & ST_IN_EMPTY)
-
-// Given a pointer to board structure, read a byte or word from the fifo
-//
-#define BYTE_FROM(pB) (unsigned char)INB(pB->i2eData)
-#define WORD_FROM(pB) (unsigned short)INW(pB->i2eData)
-
-// Given a pointer to board structure, is there room for any data to be written
-// to the data fifo?
-//
-#define HAS_OUTROOM(pB) !(INB(pB->i2eStatus) & ST_OUT_FULL)
-#define HAS_NO_OUTROOM(pB) (INB(pB->i2eStatus) & ST_OUT_FULL)
-
-// Given a pointer to board structure, write a single byte to the fifo
-// structure. Note that for 16-bit interfaces, the high order byte is undefined
-// and unknown.
-//
-#define BYTE_TO(pB, c) OUTB(pB->i2eData,(c))
-
-// Write a word to the fifo structure. For 8-bit interfaces, this may have
-// unknown results.
-//
-#define WORD_TO(pB, c) OUTW(pB->i2eData,(c))
+#define I2_HAS_INPUT(pB) !(inb(pB->i2eStatus) & ST_IN_EMPTY)
// Given a pointer to the board structure, is there anything in the incoming
// mailbox?
//
-#define HAS_MAIL(pB) (INB(pB->i2eStatus) & ST_IN_MAIL)
+#define I2_HAS_MAIL(pB) (inb(pB->i2eStatus) & ST_IN_MAIL)
-#define UPDATE_FIFO_ROOM(pB) (pB)->i2eFifoRemains=(pB)->i2eFifoSize
-
-// Handy macro to round up a number (like the buffer write and read routines do)
-//
-#define ROUNDUP(number) (((number)+1) & (~1))
+#define I2_UPDATE_FIFO_ROOM(pB) ((pB)->i2eFifoRemains = (pB)->i2eFifoSize)
//------------------------------------------
// Function Declarations for i2ellis.c
@@ -593,20 +556,11 @@
//
static int iiDownloadAll(i2eBordStrPtr, loadHdrStrPtr, int, int);
-// Called indirectly always. Needed externally so the routine might be
-// SPECIFIED as an argument to iiReset()
-//
-//static void ii2DelayIO(unsigned int); // N-millisecond delay using
- //hardware spin
-//static void ii2DelayTimer(unsigned int); // N-millisecond delay using Linux
- //timer
-
// Many functions defined here return True if good, False otherwise, with an
// error code in i2eError field. Here is a handy macro for setting the error
// code and returning.
//
-#define COMPLETE(pB,code) \
- do { \
+#define I2_COMPLETE(pB,code) do { \
pB->i2eError = code; \
return (code == I2EE_GOOD);\
} while (0)
diff --git a/drivers/char/ip2/i2hw.h b/drivers/char/ip2/i2hw.h
index 15fe04e..8aa6e7a 100644
--- a/drivers/char/ip2/i2hw.h
+++ b/drivers/char/ip2/i2hw.h
@@ -129,7 +129,6 @@
//------------------------------------------------
//
#include "ip2types.h"
-#include "i2os.h" /* For any o.s., compiler, or host-related issues */
//-------------------------------------------------------------------------
// Manifests for the I/O map:
@@ -644,5 +643,10 @@
#define ABS_BIGGEST_BOX 16 // Absolute the most ports per box
#define ABS_MOST_PORTS (ABS_MAX_BOXES * ABS_BIGGEST_BOX)
+#define I2_OUTSW(port, addr, count) outsw((port), (addr), (((count)+1)/2))
+#define I2_OUTSB(port, addr, count) outsb((port), (addr), (((count)+1))&-2)
+#define I2_INSW(port, addr, count) insw((port), (addr), (((count)+1)/2))
+#define I2_INSB(port, addr, count) insb((port), (addr), (((count)+1))&-2)
+
#endif // I2HW_H
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index 9c25320..938879c 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -227,17 +227,17 @@
i2ChanStrPtr *ppCh;
if (pB->i2eValid != I2E_MAGIC) {
- COMPLETE(pB, I2EE_BADMAGIC);
+ I2_COMPLETE(pB, I2EE_BADMAGIC);
}
if (pB->i2eState != II_STATE_STDLOADED) {
- COMPLETE(pB, I2EE_BADSTATE);
+ I2_COMPLETE(pB, I2EE_BADSTATE);
}
- LOCK_INIT(&pB->read_fifo_spinlock);
- LOCK_INIT(&pB->write_fifo_spinlock);
- LOCK_INIT(&pB->Dbuf_spinlock);
- LOCK_INIT(&pB->Bbuf_spinlock);
- LOCK_INIT(&pB->Fbuf_spinlock);
+ rwlock_init(&pB->read_fifo_spinlock);
+ rwlock_init(&pB->write_fifo_spinlock);
+ rwlock_init(&pB->Dbuf_spinlock);
+ rwlock_init(&pB->Bbuf_spinlock);
+ rwlock_init(&pB->Fbuf_spinlock);
// NO LOCK needed yet - this is init
@@ -259,10 +259,10 @@
if ( !(pB->i2eChannelMap[index >> 4] & (1 << (index & 0xf)) ) ) {
continue;
}
- LOCK_INIT(&pCh->Ibuf_spinlock);
- LOCK_INIT(&pCh->Obuf_spinlock);
- LOCK_INIT(&pCh->Cbuf_spinlock);
- LOCK_INIT(&pCh->Pbuf_spinlock);
+ rwlock_init(&pCh->Ibuf_spinlock);
+ rwlock_init(&pCh->Obuf_spinlock);
+ rwlock_init(&pCh->Cbuf_spinlock);
+ rwlock_init(&pCh->Pbuf_spinlock);
// NO LOCK needed yet - this is init
// Set up validity flag according to support level
if (pB->i2eGoodMap[index >> 4] & (1 << (index & 0xf)) ) {
@@ -347,7 +347,7 @@
}
// No need to check for wrap here; this is initialization.
pB->i2Fbuf_stuff = stuffIndex;
- COMPLETE(pB, I2EE_GOOD);
+ I2_COMPLETE(pB, I2EE_GOOD);
}
@@ -374,7 +374,7 @@
case NEED_INLINE:
- WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Dbuf_spinlock, flags);
if ( pB->i2Dbuf_stuff != pB->i2Dbuf_strip)
{
queueIndex = pB->i2Dbuf_strip;
@@ -386,12 +386,12 @@
pB->i2Dbuf_strip = queueIndex;
pCh->channelNeeds &= ~NEED_INLINE;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Dbuf_spinlock, flags);
break;
case NEED_BYPASS:
- WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Bbuf_spinlock, flags);
if (pB->i2Bbuf_stuff != pB->i2Bbuf_strip)
{
queueIndex = pB->i2Bbuf_strip;
@@ -403,12 +403,12 @@
pB->i2Bbuf_strip = queueIndex;
pCh->channelNeeds &= ~NEED_BYPASS;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Bbuf_spinlock, flags);
break;
case NEED_FLOW:
- WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Fbuf_spinlock, flags);
if (pB->i2Fbuf_stuff != pB->i2Fbuf_strip)
{
queueIndex = pB->i2Fbuf_strip;
@@ -420,7 +420,7 @@
pB->i2Fbuf_strip = queueIndex;
pCh->channelNeeds &= ~NEED_FLOW;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Fbuf_spinlock, flags);
break;
default:
printk(KERN_ERR "i2DeQueueNeeds called with bad type:%x\n",type);
@@ -453,7 +453,7 @@
case NEED_INLINE:
- WRITE_LOCK_IRQSAVE(&pB->Dbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Dbuf_spinlock, flags);
if ( !(pCh->channelNeeds & NEED_INLINE) )
{
pCh->channelNeeds |= NEED_INLINE;
@@ -463,12 +463,12 @@
queueIndex = 0;
pB->i2Dbuf_stuff = queueIndex;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Dbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Dbuf_spinlock, flags);
break;
case NEED_BYPASS:
- WRITE_LOCK_IRQSAVE(&pB->Bbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Bbuf_spinlock, flags);
if ((type & NEED_BYPASS) && !(pCh->channelNeeds & NEED_BYPASS))
{
pCh->channelNeeds |= NEED_BYPASS;
@@ -478,12 +478,12 @@
queueIndex = 0;
pB->i2Bbuf_stuff = queueIndex;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Bbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Bbuf_spinlock, flags);
break;
case NEED_FLOW:
- WRITE_LOCK_IRQSAVE(&pB->Fbuf_spinlock,flags);
+ write_lock_irqsave(&pB->Fbuf_spinlock, flags);
if ((type & NEED_FLOW) && !(pCh->channelNeeds & NEED_FLOW))
{
pCh->channelNeeds |= NEED_FLOW;
@@ -493,7 +493,7 @@
queueIndex = 0;
pB->i2Fbuf_stuff = queueIndex;
}
- WRITE_UNLOCK_IRQRESTORE(&pB->Fbuf_spinlock,flags);
+ write_unlock_irqrestore(&pB->Fbuf_spinlock, flags);
break;
case NEED_CREDIT:
@@ -562,9 +562,8 @@
pB = pCh->pMyBord;
// Board must also exist, and THE INTERRUPT COMMAND ALREADY SENT
- if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == IRQ_UNDEFINED) {
+ if (pB->i2eValid != I2E_MAGIC || pB->i2eUsingIrq == I2_IRQ_UNDEFINED)
return -2;
- }
// If the board has gone fatal, return bad, and also hit the trap routine if
// it exists.
if (pB->i2eFatal) {
@@ -620,13 +619,13 @@
switch(type) {
case PTYPE_INLINE:
lock_var_p = &pCh->Obuf_spinlock;
- WRITE_LOCK_IRQSAVE(lock_var_p,flags);
+ write_lock_irqsave(lock_var_p, flags);
stuffIndex = pCh->Obuf_stuff;
bufroom = pCh->Obuf_strip - stuffIndex;
break;
case PTYPE_BYPASS:
lock_var_p = &pCh->Cbuf_spinlock;
- WRITE_LOCK_IRQSAVE(lock_var_p,flags);
+ write_lock_irqsave(lock_var_p, flags);
stuffIndex = pCh->Cbuf_stuff;
bufroom = pCh->Cbuf_strip - stuffIndex;
break;
@@ -645,7 +644,7 @@
break; /* from for()- Enough room: goto proceed */
}
ip2trace(CHANN, ITRC_QUEUE, 3, 1, totalsize);
- WRITE_UNLOCK_IRQRESTORE(lock_var_p, flags);
+ write_unlock_irqrestore(lock_var_p, flags);
} else
ip2trace(CHANN, ITRC_QUEUE, 3, 1, totalsize);
@@ -747,7 +746,7 @@
{
case PTYPE_INLINE:
pCh->Obuf_stuff = stuffIndex; // Store buffer pointer
- WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
pB->debugInlineQueued++;
// Add the channel pointer to list of channels needing service (first
@@ -757,7 +756,7 @@
case PTYPE_BYPASS:
pCh->Cbuf_stuff = stuffIndex; // Store buffer pointer
- WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Cbuf_spinlock, flags);
pB->debugBypassQueued++;
// Add the channel pointer to list of channels needing service (first
@@ -840,7 +839,7 @@
count = -1;
goto i2Input_exit;
}
- WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Ibuf_spinlock, flags);
// initialize some accelerators and private copies
stripIndex = pCh->Ibuf_strip;
@@ -850,7 +849,7 @@
// If buffer is empty or requested data count was 0, (trivial case) return
// without any further thought.
if ( count == 0 ) {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
goto i2Input_exit;
}
// Adjust for buffer wrap
@@ -891,10 +890,10 @@
if ((pCh->sinceLastFlow += count) >= pCh->whenSendFlow) {
pCh->sinceLastFlow -= pCh->whenSendFlow;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW);
} else {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
}
i2Input_exit:
@@ -926,7 +925,7 @@
ip2trace (CHANN, ITRC_INPUT, 10, 0);
- WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Ibuf_spinlock, flags);
count = pCh->Ibuf_stuff - pCh->Ibuf_strip;
// Adjust for buffer wrap
@@ -947,10 +946,10 @@
if ( (pCh->sinceLastFlow += count) >= pCh->whenSendFlow )
{
pCh->sinceLastFlow -= pCh->whenSendFlow;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
i2QueueNeeds(pCh->pMyBord, pCh, NEED_FLOW);
} else {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
}
ip2trace (CHANN, ITRC_INPUT, 19, 1, count);
@@ -979,9 +978,9 @@
// initialize some accelerators and private copies
- READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
count = pCh->Ibuf_stuff - pCh->Ibuf_strip;
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
// Adjust for buffer wrap
if (count < 0)
@@ -1045,9 +1044,9 @@
while ( count > 0 ) {
// How much room in output buffer is there?
- READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Obuf_spinlock, flags);
amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1;
- READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
if (amountToMove < 0) {
amountToMove += OBUF_SIZE;
}
@@ -1075,7 +1074,7 @@
if ( !(pCh->flush_flags && i2RetryFlushOutput(pCh) )
&& amountToMove > 0 )
{
- WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Obuf_spinlock, flags);
stuffIndex = pCh->Obuf_stuff;
// Had room to move some data: don't know whether the block size,
@@ -1102,7 +1101,7 @@
}
pCh->Obuf_stuff = stuffIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
ip2trace (CHANN, ITRC_OUTPUT, 13, 1, stuffIndex );
@@ -1352,9 +1351,9 @@
if ( !i2Validate ( pCh ) ) {
return -1;
}
- READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Obuf_spinlock, flags);
amountToMove = pCh->Obuf_strip - pCh->Obuf_stuff - 1;
- READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
if (amountToMove < 0) {
amountToMove += OBUF_SIZE;
@@ -1464,11 +1463,11 @@
// ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_ENTER, 0 );
- while (HAS_INPUT(pB)) {
+ while (I2_HAS_INPUT(pB)) {
// ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 2, 0 );
// Process packet from fifo a one atomic unit
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock,bflags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, bflags);
// The first word (or two bytes) will have channel number and type of
// packet, possibly other information
@@ -1490,7 +1489,8 @@
// sick!
if ( ((unsigned int)count) > IBUF_SIZE ) {
pB->i2eFatal = 2;
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
return; /* Bail out ASAP */
}
// Channel is illegally big ?
@@ -1498,7 +1498,8 @@
(NULL==(pCh = ((i2ChanStrPtr*)pB->i2eChannelPtr)[channel])))
{
iiReadBuf(pB, junkBuffer, count);
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
break; /* From switch: ready for next packet */
}
@@ -1512,14 +1513,15 @@
if(ID_OF(pB->i2eLeadoffWord) == ID_HOT_KEY)
{
pCh->hotKeyIn = iiReadWord(pB) & 0xff;
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_HOTACK);
break; /* From the switch: ready for next packet */
}
// Normal data! We crudely assume there is room for the data in our
// buffer because the board wouldn't have exceeded his credit limit.
- WRITE_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,cflags);
+ write_lock_irqsave(&pCh->Ibuf_spinlock, cflags);
// We have 2 locks now
stuffIndex = pCh->Ibuf_stuff;
amountToRead = IBUF_SIZE - stuffIndex;
@@ -1562,8 +1564,9 @@
// Update stuff index
pCh->Ibuf_stuff = stuffIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,cflags);
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pCh->Ibuf_spinlock, cflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
#ifdef USE_IQ
schedule_work(&pCh->tqueue_input);
@@ -1585,7 +1588,8 @@
iiReadBuf(pB, cmdBuffer, count);
// We can release early with buffer grab
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,bflags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
+ bflags);
pc = cmdBuffer;
pcLimit = &(cmdBuffer[count]);
@@ -1830,12 +1834,12 @@
default: // Neither packet? should be impossible
ip2trace (ITRC_NO_PORT, ITRC_SFIFO, 5, 1,
PTYPE_OF(pB->i2eLeadoffWord) );
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock,
+ write_unlock_irqrestore(&pB->read_fifo_spinlock,
bflags);
break;
} // End of switch on type of packets
- } //while(board HAS_INPUT)
+ } /*while(board I2_HAS_INPUT)*/
ip2trace (ITRC_NO_PORT, ITRC_SFIFO, ITRC_RETURN, 0 );
@@ -1858,7 +1862,7 @@
{
int rc = 0;
unsigned long flags;
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
if (!pB->i2eWaitingForEmptyFifo) {
if (pB->i2eFifoRemains > (count+reserve)) {
pB->i2eFifoRemains -= count;
@@ -1867,7 +1871,7 @@
rc = count;
}
}
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
return rc;
}
//******************************************************************************
@@ -1898,7 +1902,7 @@
while ( --bailout && notClogged &&
(NULL != (pCh = i2DeQueueNeeds(pB,NEED_BYPASS))))
{
- WRITE_LOCK_IRQSAVE(&pCh->Cbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Cbuf_spinlock, flags);
stripIndex = pCh->Cbuf_strip;
// as long as there are packets for this channel...
@@ -1906,7 +1910,7 @@
while (stripIndex != pCh->Cbuf_stuff) {
pRemove = &(pCh->Cbuf[stripIndex]);
packetSize = CMD_COUNT_OF(pRemove) + sizeof(i2CmdHeader);
- paddedSize = ROUNDUP(packetSize);
+ paddedSize = roundup(packetSize, 2);
if (paddedSize > 0) {
if ( 0 == i2Write2Fifo(pB, pRemove, paddedSize,0)) {
@@ -1930,7 +1934,7 @@
// Done with this channel. Move to next, removing this one from
// the queue of channels if we cleaned it out (i.e., didn't get clogged.
pCh->Cbuf_strip = stripIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Cbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Cbuf_spinlock, flags);
} // Either clogged or finished all the work
#ifdef IP2DEBUG_TRACE
@@ -1954,7 +1958,7 @@
i2StuffFifoFlow(i2eBordStrPtr pB)
{
i2ChanStrPtr pCh;
- unsigned short paddedSize = ROUNDUP(sizeof(flowIn));
+ unsigned short paddedSize = roundup(sizeof(flowIn), 2);
ip2trace (ITRC_NO_PORT, ITRC_SFLOW, ITRC_ENTER, 2,
pB->i2eFifoRemains, paddedSize );
@@ -2010,7 +2014,7 @@
while ( --bailout && notClogged &&
(NULL != (pCh = i2DeQueueNeeds(pB,NEED_INLINE))) )
{
- WRITE_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Obuf_spinlock, flags);
stripIndex = pCh->Obuf_strip;
ip2trace (CHANN, ITRC_SICMD, 3, 2, stripIndex, pCh->Obuf_stuff );
@@ -2031,7 +2035,7 @@
packetSize = flowsize + sizeof(i2CmdHeader);
}
flowsize = CREDIT_USAGE(flowsize);
- paddedSize = ROUNDUP(packetSize);
+ paddedSize = roundup(packetSize, 2);
ip2trace (CHANN, ITRC_SICMD, 4, 2, pB->i2eFifoRemains, paddedSize );
@@ -2086,7 +2090,7 @@
// Done with this channel. Move to next, removing this one from the
// queue of channels if we cleaned it out (i.e., didn't get clogged.
pCh->Obuf_strip = stripIndex;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
if ( notClogged )
{
@@ -2190,10 +2194,11 @@
if (inmail & MB_OUT_STRIPPED) {
pB->i2eFifoOutInts++;
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
pB->i2eFifoRemains = pB->i2eFifoSize;
pB->i2eWaitingForEmptyFifo = 0;
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock,
+ flags);
ip2trace (ITRC_NO_PORT, ITRC_INTR, 30, 1, pB->i2eFifoRemains );
diff --git a/drivers/char/ip2/i2os.h b/drivers/char/ip2/i2os.h
deleted file mode 100644
index eff9b54..0000000
--- a/drivers/char/ip2/i2os.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*******************************************************************************
-*
-* (c) 1999 by Computone Corporation
-*
-********************************************************************************
-*
-*
-* PACKAGE: Linux tty Device Driver for IntelliPort II family of multiport
-* serial I/O controllers.
-*
-* DESCRIPTION: Defines, definitions and includes which are heavily dependent
-* on O/S, host, compiler, etc. This file is tailored for:
-* Linux v2.0.0 and later
-* Gnu gcc c2.7.2
-* 80x86 architecture
-*
-*******************************************************************************/
-
-#ifndef I2OS_H /* To prevent multiple includes */
-#define I2OS_H 1
-
-//-------------------------------------------------
-// Required Includes
-//-------------------------------------------------
-
-#include "ip2types.h"
-#include <asm/io.h> /* For inb, etc */
-
-//------------------------------------
-// Defines for I/O instructions:
-//------------------------------------
-
-#define INB(port) inb(port)
-#define OUTB(port,value) outb((value),(port))
-#define INW(port) inw(port)
-#define OUTW(port,value) outw((value),(port))
-#define OUTSW(port,addr,count) outsw((port),(addr),(((count)+1)/2))
-#define OUTSB(port,addr,count) outsb((port),(addr),(((count)+1))&-2)
-#define INSW(port,addr,count) insw((port),(addr),(((count)+1)/2))
-#define INSB(port,addr,count) insb((port),(addr),(((count)+1))&-2)
-
-//--------------------------------------------
-// Interrupt control
-//--------------------------------------------
-
-#define LOCK_INIT(a) rwlock_init(a)
-
-#define SAVE_AND_DISABLE_INTS(a,b) { \
- /* printk("get_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- spin_lock_irqsave(a,b); \
-}
-
-#define RESTORE_INTS(a,b) { \
- /* printk("rel_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- spin_unlock_irqrestore(a,b); \
-}
-
-#define READ_LOCK_IRQSAVE(a,b) { \
- /* printk("get_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- read_lock_irqsave(a,b); \
-}
-
-#define READ_UNLOCK_IRQRESTORE(a,b) { \
- /* printk("rel_read_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- read_unlock_irqrestore(a,b); \
-}
-
-#define WRITE_LOCK_IRQSAVE(a,b) { \
- /* printk("get_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- write_lock_irqsave(a,b); \
-}
-
-#define WRITE_UNLOCK_IRQRESTORE(a,b) { \
- /* printk("rel_write_lock: 0x%x,%4d,%s\n",(int)a,__LINE__,__FILE__);*/ \
- write_unlock_irqrestore(a,b); \
-}
-
-
-//------------------------------------------------------------------------------
-// Hardware-delay loop
-//
-// Probably used in only one place (see i2ellis.c) but this helps keep things
-// together. Note we have unwound the IN instructions. On machines with a
-// reasonable cache, the eight instructions (1 byte each) should fit in cache
-// nicely, and on un-cached machines, the code-fetch would tend not to dominate.
-// Note that cx is shifted so that "count" still reflects the total number of
-// iterations assuming no unwinding.
-//------------------------------------------------------------------------------
-
-//#define DELAY1MS(port,count,label)
-
-//------------------------------------------------------------------------------
-// Macros to switch to a new stack, saving stack pointers, and to restore the
-// old stack (Used, for example, in i2lib.c) "heap" is the address of some
-// buffer which will become the new stack (working down from highest address).
-// The two words at the two lowest addresses in this stack are for storing the
-// SS and SP.
-//------------------------------------------------------------------------------
-
-//#define TO_NEW_STACK(heap,size)
-//#define TO_OLD_STACK(heap)
-
-//------------------------------------------------------------------------------
-// Macros to save the original IRQ vectors and masks, and to patch in new ones.
-//------------------------------------------------------------------------------
-
-//#define SAVE_IRQ_MASKS(dest)
-//#define WRITE_IRQ_MASKS(src)
-//#define SAVE_IRQ_VECTOR(value,dest)
-//#define WRITE_IRQ_VECTOR(value,src)
-
-//------------------------------------------------------------------------------
-// Macro to copy data from one far pointer to another.
-//------------------------------------------------------------------------------
-
-#define I2_MOVE_DATA(fpSource,fpDest,count) memmove(fpDest,fpSource,count);
-
-//------------------------------------------------------------------------------
-// Macros to issue eoi's to host interrupt control (IBM AT 8259-style).
-//------------------------------------------------------------------------------
-
-//#define MASTER_EOI
-//#define SLAVE_EOI
-
-#endif /* I2OS_H */
-
-
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index b1d6cad..70957ac 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -133,8 +133,9 @@
*****************/
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
-static int ip2_read_procmem(char *, char **, off_t, int);
+static const struct file_operations ip2mem_proc_fops;
static int ip2_read_proc(char *, char **, off_t, int, int *, void * );
/********************/
@@ -168,7 +169,7 @@
static int ip2_open(PTTY, struct file *);
static void ip2_close(PTTY, struct file *);
static int ip2_write(PTTY, const unsigned char *, int);
-static void ip2_putchar(PTTY, unsigned char);
+static int ip2_putchar(PTTY, unsigned char);
static void ip2_flush_chars(PTTY);
static int ip2_write_room(PTTY);
static int ip2_chars_in_buf(PTTY);
@@ -354,14 +355,15 @@
/* the driver initialisation function and returns what it returns. */
/******************************************************************************/
#ifdef MODULE
-int
-init_module(void)
+static int __init
+ip2_init_module(void)
{
#ifdef IP2DEBUG_INIT
printk (KERN_DEBUG "Loading module ...\n" );
#endif
return 0;
}
+module_init(ip2_init_module);
#endif /* MODULE */
/******************************************************************************/
@@ -380,8 +382,8 @@
/* driver should be returned since it may be unloaded from memory. */
/******************************************************************************/
#ifdef MODULE
-void
-cleanup_module(void)
+void __exit
+ip2_cleanup_module(void)
{
int err;
int i;
@@ -423,7 +425,7 @@
}
put_tty_driver(ip2_tty_driver);
unregister_chrdev(IP2_IPL_MAJOR, pcIpl);
- remove_proc_entry("ip2mem", &proc_root);
+ remove_proc_entry("ip2mem", NULL);
// free memory
for (i = 0; i < IP2_MAX_BOARDS; i++) {
@@ -451,6 +453,7 @@
printk (KERN_DEBUG "IP2 Unloaded\n" );
#endif
}
+module_exit(ip2_cleanup_module);
#endif /* MODULE */
static const struct tty_operations ip2_ops = {
@@ -695,7 +698,7 @@
}
}
/* Register the read_procmem thing */
- if (!create_proc_info_entry("ip2mem",0,&proc_root,ip2_read_procmem)) {
+ if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) {
printk(KERN_ERR "IP2: failed to register read_procmem\n");
} else {
@@ -1049,9 +1052,9 @@
* Write to FIFO; don't bother to adjust fifo capacity for this, since
* board will respond almost immediately after SendMail hit.
*/
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
iiWriteBuf(pB, tempCommand, 4);
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
pB->i2eUsingIrq = boardIrq;
pB->i2eOutMailWaiting |= MB_OUT_STUFFED;
@@ -1069,9 +1072,9 @@
(CMD_OF(tempCommand))[4] = 64; // chars
(CMD_OF(tempCommand))[5] = 87; // HW_TEST
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
iiWriteBuf(pB, tempCommand, 8);
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
CHANNEL_OF(tempCommand) = 0;
PTYPE_OF(tempCommand) = PTYPE_BYPASS;
@@ -1086,9 +1089,9 @@
CMD_COUNT_OF(tempCommand) = 2;
(CMD_OF(tempCommand))[0] = 44; /* get ping */
(CMD_OF(tempCommand))[1] = 200; /* 200 ms */
- WRITE_LOCK_IRQSAVE(&pB->write_fifo_spinlock,flags);
+ write_lock_irqsave(&pB->write_fifo_spinlock, flags);
iiWriteBuf(pB, tempCommand, 4);
- WRITE_UNLOCK_IRQRESTORE(&pB->write_fifo_spinlock,flags);
+ write_unlock_irqrestore(&pB->write_fifo_spinlock, flags);
#endif
iiEnableMailIrq(pB);
@@ -1267,12 +1270,12 @@
// Data input
if ( pCh->pTTY != NULL ) {
- READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
+ read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
if (!pCh->throttled && (pCh->Ibuf_stuff != pCh->Ibuf_strip)) {
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
i2Input( pCh );
} else
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
} else {
ip2trace(CHANN, ITRC_INPUT, 22, 0 );
@@ -1613,10 +1616,8 @@
serviceOutgoingFifo ( pCh->pMyBord );
- if ( tty->driver->flush_buffer )
- tty->driver->flush_buffer(tty);
- if ( tty->ldisc.flush_buffer )
- tty->ldisc.flush_buffer(tty);
+ tty_ldisc_flush(tty);
+ tty_driver_flush_buffer(tty);
tty->closing = 0;
pCh->pTTY = NULL;
@@ -1716,9 +1717,9 @@
ip2_flush_chars( tty );
/* This is the actual move bit. Make sure it does what we need!!!!! */
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
bytesSent = i2Output( pCh, pData, count);
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
@@ -1735,7 +1736,7 @@
/* */
/* */
/******************************************************************************/
-static void
+static int
ip2_putchar( PTTY tty, unsigned char ch )
{
i2ChanStrPtr pCh = tty->driver_data;
@@ -1743,13 +1744,14 @@
// ip2trace (CHANN, ITRC_PUTC, ITRC_ENTER, 1, ch );
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
pCh->Pbuf[pCh->Pbuf_stuff++] = ch;
if ( pCh->Pbuf_stuff == sizeof pCh->Pbuf ) {
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
ip2_flush_chars( tty );
} else
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
+ return 1;
// ip2trace (CHANN, ITRC_PUTC, ITRC_RETURN, 1, ch );
}
@@ -1769,7 +1771,7 @@
i2ChanStrPtr pCh = tty->driver_data;
unsigned long flags;
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
if ( pCh->Pbuf_stuff ) {
// ip2trace (CHANN, ITRC_PUTC, 10, 1, strip );
@@ -1783,7 +1785,7 @@
}
pCh->Pbuf_stuff -= strip;
}
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
}
/******************************************************************************/
@@ -1801,9 +1803,9 @@
i2ChanStrPtr pCh = tty->driver_data;
unsigned long flags;
- READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
bytesFree = i2OutputFree( pCh ) - pCh->Pbuf_stuff;
- READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
ip2trace (CHANN, ITRC_WRITE, 11, 1, bytesFree );
@@ -1833,12 +1835,12 @@
pCh->Obuf_char_count + pCh->Pbuf_stuff,
pCh->Obuf_char_count, pCh->Pbuf_stuff );
#endif
- READ_LOCK_IRQSAVE(&pCh->Obuf_spinlock,flags);
+ read_lock_irqsave(&pCh->Obuf_spinlock, flags);
rc = pCh->Obuf_char_count;
- READ_UNLOCK_IRQRESTORE(&pCh->Obuf_spinlock,flags);
- READ_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Obuf_spinlock, flags);
+ read_lock_irqsave(&pCh->Pbuf_spinlock, flags);
rc += pCh->Pbuf_stuff;
- READ_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ read_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
return rc;
}
@@ -1862,9 +1864,9 @@
#ifdef IP2DEBUG_WRITE
printk (KERN_DEBUG "IP2: flush buffer\n" );
#endif
- WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
+ write_lock_irqsave(&pCh->Pbuf_spinlock, flags);
pCh->Pbuf_stuff = 0;
- WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
+ write_unlock_irqrestore(&pCh->Pbuf_spinlock, flags);
i2FlushOutput( pCh );
ip2_owake(tty);
@@ -1950,15 +1952,15 @@
pCh->throttled = 0;
i2QueueCommands(PTYPE_BYPASS, pCh, 0, 1, CMD_RESUME);
serviceOutgoingFifo( pCh->pMyBord );
- READ_LOCK_IRQSAVE(&pCh->Ibuf_spinlock,flags)
+ read_lock_irqsave(&pCh->Ibuf_spinlock, flags);
if ( pCh->Ibuf_stuff != pCh->Ibuf_strip ) {
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
#ifdef IP2DEBUG_READ
printk (KERN_DEBUG "i2Input called from unthrottle\n" );
#endif
i2Input( pCh );
} else
- READ_UNLOCK_IRQRESTORE(&pCh->Ibuf_spinlock,flags)
+ read_unlock_irqrestore(&pCh->Ibuf_spinlock, flags);
}
static void
@@ -2201,9 +2203,9 @@
* for masking). Caller should use TIOCGICOUNT to see which one it was
*/
case TIOCMIWAIT:
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
cprev = pCh->icount; /* note the counters on entry */
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
i2QueueCommands(PTYPE_BYPASS, pCh, 100, 4,
CMD_DCD_REP, CMD_CTS_REP, CMD_DSR_REP, CMD_RI_REP);
init_waitqueue_entry(&wait, current);
@@ -2223,9 +2225,9 @@
rc = -ERESTARTSYS;
break;
}
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
cnow = pCh->icount; /* atomic copy */
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) {
rc = -EIO; /* no change => rc */
@@ -2263,9 +2265,9 @@
case TIOCGICOUNT:
ip2trace (CHANN, ITRC_IOCTL, 11, 1, rc );
- WRITE_LOCK_IRQSAVE(&pB->read_fifo_spinlock, flags);
+ write_lock_irqsave(&pB->read_fifo_spinlock, flags);
cnow = pCh->icount;
- WRITE_UNLOCK_IRQRESTORE(&pB->read_fifo_spinlock, flags);
+ write_unlock_irqrestore(&pB->read_fifo_spinlock, flags);
p_cuser = argp;
rc = put_user(cnow.cts, &p_cuser->cts);
rc = put_user(cnow.dsr, &p_cuser->dsr);
@@ -2871,7 +2873,7 @@
case 65: /* Board - ip2stat */
if ( pB ) {
rc = copy_to_user(argp, pB, sizeof(i2eBordStr));
- rc = put_user(INB(pB->i2eStatus),
+ rc = put_user(inb(pB->i2eStatus),
(ULONG __user *)(arg + (ULONG)(&pB->i2eStatus) - (ULONG)pB ) );
} else {
rc = -ENODEV;
@@ -2967,65 +2969,61 @@
}
return 0;
}
-/******************************************************************************/
-/* Function: ip2_read_procmem */
-/* Parameters: */
-/* */
-/* Returns: Length of output */
-/* */
-/* Description: */
-/* Supplies some driver operating parameters */
-/* Not real useful unless your debugging the fifo */
-/* */
-/******************************************************************************/
-
-#define LIMIT (PAGE_SIZE - 120)
static int
-ip2_read_procmem(char *buf, char **start, off_t offset, int len)
+proc_ip2mem_show(struct seq_file *m, void *v)
{
i2eBordStrPtr pB;
i2ChanStrPtr pCh;
PTTY tty;
int i;
- len = 0;
-
#define FMTLINE "%3d: 0x%08x 0x%08x 0%011o 0%011o\n"
#define FMTLIN2 " 0x%04x 0x%04x tx flow 0x%x\n"
#define FMTLIN3 " 0x%04x 0x%04x rc flow\n"
- len += sprintf(buf+len,"\n");
+ seq_printf(m,"\n");
for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
pB = i2BoardPtrTable[i];
if ( pB ) {
- len += sprintf(buf+len,"board %d:\n",i);
- len += sprintf(buf+len,"\tFifo rem: %d mty: %x outM %x\n",
+ seq_printf(m,"board %d:\n",i);
+ seq_printf(m,"\tFifo rem: %d mty: %x outM %x\n",
pB->i2eFifoRemains,pB->i2eWaitingForEmptyFifo,pB->i2eOutMailWaiting);
}
}
- len += sprintf(buf+len,"#: tty flags, port flags, cflags, iflags\n");
+ seq_printf(m,"#: tty flags, port flags, cflags, iflags\n");
for (i=0; i < IP2_MAX_PORTS; i++) {
- if (len > LIMIT)
- break;
pCh = DevTable[i];
if (pCh) {
tty = pCh->pTTY;
if (tty && tty->count) {
- len += sprintf(buf+len,FMTLINE,i,(int)tty->flags,pCh->flags,
+ seq_printf(m,FMTLINE,i,(int)tty->flags,pCh->flags,
tty->termios->c_cflag,tty->termios->c_iflag);
- len += sprintf(buf+len,FMTLIN2,
+ seq_printf(m,FMTLIN2,
pCh->outfl.asof,pCh->outfl.room,pCh->channelNeeds);
- len += sprintf(buf+len,FMTLIN3,pCh->infl.asof,pCh->infl.room);
+ seq_printf(m,FMTLIN3,pCh->infl.asof,pCh->infl.room);
}
}
}
- return len;
+ return 0;
}
+static int proc_ip2mem_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_ip2mem_show, NULL);
+}
+
+static const struct file_operations ip2mem_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_ip2mem_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/*
* This is the handler for /proc/tty/driver/ip2
*
diff --git a/drivers/char/ipmi/Makefile b/drivers/char/ipmi/Makefile
index 553f0a4..eb8a1a8 100644
--- a/drivers/char/ipmi/Makefile
+++ b/drivers/char/ipmi/Makefile
@@ -9,7 +9,3 @@
obj-$(CONFIG_IPMI_SI) += ipmi_si.o
obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
-
-ipmi_si.o: $(ipmi_si-objs)
- $(LD) -r -o $@ $(ipmi_si-objs)
-
diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c
index e736119..7b98c06 100644
--- a/drivers/char/ipmi/ipmi_bt_sm.c
+++ b/drivers/char/ipmi/ipmi_bt_sm.c
@@ -37,26 +37,32 @@
#define BT_DEBUG_ENABLE 1 /* Generic messages */
#define BT_DEBUG_MSG 2 /* Prints all request/response buffers */
#define BT_DEBUG_STATES 4 /* Verbose look at state changes */
-/* BT_DEBUG_OFF must be zero to correspond to the default uninitialized
- value */
+/*
+ * BT_DEBUG_OFF must be zero to correspond to the default uninitialized
+ * value
+ */
static int bt_debug; /* 0 == BT_DEBUG_OFF */
module_param(bt_debug, int, 0644);
MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states");
-/* Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
- and 64 byte buffers. However, one HP implementation wants 255 bytes of
- buffer (with a documented message of 160 bytes) so go for the max.
- Since the Open IPMI architecture is single-message oriented at this
- stage, the queue depth of BT is of no concern. */
+/*
+ * Typical "Get BT Capabilities" values are 2-3 retries, 5-10 seconds,
+ * and 64 byte buffers. However, one HP implementation wants 255 bytes of
+ * buffer (with a documented message of 160 bytes) so go for the max.
+ * Since the Open IPMI architecture is single-message oriented at this
+ * stage, the queue depth of BT is of no concern.
+ */
#define BT_NORMAL_TIMEOUT 5 /* seconds */
#define BT_NORMAL_RETRY_LIMIT 2
#define BT_RESET_DELAY 6 /* seconds after warm reset */
-/* States are written in chronological order and usually cover
- multiple rows of the state table discussion in the IPMI spec. */
+/*
+ * States are written in chronological order and usually cover
+ * multiple rows of the state table discussion in the IPMI spec.
+ */
enum bt_states {
BT_STATE_IDLE = 0, /* Order is critical in this list */
@@ -76,10 +82,12 @@
BT_STATE_LONG_BUSY /* BT doesn't get hosed :-) */
};
-/* Macros seen at the end of state "case" blocks. They help with legibility
- and debugging. */
+/*
+ * Macros seen at the end of state "case" blocks. They help with legibility
+ * and debugging.
+ */
-#define BT_STATE_CHANGE(X,Y) { bt->state = X; return Y; }
+#define BT_STATE_CHANGE(X, Y) { bt->state = X; return Y; }
#define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; }
@@ -110,11 +118,13 @@
#define BT_H_BUSY 0x40
#define BT_B_BUSY 0x80
-/* Some bits are toggled on each write: write once to set it, once
- more to clear it; writing a zero does nothing. To absolutely
- clear it, check its state and write if set. This avoids the "get
- current then use as mask" scheme to modify one bit. Note that the
- variable "bt" is hardcoded into these macros. */
+/*
+ * Some bits are toggled on each write: write once to set it, once
+ * more to clear it; writing a zero does nothing. To absolutely
+ * clear it, check its state and write if set. This avoids the "get
+ * current then use as mask" scheme to modify one bit. Note that the
+ * variable "bt" is hardcoded into these macros.
+ */
#define BT_STATUS bt->io->inputb(bt->io, 0)
#define BT_CONTROL(x) bt->io->outputb(bt->io, 0, x)
@@ -125,8 +135,10 @@
#define BT_INTMASK_R bt->io->inputb(bt->io, 2)
#define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x)
-/* Convenience routines for debugging. These are not multi-open safe!
- Note the macros have hardcoded variables in them. */
+/*
+ * Convenience routines for debugging. These are not multi-open safe!
+ * Note the macros have hardcoded variables in them.
+ */
static char *state2txt(unsigned char state)
{
@@ -182,7 +194,8 @@
static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
{
memset(bt, 0, sizeof(struct si_sm_data));
- if (bt->io != io) { /* external: one-time only things */
+ if (bt->io != io) {
+ /* external: one-time only things */
bt->io = io;
bt->seq = 0;
}
@@ -229,7 +242,7 @@
printk(KERN_WARNING "BT: +++++++++++++++++ New command\n");
printk(KERN_WARNING "BT: NetFn/LUN CMD [%d data]:", size - 2);
for (i = 0; i < size; i ++)
- printk (" %02x", data[i]);
+ printk(" %02x", data[i]);
printk("\n");
}
bt->write_data[0] = size + 1; /* all data plus seq byte */
@@ -246,8 +259,10 @@
return 0;
}
-/* After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE
- it calls this. Strip out the length and seq bytes. */
+/*
+ * After the upper state machine has been told SI_SM_TRANSACTION_COMPLETE
+ * it calls this. Strip out the length and seq bytes.
+ */
static int bt_get_result(struct si_sm_data *bt,
unsigned char *data,
@@ -269,10 +284,10 @@
memcpy(data + 2, bt->read_data + 4, msg_len - 2);
if (bt_debug & BT_DEBUG_MSG) {
- printk (KERN_WARNING "BT: result %d bytes:", msg_len);
+ printk(KERN_WARNING "BT: result %d bytes:", msg_len);
for (i = 0; i < msg_len; i++)
printk(" %02x", data[i]);
- printk ("\n");
+ printk("\n");
}
return msg_len;
}
@@ -292,8 +307,10 @@
BT_INTMASK_W(BT_BMC_HWRST);
}
-/* Get rid of an unwanted/stale response. This should only be needed for
- BMCs that support multiple outstanding requests. */
+/*
+ * Get rid of an unwanted/stale response. This should only be needed for
+ * BMCs that support multiple outstanding requests.
+ */
static void drain_BMC2HOST(struct si_sm_data *bt)
{
@@ -326,8 +343,8 @@
printk(KERN_WARNING "BT: write %d bytes seq=0x%02X",
bt->write_count, bt->seq);
for (i = 0; i < bt->write_count; i++)
- printk (" %02x", bt->write_data[i]);
- printk ("\n");
+ printk(" %02x", bt->write_data[i]);
+ printk("\n");
}
for (i = 0; i < bt->write_count; i++)
HOST2BMC(bt->write_data[i]);
@@ -337,8 +354,10 @@
{
unsigned char i;
- /* length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode.
- Keep layout of first four bytes aligned with write_data[] */
+ /*
+ * length is "framing info", minimum = 4: NetFn, Seq, Cmd, cCode.
+ * Keep layout of first four bytes aligned with write_data[]
+ */
bt->read_data[0] = BMC2HOST;
bt->read_count = bt->read_data[0];
@@ -362,8 +381,8 @@
if (max > 16)
max = 16;
for (i = 0; i < max; i++)
- printk (" %02x", bt->read_data[i]);
- printk ("%s\n", bt->read_count == max ? "" : " ...");
+ printk(KERN_CONT " %02x", bt->read_data[i]);
+ printk(KERN_CONT "%s\n", bt->read_count == max ? "" : " ...");
}
/* per the spec, the (NetFn[1], Seq[2], Cmd[3]) tuples must match */
@@ -402,8 +421,10 @@
printk(KERN_WARNING "IPMI BT: %s in %s %s ", /* open-ended line */
reason, STATE2TXT, STATUS2TXT);
- /* Per the IPMI spec, retries are based on the sequence number
- known only to this module, so manage a restart here. */
+ /*
+ * Per the IPMI spec, retries are based on the sequence number
+ * known only to this module, so manage a restart here.
+ */
(bt->error_retries)++;
if (bt->error_retries < bt->BT_CAP_retries) {
printk("%d retries left\n",
@@ -412,8 +433,8 @@
return SI_SM_CALL_WITHOUT_DELAY;
}
- printk("failed %d retries, sending error response\n",
- bt->BT_CAP_retries);
+ printk(KERN_WARNING "failed %d retries, sending error response\n",
+ bt->BT_CAP_retries);
if (!bt->nonzero_status)
printk(KERN_ERR "IPMI BT: stuck, try power cycle\n");
@@ -424,8 +445,10 @@
return SI_SM_CALL_WITHOUT_DELAY;
}
- /* Concoct a useful error message, set up the next state, and
- be done with this sequence. */
+ /*
+ * Concoct a useful error message, set up the next state, and
+ * be done with this sequence.
+ */
bt->state = BT_STATE_IDLE;
switch (cCode) {
@@ -461,10 +484,12 @@
last_printed = bt->state;
}
- /* Commands that time out may still (eventually) provide a response.
- This stale response will get in the way of a new response so remove
- it if possible (hopefully during IDLE). Even if it comes up later
- it will be rejected by its (now-forgotten) seq number. */
+ /*
+ * Commands that time out may still (eventually) provide a response.
+ * This stale response will get in the way of a new response so remove
+ * it if possible (hopefully during IDLE). Even if it comes up later
+ * it will be rejected by its (now-forgotten) seq number.
+ */
if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) {
drain_BMC2HOST(bt);
@@ -472,7 +497,8 @@
}
if ((bt->state != BT_STATE_IDLE) &&
- (bt->state < BT_STATE_PRINTME)) { /* check timeout */
+ (bt->state < BT_STATE_PRINTME)) {
+ /* check timeout */
bt->timeout -= time;
if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1))
return error_recovery(bt,
@@ -482,8 +508,10 @@
switch (bt->state) {
- /* Idle state first checks for asynchronous messages from another
- channel, then does some opportunistic housekeeping. */
+ /*
+ * Idle state first checks for asynchronous messages from another
+ * channel, then does some opportunistic housekeeping.
+ */
case BT_STATE_IDLE:
if (status & BT_SMS_ATN) {
@@ -531,16 +559,19 @@
BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
BT_CONTROL(BT_H_BUSY); /* set */
- /* Uncached, ordered writes should just proceeed serially but
- some BMCs don't clear B2H_ATN with one hit. Fast-path a
- workaround without too much penalty to the general case. */
+ /*
+ * Uncached, ordered writes should just proceeed serially but
+ * some BMCs don't clear B2H_ATN with one hit. Fast-path a
+ * workaround without too much penalty to the general case.
+ */
BT_CONTROL(BT_B2H_ATN); /* clear it to ACK the BMC */
BT_STATE_CHANGE(BT_STATE_CLEAR_B2H,
SI_SM_CALL_WITHOUT_DELAY);
case BT_STATE_CLEAR_B2H:
- if (status & BT_B2H_ATN) { /* keep hitting it */
+ if (status & BT_B2H_ATN) {
+ /* keep hitting it */
BT_CONTROL(BT_B2H_ATN);
BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
}
@@ -548,7 +579,8 @@
SI_SM_CALL_WITHOUT_DELAY);
case BT_STATE_READ_BYTES:
- if (!(status & BT_H_BUSY)) /* check in case of retry */
+ if (!(status & BT_H_BUSY))
+ /* check in case of retry */
BT_CONTROL(BT_H_BUSY);
BT_CONTROL(BT_CLR_RD_PTR); /* start of BMC2HOST buffer */
i = read_all_bytes(bt); /* true == packet seq match */
@@ -599,8 +631,10 @@
BT_STATE_CHANGE(BT_STATE_XACTION_START,
SI_SM_CALL_WITH_DELAY);
- /* Get BT Capabilities, using timing of upper level state machine.
- Set outreqs to prevent infinite loop on timeout. */
+ /*
+ * Get BT Capabilities, using timing of upper level state machine.
+ * Set outreqs to prevent infinite loop on timeout.
+ */
case BT_STATE_CAPABILITIES_BEGIN:
bt->BT_CAP_outreqs = 1;
{
@@ -638,10 +672,12 @@
static int bt_detect(struct si_sm_data *bt)
{
- /* It's impossible for the BT status and interrupt registers to be
- all 1's, (assuming a properly functioning, self-initialized BMC)
- but that's what you get from reading a bogus address, so we
- test that first. The calling routine uses negative logic. */
+ /*
+ * It's impossible for the BT status and interrupt registers to be
+ * all 1's, (assuming a properly functioning, self-initialized BMC)
+ * 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;
@@ -658,8 +694,7 @@
return sizeof(struct si_sm_data);
}
-struct si_sm_handlers bt_smi_handlers =
-{
+struct si_sm_handlers bt_smi_handlers = {
.init_data = bt_init_data,
.start_transaction = bt_start_transaction,
.get_result = bt_get_result,
diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c
index c1b8228..8070487 100644
--- a/drivers/char/ipmi/ipmi_kcs_sm.c
+++ b/drivers/char/ipmi/ipmi_kcs_sm.c
@@ -60,37 +60,58 @@
/* The states the KCS driver may be in. */
enum kcs_states {
- KCS_IDLE, /* The KCS interface is currently
- doing nothing. */
- KCS_START_OP, /* We are starting an operation. The
- data is in the output buffer, but
- nothing has been done to the
- interface yet. This was added to
- the state machine in the spec to
- wait for the initial IBF. */
- KCS_WAIT_WRITE_START, /* We have written a write cmd to the
- interface. */
- KCS_WAIT_WRITE, /* We are writing bytes to the
- interface. */
- KCS_WAIT_WRITE_END, /* We have written the write end cmd
- to the interface, and still need to
- write the last byte. */
- KCS_WAIT_READ, /* We are waiting to read data from
- the interface. */
- KCS_ERROR0, /* State to transition to the error
- handler, this was added to the
- state machine in the spec to be
- sure IBF was there. */
- KCS_ERROR1, /* First stage error handler, wait for
- the interface to respond. */
- KCS_ERROR2, /* The abort cmd has been written,
- wait for the interface to
- respond. */
- KCS_ERROR3, /* We wrote some data to the
- interface, wait for it to switch to
- read mode. */
- KCS_HOSED /* The hardware failed to follow the
- state machine. */
+ /* The KCS interface is currently doing nothing. */
+ KCS_IDLE,
+
+ /*
+ * We are starting an operation. The data is in the output
+ * buffer, but nothing has been done to the interface yet. This
+ * was added to the state machine in the spec to wait for the
+ * initial IBF.
+ */
+ KCS_START_OP,
+
+ /* We have written a write cmd to the interface. */
+ KCS_WAIT_WRITE_START,
+
+ /* We are writing bytes to the interface. */
+ KCS_WAIT_WRITE,
+
+ /*
+ * We have written the write end cmd to the interface, and
+ * still need to write the last byte.
+ */
+ KCS_WAIT_WRITE_END,
+
+ /* We are waiting to read data from the interface. */
+ KCS_WAIT_READ,
+
+ /*
+ * State to transition to the error handler, this was added to
+ * the state machine in the spec to be sure IBF was there.
+ */
+ KCS_ERROR0,
+
+ /*
+ * First stage error handler, wait for the interface to
+ * respond.
+ */
+ KCS_ERROR1,
+
+ /*
+ * The abort cmd has been written, wait for the interface to
+ * respond.
+ */
+ KCS_ERROR2,
+
+ /*
+ * We wrote some data to the interface, wait for it to switch
+ * to read mode.
+ */
+ KCS_ERROR3,
+
+ /* The hardware failed to follow the state machine. */
+ KCS_HOSED
};
#define MAX_KCS_READ_SIZE IPMI_MAX_MSG_LENGTH
@@ -102,8 +123,7 @@
#define MAX_ERROR_RETRIES 10
#define ERROR0_OBF_WAIT_JIFFIES (2*HZ)
-struct si_sm_data
-{
+struct si_sm_data {
enum kcs_states state;
struct si_sm_io *io;
unsigned char write_data[MAX_KCS_WRITE_SIZE];
@@ -187,7 +207,8 @@
(kcs->error_retries)++;
if (kcs->error_retries > MAX_ERROR_RETRIES) {
if (kcs_debug & KCS_DEBUG_ENABLE)
- printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n", reason);
+ printk(KERN_DEBUG "ipmi_kcs_sm: kcs hosed: %s\n",
+ reason);
kcs->state = KCS_HOSED;
} else {
kcs->error0_timeout = jiffies + ERROR0_OBF_WAIT_JIFFIES;
@@ -271,10 +292,9 @@
if (kcs_debug & KCS_DEBUG_MSG) {
printk(KERN_DEBUG "start_kcs_transaction -");
- for (i = 0; i < size; i ++) {
+ for (i = 0; i < size; i++)
printk(" %02x", (unsigned char) (data [i]));
- }
- printk ("\n");
+ printk("\n");
}
kcs->error_retries = 0;
memcpy(kcs->write_data, data, size);
@@ -305,9 +325,11 @@
kcs->read_pos = 3;
}
if (kcs->truncated) {
- /* Report a truncated error. We might overwrite
- another error, but that's too bad, the user needs
- to know it was truncated. */
+ /*
+ * Report a truncated error. We might overwrite
+ * another error, but that's too bad, the user needs
+ * to know it was truncated.
+ */
data[2] = IPMI_ERR_MSG_TRUNCATED;
kcs->truncated = 0;
}
@@ -315,9 +337,11 @@
return kcs->read_pos;
}
-/* This implements the state machine defined in the IPMI manual, see
- that for details on how this works. Divide that flowchart into
- sections delimited by "Wait for IBF" and this will become clear. */
+/*
+ * This implements the state machine defined in the IPMI manual, see
+ * that for details on how this works. Divide that flowchart into
+ * sections delimited by "Wait for IBF" and this will become clear.
+ */
static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
{
unsigned char status;
@@ -388,11 +412,12 @@
write_next_byte(kcs);
}
break;
-
+
case KCS_WAIT_WRITE_END:
if (state != KCS_WRITE_STATE) {
start_error_recovery(kcs,
- "Not in write state for write end");
+ "Not in write state"
+ " for write end");
break;
}
clear_obf(kcs, status);
@@ -413,13 +438,15 @@
return SI_SM_CALL_WITH_DELAY;
read_next_byte(kcs);
} else {
- /* We don't implement this exactly like the state
- machine in the spec. Some broken hardware
- does not write the final dummy byte to the
- read register. Thus obf will never go high
- here. We just go straight to idle, and we
- handle clearing out obf in idle state if it
- happens to come in. */
+ /*
+ * We don't implement this exactly like the state
+ * machine in the spec. Some broken hardware
+ * does not write the final dummy byte to the
+ * read register. Thus obf will never go high
+ * here. We just go straight to idle, and we
+ * handle clearing out obf in idle state if it
+ * happens to come in.
+ */
clear_obf(kcs, status);
kcs->orig_write_count = 0;
kcs->state = KCS_IDLE;
@@ -430,7 +457,8 @@
case KCS_ERROR0:
clear_obf(kcs, status);
status = read_status(kcs);
- if (GET_STATUS_OBF(status)) /* controller isn't responding */
+ if (GET_STATUS_OBF(status))
+ /* controller isn't responding */
if (time_before(jiffies, kcs->error0_timeout))
return SI_SM_CALL_WITH_TICK_DELAY;
write_cmd(kcs, KCS_GET_STATUS_ABORT);
@@ -442,7 +470,7 @@
write_data(kcs, 0);
kcs->state = KCS_ERROR2;
break;
-
+
case KCS_ERROR2:
if (state != KCS_READ_STATE) {
start_error_recovery(kcs,
@@ -456,7 +484,7 @@
write_data(kcs, KCS_READ_BYTE);
kcs->state = KCS_ERROR3;
break;
-
+
case KCS_ERROR3:
if (state != KCS_IDLE_STATE) {
start_error_recovery(kcs,
@@ -475,7 +503,7 @@
return SI_SM_TRANSACTION_COMPLETE;
}
break;
-
+
case KCS_HOSED:
break;
}
@@ -495,10 +523,12 @@
static int kcs_detect(struct si_sm_data *kcs)
{
- /* It's impossible for the KCS status register to be all 1's,
- (assuming a properly functioning, self-initialized BMC)
- but that's what you get from reading a bogus address, so we
- test that first. */
+ /*
+ * It's impossible for the KCS status register to be all 1's,
+ * (assuming a properly functioning, self-initialized BMC)
+ * but that's what you get from reading a bogus address, so we
+ * test that first.
+ */
if (read_status(kcs) == 0xff)
return 1;
@@ -509,8 +539,7 @@
{
}
-struct si_sm_handlers kcs_smi_handlers =
-{
+struct si_sm_handlers kcs_smi_handlers = {
.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 32b2b22..8a59aaa 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -47,7 +47,7 @@
#define PFX "IPMI message handler: "
-#define IPMI_DRIVER_VERSION "39.1"
+#define IPMI_DRIVER_VERSION "39.2"
static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
static int ipmi_init_msghandler(void);
@@ -63,16 +63,16 @@
#define MAX_EVENTS_IN_QUEUE 25
-/* Don't let a message sit in a queue forever, always time it with at lest
- the max message timer. This is in milliseconds. */
+/*
+ * Don't let a message sit in a queue forever, always time it with at lest
+ * the max message timer. This is in milliseconds.
+ */
#define MAX_MSG_TIMEOUT 60000
-
/*
* The main "user" data structure.
*/
-struct ipmi_user
-{
+struct ipmi_user {
struct list_head link;
/* Set to "0" when the user is destroyed. */
@@ -91,8 +91,7 @@
int gets_events;
};
-struct cmd_rcvr
-{
+struct cmd_rcvr {
struct list_head link;
ipmi_user_t user;
@@ -106,12 +105,12 @@
* or change any data until the RCU period completes. So we
* use this next variable during mass deletion so we can have
* a list and don't have to wait and restart the search on
- * every individual deletion of a command. */
+ * every individual deletion of a command.
+ */
struct cmd_rcvr *next;
};
-struct seq_table
-{
+struct seq_table {
unsigned int inuse : 1;
unsigned int broadcast : 1;
@@ -119,53 +118,60 @@
unsigned long orig_timeout;
unsigned int retries_left;
- /* To verify on an incoming send message response that this is
- the message that the response is for, we keep a sequence id
- and increment it every time we send a message. */
+ /*
+ * To verify on an incoming send message response that this is
+ * the message that the response is for, we keep a sequence id
+ * and increment it every time we send a message.
+ */
long seqid;
- /* This is held so we can properly respond to the message on a
- timeout, and it is used to hold the temporary data for
- retransmission, too. */
+ /*
+ * This is held so we can properly respond to the message on a
+ * timeout, and it is used to hold the temporary data for
+ * retransmission, too.
+ */
struct ipmi_recv_msg *recv_msg;
};
-/* Store the information in a msgid (long) to allow us to find a
- sequence table entry from the msgid. */
+/*
+ * Store the information in a msgid (long) to allow us to find a
+ * sequence table entry from the msgid.
+ */
#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff))
#define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \
do { \
seq = ((msgid >> 26) & 0x3f); \
seqid = (msgid & 0x3fffff); \
- } while (0)
+ } while (0)
#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff)
-struct ipmi_channel
-{
+struct ipmi_channel {
unsigned char medium;
unsigned char protocol;
- /* My slave address. This is initialized to IPMI_BMC_SLAVE_ADDR,
- but may be changed by the user. */
+ /*
+ * 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... */
+ /*
+ * My LUN. This should generally stay the SMS LUN, but just in
+ * case...
+ */
unsigned char lun;
};
#ifdef CONFIG_PROC_FS
-struct ipmi_proc_entry
-{
+struct ipmi_proc_entry {
char *name;
struct ipmi_proc_entry *next;
};
#endif
-struct bmc_device
-{
+struct bmc_device {
struct platform_device *dev;
struct ipmi_device_id id;
unsigned char guid[16];
@@ -186,10 +192,108 @@
struct device_attribute aux_firmware_rev_attr;
};
+/*
+ * Various statistics for IPMI, these index stats[] in the ipmi_smi
+ * structure.
+ */
+enum ipmi_stat_indexes {
+ /* Commands we got from the user that were invalid. */
+ IPMI_STAT_sent_invalid_commands = 0,
+
+ /* Commands we sent to the MC. */
+ IPMI_STAT_sent_local_commands,
+
+ /* Responses from the MC that were delivered to a user. */
+ IPMI_STAT_handled_local_responses,
+
+ /* Responses from the MC that were not delivered to a user. */
+ IPMI_STAT_unhandled_local_responses,
+
+ /* Commands we sent out to the IPMB bus. */
+ IPMI_STAT_sent_ipmb_commands,
+
+ /* Commands sent on the IPMB that had errors on the SEND CMD */
+ IPMI_STAT_sent_ipmb_command_errs,
+
+ /* Each retransmit increments this count. */
+ IPMI_STAT_retransmitted_ipmb_commands,
+
+ /*
+ * When a message times out (runs out of retransmits) this is
+ * incremented.
+ */
+ IPMI_STAT_timed_out_ipmb_commands,
+
+ /*
+ * This is like above, but for broadcasts. Broadcasts are
+ * *not* included in the above count (they are expected to
+ * time out).
+ */
+ IPMI_STAT_timed_out_ipmb_broadcasts,
+
+ /* Responses I have sent to the IPMB bus. */
+ IPMI_STAT_sent_ipmb_responses,
+
+ /* The response was delivered to the user. */
+ IPMI_STAT_handled_ipmb_responses,
+
+ /* The response had invalid data in it. */
+ IPMI_STAT_invalid_ipmb_responses,
+
+ /* The response didn't have anyone waiting for it. */
+ IPMI_STAT_unhandled_ipmb_responses,
+
+ /* Commands we sent out to the IPMB bus. */
+ IPMI_STAT_sent_lan_commands,
+
+ /* Commands sent on the IPMB that had errors on the SEND CMD */
+ IPMI_STAT_sent_lan_command_errs,
+
+ /* Each retransmit increments this count. */
+ IPMI_STAT_retransmitted_lan_commands,
+
+ /*
+ * When a message times out (runs out of retransmits) this is
+ * incremented.
+ */
+ IPMI_STAT_timed_out_lan_commands,
+
+ /* Responses I have sent to the IPMB bus. */
+ IPMI_STAT_sent_lan_responses,
+
+ /* The response was delivered to the user. */
+ IPMI_STAT_handled_lan_responses,
+
+ /* The response had invalid data in it. */
+ IPMI_STAT_invalid_lan_responses,
+
+ /* The response didn't have anyone waiting for it. */
+ IPMI_STAT_unhandled_lan_responses,
+
+ /* The command was delivered to the user. */
+ IPMI_STAT_handled_commands,
+
+ /* The command had invalid data in it. */
+ IPMI_STAT_invalid_commands,
+
+ /* The command didn't have anyone waiting for it. */
+ IPMI_STAT_unhandled_commands,
+
+ /* Invalid data in an event. */
+ IPMI_STAT_invalid_events,
+
+ /* Events that were received with the proper format. */
+ IPMI_STAT_events,
+
+
+ /* This *must* remain last, add new values above this. */
+ IPMI_NUM_STATS
+};
+
+
#define IPMI_IPMB_NUM_SEQ 64
#define IPMI_MAX_CHANNELS 16
-struct ipmi_smi
-{
+struct ipmi_smi {
/* What interface number are we? */
int intf_num;
@@ -198,8 +302,10 @@
/* Used for a list of interfaces. */
struct list_head link;
- /* The list of upper layers that are using me. seq_lock
- * protects this. */
+ /*
+ * The list of upper layers that are using me. seq_lock
+ * protects this.
+ */
struct list_head users;
/* Information to supply to users. */
@@ -213,10 +319,12 @@
char *my_dev_name;
char *sysfs_name;
- /* This is the lower-layer's sender routine. Note that you
+ /*
+ * This is the lower-layer's sender routine. Note that you
* must either be holding the ipmi_interfaces_mutex or be in
* an umpreemptible region to use this. You must fetch the
- * value into a local variable and make sure it is not NULL. */
+ * value into a local variable and make sure it is not NULL.
+ */
struct ipmi_smi_handlers *handlers;
void *send_info;
@@ -229,34 +337,45 @@
/* Driver-model device for the system interface. */
struct device *si_dev;
- /* A table of sequence numbers for this interface. We use the
- sequence numbers for IPMB messages that go out of the
- interface to match them up with their responses. A routine
- is called periodically to time the items in this list. */
+ /*
+ * A table of sequence numbers for this interface. We use the
+ * sequence numbers for IPMB messages that go out of the
+ * interface to match them up with their responses. A routine
+ * is called periodically to time the items in this list.
+ */
spinlock_t seq_lock;
struct seq_table seq_table[IPMI_IPMB_NUM_SEQ];
int curr_seq;
- /* Messages that were delayed for some reason (out of memory,
- for instance), will go in here to be processed later in a
- periodic timer interrupt. */
+ /*
+ * Messages that were delayed for some reason (out of memory,
+ * for instance), will go in here to be processed later in a
+ * periodic timer interrupt.
+ */
spinlock_t waiting_msgs_lock;
struct list_head waiting_msgs;
- /* The list of command receivers that are registered for commands
- on this interface. */
+ /*
+ * The list of command receivers that are registered for commands
+ * on this interface.
+ */
struct mutex cmd_rcvrs_mutex;
struct list_head cmd_rcvrs;
- /* Events that were queues because no one was there to receive
- them. */
+ /*
+ * Events that were queues because no one was there to receive
+ * them.
+ */
spinlock_t events_lock; /* For dealing with event stuff. */
struct list_head waiting_events;
unsigned int waiting_events_count; /* How many events in queue? */
- int delivering_events;
+ char delivering_events;
+ char event_msg_printed;
- /* The event receiver for my BMC, only really used at panic
- shutdown as a place to store this. */
+ /*
+ * The event receiver for my BMC, only really used at panic
+ * shutdown as a place to store this.
+ */
unsigned char event_receiver;
unsigned char event_receiver_lun;
unsigned char local_sel_device;
@@ -268,14 +387,18 @@
int auto_maintenance_timeout;
spinlock_t maintenance_mode_lock; /* Used in a timer... */
- /* A cheap hack, if this is non-null and a message to an
- 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. */
+ /*
+ * A cheap hack, if this is non-null and a message to an
+ * 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_recv_msg *msg);
- /* When we are scanning the channels for an SMI, this will
- tell which channel we are scanning. */
+ /*
+ * When we are scanning the channels for an SMI, this will
+ * tell which channel we are scanning.
+ */
int curr_channel;
/* Channel information */
@@ -285,74 +408,14 @@
struct proc_dir_entry *proc_dir;
char proc_dir_name[10];
- spinlock_t counter_lock; /* For making counters atomic. */
+ atomic_t stats[IPMI_NUM_STATS];
- /* Commands we got that were invalid. */
- unsigned int sent_invalid_commands;
-
- /* Commands we sent to the MC. */
- unsigned int sent_local_commands;
- /* Responses from the MC that were delivered to a user. */
- unsigned int handled_local_responses;
- /* Responses from the MC that were not delivered to a user. */
- unsigned int unhandled_local_responses;
-
- /* Commands we sent out to the IPMB bus. */
- unsigned int sent_ipmb_commands;
- /* Commands sent on the IPMB that had errors on the SEND CMD */
- unsigned int sent_ipmb_command_errs;
- /* Each retransmit increments this count. */
- unsigned int retransmitted_ipmb_commands;
- /* When a message times out (runs out of retransmits) this is
- incremented. */
- unsigned int timed_out_ipmb_commands;
-
- /* This is like above, but for broadcasts. Broadcasts are
- *not* included in the above count (they are expected to
- time out). */
- unsigned int timed_out_ipmb_broadcasts;
-
- /* Responses I have sent to the IPMB bus. */
- unsigned int sent_ipmb_responses;
-
- /* The response was delivered to the user. */
- unsigned int handled_ipmb_responses;
- /* The response had invalid data in it. */
- unsigned int invalid_ipmb_responses;
- /* The response didn't have anyone waiting for it. */
- unsigned int unhandled_ipmb_responses;
-
- /* Commands we sent out to the IPMB bus. */
- unsigned int sent_lan_commands;
- /* Commands sent on the IPMB that had errors on the SEND CMD */
- unsigned int sent_lan_command_errs;
- /* Each retransmit increments this count. */
- unsigned int retransmitted_lan_commands;
- /* When a message times out (runs out of retransmits) this is
- incremented. */
- unsigned int timed_out_lan_commands;
-
- /* Responses I have sent to the IPMB bus. */
- unsigned int sent_lan_responses;
-
- /* The response was delivered to the user. */
- unsigned int handled_lan_responses;
- /* The response had invalid data in it. */
- unsigned int invalid_lan_responses;
- /* The response didn't have anyone waiting for it. */
- unsigned int unhandled_lan_responses;
-
- /* The command was delivered to the user. */
- unsigned int handled_commands;
- /* The command had invalid data in it. */
- unsigned int invalid_commands;
- /* The command didn't have anyone waiting for it. */
- unsigned int unhandled_commands;
-
- /* Invalid data in an event. */
- unsigned int invalid_events;
- /* Events that were received with the proper format. */
- unsigned int events;
+ /*
+ * run_to_completion duplicate of smb_info, smi_info
+ * and ipmi_serial_info structures. Used to decrease numbers of
+ * parameters passed by "low" level IPMI code.
+ */
+ int run_to_completion;
};
#define to_si_intf_from_dev(device) container_of(device, struct ipmi_smi, dev)
@@ -368,12 +431,19 @@
static LIST_HEAD(ipmi_interfaces);
static DEFINE_MUTEX(ipmi_interfaces_mutex);
-/* List of watchers that want to know when smi's are added and
- deleted. */
+/*
+ * List of watchers that want to know when smi's are added and deleted.
+ */
static LIST_HEAD(smi_watchers);
static DEFINE_MUTEX(smi_watchers_mutex);
+#define ipmi_inc_stat(intf, stat) \
+ atomic_inc(&(intf)->stats[IPMI_STAT_ ## stat])
+#define ipmi_get_stat(intf, stat) \
+ ((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat]))
+
+
static void free_recv_msg_list(struct list_head *q)
{
struct ipmi_recv_msg *msg, *msg2;
@@ -417,10 +487,8 @@
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if ((intf->seq_table[i].inuse)
- && (intf->seq_table[i].recv_msg))
- {
+ && (intf->seq_table[i].recv_msg))
ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
- }
}
}
@@ -487,6 +555,7 @@
}
return -ENOMEM;
}
+EXPORT_SYMBOL(ipmi_smi_watcher_register);
int ipmi_smi_watcher_unregister(struct ipmi_smi_watcher *watcher)
{
@@ -495,6 +564,7 @@
mutex_unlock(&smi_watchers_mutex);
return 0;
}
+EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
/*
* Must be called with smi_watchers_mutex held.
@@ -530,8 +600,7 @@
}
if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
- || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
- {
+ || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) {
struct ipmi_ipmb_addr *ipmb_addr1
= (struct ipmi_ipmb_addr *) addr1;
struct ipmi_ipmb_addr *ipmb_addr2
@@ -559,9 +628,8 @@
int ipmi_validate_addr(struct ipmi_addr *addr, int len)
{
- if (len < sizeof(struct ipmi_system_interface_addr)) {
+ if (len < sizeof(struct ipmi_system_interface_addr))
return -EINVAL;
- }
if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
if (addr->channel != IPMI_BMC_CHANNEL)
@@ -575,23 +643,21 @@
return -EINVAL;
if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
- || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
- {
- if (len < sizeof(struct ipmi_ipmb_addr)) {
+ || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) {
+ if (len < sizeof(struct ipmi_ipmb_addr))
return -EINVAL;
- }
return 0;
}
if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
- if (len < sizeof(struct ipmi_lan_addr)) {
+ if (len < sizeof(struct ipmi_lan_addr))
return -EINVAL;
- }
return 0;
}
return -EINVAL;
}
+EXPORT_SYMBOL(ipmi_validate_addr);
unsigned int ipmi_addr_length(int addr_type)
{
@@ -599,34 +665,28 @@
return sizeof(struct ipmi_system_interface_addr);
if ((addr_type == IPMI_IPMB_ADDR_TYPE)
- || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
- {
+ || (addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
return sizeof(struct ipmi_ipmb_addr);
- }
if (addr_type == IPMI_LAN_ADDR_TYPE)
return sizeof(struct ipmi_lan_addr);
return 0;
}
+EXPORT_SYMBOL(ipmi_addr_length);
static void deliver_response(struct ipmi_recv_msg *msg)
{
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);
+ ipmi_inc_stat(intf, handled_local_responses);
} 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_inc_stat(intf, unhandled_local_responses);
}
ipmi_free_recv_msg(msg);
} else {
@@ -646,9 +706,11 @@
deliver_response(msg);
}
-/* Find the next sequence number not being used and add the given
- message with the given timeout to the sequence table. This must be
- called with the interface's seq_lock held. */
+/*
+ * Find the next sequence number not being used and add the given
+ * message with the given timeout to the sequence table. This must be
+ * called with the interface's seq_lock held.
+ */
static int intf_next_seq(ipmi_smi_t intf,
struct ipmi_recv_msg *recv_msg,
unsigned long timeout,
@@ -660,10 +722,8 @@
int rv = 0;
unsigned int i;
- for (i = intf->curr_seq;
- (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
- i = (i+1)%IPMI_IPMB_NUM_SEQ)
- {
+ for (i = intf->curr_seq; (i+1)%IPMI_IPMB_NUM_SEQ != intf->curr_seq;
+ i = (i+1)%IPMI_IPMB_NUM_SEQ) {
if (!intf->seq_table[i].inuse)
break;
}
@@ -671,8 +731,10 @@
if (!intf->seq_table[i].inuse) {
intf->seq_table[i].recv_msg = recv_msg;
- /* Start with the maximum timeout, when the send response
- comes in we will start the real timer. */
+ /*
+ * Start with the maximum timeout, when the send response
+ * comes in we will start the real timer.
+ */
intf->seq_table[i].timeout = MAX_MSG_TIMEOUT;
intf->seq_table[i].orig_timeout = timeout;
intf->seq_table[i].retries_left = retries;
@@ -685,15 +747,17 @@
} else {
rv = -EAGAIN;
}
-
+
return rv;
}
-/* Return the receive message for the given sequence number and
- release the sequence number so it can be reused. Some other data
- is passed in to be sure the message matches up correctly (to help
- guard against message coming in after their timeout and the
- sequence number being reused). */
+/*
+ * Return the receive message for the given sequence number and
+ * release the sequence number so it can be reused. Some other data
+ * is passed in to be sure the message matches up correctly (to help
+ * guard against message coming in after their timeout and the
+ * sequence number being reused).
+ */
static int intf_find_seq(ipmi_smi_t intf,
unsigned char seq,
short channel,
@@ -712,11 +776,9 @@
if (intf->seq_table[seq].inuse) {
struct ipmi_recv_msg *msg = intf->seq_table[seq].recv_msg;
- if ((msg->addr.channel == channel)
- && (msg->msg.cmd == cmd)
- && (msg->msg.netfn == netfn)
- && (ipmi_addr_equal(addr, &(msg->addr))))
- {
+ if ((msg->addr.channel == channel) && (msg->msg.cmd == cmd)
+ && (msg->msg.netfn == netfn)
+ && (ipmi_addr_equal(addr, &(msg->addr)))) {
*recv_msg = msg;
intf->seq_table[seq].inuse = 0;
rv = 0;
@@ -741,11 +803,12 @@
GET_SEQ_FROM_MSGID(msgid, seq, seqid);
spin_lock_irqsave(&(intf->seq_lock), flags);
- /* We do this verification because the user can be deleted
- while a message is outstanding. */
+ /*
+ * We do this verification because the user can be deleted
+ * while a message is outstanding.
+ */
if ((intf->seq_table[seq].inuse)
- && (intf->seq_table[seq].seqid == seqid))
- {
+ && (intf->seq_table[seq].seqid == seqid)) {
struct seq_table *ent = &(intf->seq_table[seq]);
ent->timeout = ent->orig_timeout;
rv = 0;
@@ -770,11 +833,12 @@
GET_SEQ_FROM_MSGID(msgid, seq, seqid);
spin_lock_irqsave(&(intf->seq_lock), flags);
- /* We do this verification because the user can be deleted
- while a message is outstanding. */
+ /*
+ * We do this verification because the user can be deleted
+ * while a message is outstanding.
+ */
if ((intf->seq_table[seq].inuse)
- && (intf->seq_table[seq].seqid == seqid))
- {
+ && (intf->seq_table[seq].seqid == seqid)) {
struct seq_table *ent = &(intf->seq_table[seq]);
ent->inuse = 0;
@@ -800,24 +864,30 @@
int rv = 0;
ipmi_smi_t intf;
- /* There is no module usecount here, because it's not
- required. Since this can only be used by and called from
- other modules, they will implicitly use this module, and
- thus this can't be removed unless the other modules are
- removed. */
+ /*
+ * There is no module usecount here, because it's not
+ * required. Since this can only be used by and called from
+ * other modules, they will implicitly use this module, and
+ * thus this can't be removed unless the other modules are
+ * removed.
+ */
if (handler == NULL)
return -EINVAL;
- /* Make sure the driver is actually initialized, this handles
- problems with initialization order. */
+ /*
+ * Make sure the driver is actually initialized, this handles
+ * problems with initialization order.
+ */
if (!initialized) {
rv = ipmi_init_msghandler();
if (rv)
return rv;
- /* The init code doesn't return an error if it was turned
- off, but it won't initialize. Check that. */
+ /*
+ * The init code doesn't return an error if it was turned
+ * off, but it won't initialize. Check that.
+ */
if (!initialized)
return -ENODEV;
}
@@ -858,8 +928,10 @@
}
}
- /* Hold the lock so intf->handlers is guaranteed to be good
- * until now */
+ /*
+ * Hold the lock so intf->handlers is guaranteed to be good
+ * until now
+ */
mutex_unlock(&ipmi_interfaces_mutex);
new_user->valid = 1;
@@ -876,6 +948,7 @@
kfree(new_user);
return rv;
}
+EXPORT_SYMBOL(ipmi_create_user);
static void free_user(struct kref *ref)
{
@@ -899,8 +972,7 @@
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++) {
if (intf->seq_table[i].inuse
- && (intf->seq_table[i].recv_msg->user == user))
- {
+ && (intf->seq_table[i].recv_msg->user == user)) {
intf->seq_table[i].inuse = 0;
ipmi_free_recv_msg(intf->seq_table[i].recv_msg);
}
@@ -943,6 +1015,7 @@
return 0;
}
+EXPORT_SYMBOL(ipmi_destroy_user);
void ipmi_get_version(ipmi_user_t user,
unsigned char *major,
@@ -951,6 +1024,7 @@
*major = user->intf->ipmi_version_major;
*minor = user->intf->ipmi_version_minor;
}
+EXPORT_SYMBOL(ipmi_get_version);
int ipmi_set_my_address(ipmi_user_t user,
unsigned int channel,
@@ -961,6 +1035,7 @@
user->intf->channels[channel].address = address;
return 0;
}
+EXPORT_SYMBOL(ipmi_set_my_address);
int ipmi_get_my_address(ipmi_user_t user,
unsigned int channel,
@@ -971,6 +1046,7 @@
*address = user->intf->channels[channel].address;
return 0;
}
+EXPORT_SYMBOL(ipmi_get_my_address);
int ipmi_set_my_LUN(ipmi_user_t user,
unsigned int channel,
@@ -981,6 +1057,7 @@
user->intf->channels[channel].lun = LUN & 0x3;
return 0;
}
+EXPORT_SYMBOL(ipmi_set_my_LUN);
int ipmi_get_my_LUN(ipmi_user_t user,
unsigned int channel,
@@ -991,6 +1068,7 @@
*address = user->intf->channels[channel].lun;
return 0;
}
+EXPORT_SYMBOL(ipmi_get_my_LUN);
int ipmi_get_maintenance_mode(ipmi_user_t user)
{
@@ -1075,6 +1153,11 @@
list_for_each_entry_safe(msg, msg2, &intf->waiting_events, link)
list_move_tail(&msg->link, &msgs);
intf->waiting_events_count = 0;
+ if (intf->event_msg_printed) {
+ printk(KERN_WARNING PFX "Event queue no longer"
+ " full\n");
+ intf->event_msg_printed = 0;
+ }
intf->delivering_events = 1;
spin_unlock_irqrestore(&intf->events_lock, flags);
@@ -1094,6 +1177,7 @@
return 0;
}
+EXPORT_SYMBOL(ipmi_set_gets_events);
static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
unsigned char netfn,
@@ -1159,6 +1243,7 @@
return rv;
}
+EXPORT_SYMBOL(ipmi_register_for_cmd);
int ipmi_unregister_for_cmd(ipmi_user_t user,
unsigned char netfn,
@@ -1196,19 +1281,13 @@
}
return rv;
}
-
-void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
-{
- ipmi_smi_t intf = user->intf;
- if (intf->handlers)
- intf->handlers->set_run_to_completion(intf->send_info, val);
-}
+EXPORT_SYMBOL(ipmi_unregister_for_cmd);
static unsigned char
ipmb_checksum(unsigned char *data, int size)
{
unsigned char csum = 0;
-
+
for (; size > 0; size--, data++)
csum += *data;
@@ -1250,8 +1329,10 @@
= ipmb_checksum(&(smi_msg->data[i+6]),
smi_msg->data_size-6);
- /* Add on the checksum size and the offset from the
- broadcast. */
+ /*
+ * Add on the checksum size and the offset from the
+ * broadcast.
+ */
smi_msg->data_size += 1 + i;
smi_msg->msgid = msgid;
@@ -1287,17 +1368,21 @@
= ipmb_checksum(&(smi_msg->data[7]),
smi_msg->data_size-7);
- /* Add on the checksum size and the offset from the
- broadcast. */
+ /*
+ * Add on the checksum size and the offset from the
+ * broadcast.
+ */
smi_msg->data_size += 1;
smi_msg->msgid = msgid;
}
-/* Separate from ipmi_request so that the user does not have to be
- supplied in certain circumstances (mainly at panic time). If
- messages are supplied, they will be freed, even if an error
- occurs. */
+/*
+ * Separate from ipmi_request so that the user does not have to be
+ * supplied in certain circumstances (mainly at panic time). If
+ * messages are supplied, they will be freed, even if an error
+ * occurs.
+ */
static int i_ipmi_request(ipmi_user_t user,
ipmi_smi_t intf,
struct ipmi_addr *addr,
@@ -1319,19 +1404,18 @@
struct ipmi_smi_handlers *handlers;
- if (supplied_recv) {
+ if (supplied_recv)
recv_msg = supplied_recv;
- } else {
+ else {
recv_msg = ipmi_alloc_recv_msg();
- if (recv_msg == NULL) {
+ if (recv_msg == NULL)
return -ENOMEM;
- }
}
recv_msg->user_msg_data = user_msg_data;
- if (supplied_smi) {
+ if (supplied_smi)
smi_msg = (struct ipmi_smi_msg *) supplied_smi;
- } else {
+ else {
smi_msg = ipmi_alloc_smi_msg();
if (smi_msg == NULL) {
ipmi_free_recv_msg(recv_msg);
@@ -1350,8 +1434,10 @@
if (user)
kref_get(&user->refcount);
recv_msg->msgid = msgid;
- /* Store the message to send in the receive message so timeout
- responses can get the proper response data. */
+ /*
+ * Store the message to send in the receive message so timeout
+ * responses can get the proper response data.
+ */
recv_msg->msg = *msg;
if (addr->addr_type == IPMI_SYSTEM_INTERFACE_ADDR_TYPE) {
@@ -1365,9 +1451,7 @@
smi_addr = (struct ipmi_system_interface_addr *) addr;
if (smi_addr->lun > 3) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1377,13 +1461,12 @@
if ((msg->netfn == IPMI_NETFN_APP_REQUEST)
&& ((msg->cmd == IPMI_SEND_MSG_CMD)
|| (msg->cmd == IPMI_GET_MSG_CMD)
- || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD)))
- {
- /* We don't let the user do these, since we manage
- the sequence numbers. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ || (msg->cmd == IPMI_READ_EVENT_MSG_BUFFER_CMD))) {
+ /*
+ * We don't let the user do these, since we manage
+ * the sequence numbers.
+ */
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1391,14 +1474,12 @@
if (((msg->netfn == IPMI_NETFN_APP_REQUEST)
&& ((msg->cmd == IPMI_COLD_RESET_CMD)
|| (msg->cmd == IPMI_WARM_RESET_CMD)))
- || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST))
- {
+ || (msg->netfn == IPMI_NETFN_FIRMWARE_REQUEST)) {
spin_lock_irqsave(&intf->maintenance_mode_lock, flags);
intf->auto_maintenance_timeout
= IPMI_MAINTENANCE_MODE_TIMEOUT;
if (!intf->maintenance_mode
- && !intf->maintenance_mode_enable)
- {
+ && !intf->maintenance_mode_enable) {
intf->maintenance_mode_enable = 1;
maintenance_mode_update(intf);
}
@@ -1407,9 +1488,7 @@
}
if ((msg->data_len + 2) > IPMI_MAX_MSG_LENGTH) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EMSGSIZE;
goto out_err;
}
@@ -1421,31 +1500,23 @@
if (msg->data_len > 0)
memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
smi_msg->data_size = msg->data_len + 2;
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_local_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_local_commands);
} else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
- || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE))
- {
+ || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) {
struct ipmi_ipmb_addr *ipmb_addr;
unsigned char ipmb_seq;
long seqid;
int broadcast = 0;
if (addr->channel >= IPMI_MAX_CHANNELS) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
if (intf->channels[addr->channel].medium
- != IPMI_CHANNEL_MEDIUM_IPMB)
- {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ != IPMI_CHANNEL_MEDIUM_IPMB) {
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1457,9 +1528,11 @@
retries = 4;
}
if (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE) {
- /* Broadcasts add a zero at the beginning of the
- message, but otherwise is the same as an IPMB
- address. */
+ /*
+ * Broadcasts add a zero at the beginning of the
+ * message, but otherwise is the same as an IPMB
+ * address.
+ */
addr->addr_type = IPMI_IPMB_ADDR_TYPE;
broadcast = 1;
}
@@ -1469,21 +1542,19 @@
if (retry_time_ms == 0)
retry_time_ms = 1000;
- /* 9 for the header and 1 for the checksum, plus
- possibly one for the broadcast. */
+ /*
+ * 9 for the header and 1 for the checksum, plus
+ * possibly one for the broadcast.
+ */
if ((msg->data_len + 10 + broadcast) > IPMI_MAX_MSG_LENGTH) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EMSGSIZE;
goto out_err;
}
ipmb_addr = (struct ipmi_ipmb_addr *) addr;
if (ipmb_addr->lun > 3) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1491,29 +1562,31 @@
memcpy(&recv_msg->addr, ipmb_addr, sizeof(*ipmb_addr));
if (recv_msg->msg.netfn & 0x1) {
- /* It's a response, so use the user's sequence
- from msgid. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_ipmb_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ /*
+ * It's a response, so use the user's sequence
+ * from msgid.
+ */
+ ipmi_inc_stat(intf, sent_ipmb_responses);
format_ipmb_msg(smi_msg, msg, ipmb_addr, msgid,
msgid, broadcast,
source_address, source_lun);
- /* Save the receive message so we can use it
- to deliver the response. */
+ /*
+ * Save the receive message so we can use it
+ * to deliver the response.
+ */
smi_msg->user_data = recv_msg;
} else {
/* It's a command, so get a sequence for it. */
spin_lock_irqsave(&(intf->seq_lock), flags);
- spin_lock(&intf->counter_lock);
- intf->sent_ipmb_commands++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, sent_ipmb_commands);
- /* Create a sequence number with a 1 second
- timeout and 4 retries. */
+ /*
+ * Create a sequence number with a 1 second
+ * timeout and 4 retries.
+ */
rv = intf_next_seq(intf,
recv_msg,
retry_time_ms,
@@ -1522,34 +1595,42 @@
&ipmb_seq,
&seqid);
if (rv) {
- /* We have used up all the sequence numbers,
- probably, so abort. */
+ /*
+ * We have used up all the sequence numbers,
+ * probably, so abort.
+ */
spin_unlock_irqrestore(&(intf->seq_lock),
flags);
goto out_err;
}
- /* Store the sequence number in the message,
- so that when the send message response
- comes back we can start the timer. */
+ /*
+ * Store the sequence number in the message,
+ * so that when the send message response
+ * comes back we can start the timer.
+ */
format_ipmb_msg(smi_msg, msg, ipmb_addr,
STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
ipmb_seq, broadcast,
source_address, source_lun);
- /* Copy the message into the recv message data, so we
- can retransmit it later if necessary. */
+ /*
+ * Copy the message into the recv message data, so we
+ * can retransmit it later if necessary.
+ */
memcpy(recv_msg->msg_data, smi_msg->data,
smi_msg->data_size);
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = smi_msg->data_size;
- /* We don't unlock until here, because we need
- to copy the completed message into the
- recv_msg before we release the lock.
- Otherwise, race conditions may bite us. I
- know that's pretty paranoid, but I prefer
- to be correct. */
+ /*
+ * We don't unlock until here, because we need
+ * to copy the completed message into the
+ * recv_msg before we release the lock.
+ * Otherwise, race conditions may bite us. I
+ * know that's pretty paranoid, but I prefer
+ * to be correct.
+ */
spin_unlock_irqrestore(&(intf->seq_lock), flags);
}
} else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
@@ -1558,21 +1639,16 @@
long seqid;
if (addr->channel >= IPMI_MAX_CHANNELS) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
if ((intf->channels[addr->channel].medium
- != IPMI_CHANNEL_MEDIUM_8023LAN)
+ != IPMI_CHANNEL_MEDIUM_8023LAN)
&& (intf->channels[addr->channel].medium
- != IPMI_CHANNEL_MEDIUM_ASYNC))
- {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ != IPMI_CHANNEL_MEDIUM_ASYNC)) {
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1585,18 +1661,14 @@
/* 11 for the header and 1 for the checksum. */
if ((msg->data_len + 12) > IPMI_MAX_MSG_LENGTH) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EMSGSIZE;
goto out_err;
}
lan_addr = (struct ipmi_lan_addr *) addr;
if (lan_addr->lun > 3) {
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1604,28 +1676,30 @@
memcpy(&recv_msg->addr, lan_addr, sizeof(*lan_addr));
if (recv_msg->msg.netfn & 0x1) {
- /* It's a response, so use the user's sequence
- from msgid. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_lan_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ /*
+ * It's a response, so use the user's sequence
+ * from msgid.
+ */
+ ipmi_inc_stat(intf, sent_lan_responses);
format_lan_msg(smi_msg, msg, lan_addr, msgid,
msgid, source_lun);
- /* Save the receive message so we can use it
- to deliver the response. */
+ /*
+ * Save the receive message so we can use it
+ * to deliver the response.
+ */
smi_msg->user_data = recv_msg;
} else {
/* It's a command, so get a sequence for it. */
spin_lock_irqsave(&(intf->seq_lock), flags);
- spin_lock(&intf->counter_lock);
- intf->sent_lan_commands++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, sent_lan_commands);
- /* Create a sequence number with a 1 second
- timeout and 4 retries. */
+ /*
+ * Create a sequence number with a 1 second
+ * timeout and 4 retries.
+ */
rv = intf_next_seq(intf,
recv_msg,
retry_time_ms,
@@ -1634,40 +1708,46 @@
&ipmb_seq,
&seqid);
if (rv) {
- /* We have used up all the sequence numbers,
- probably, so abort. */
+ /*
+ * We have used up all the sequence numbers,
+ * probably, so abort.
+ */
spin_unlock_irqrestore(&(intf->seq_lock),
flags);
goto out_err;
}
- /* Store the sequence number in the message,
- so that when the send message response
- comes back we can start the timer. */
+ /*
+ * Store the sequence number in the message,
+ * so that when the send message response
+ * comes back we can start the timer.
+ */
format_lan_msg(smi_msg, msg, lan_addr,
STORE_SEQ_IN_MSGID(ipmb_seq, seqid),
ipmb_seq, source_lun);
- /* Copy the message into the recv message data, so we
- can retransmit it later if necessary. */
+ /*
+ * Copy the message into the recv message data, so we
+ * can retransmit it later if necessary.
+ */
memcpy(recv_msg->msg_data, smi_msg->data,
smi_msg->data_size);
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = smi_msg->data_size;
- /* We don't unlock until here, because we need
- to copy the completed message into the
- recv_msg before we release the lock.
- Otherwise, race conditions may bite us. I
- know that's pretty paranoid, but I prefer
- to be correct. */
+ /*
+ * We don't unlock until here, because we need
+ * to copy the completed message into the
+ * recv_msg before we release the lock.
+ * Otherwise, race conditions may bite us. I
+ * know that's pretty paranoid, but I prefer
+ * to be correct.
+ */
spin_unlock_irqrestore(&(intf->seq_lock), flags);
}
} else {
/* Unknown address type. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->sent_invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_invalid_commands);
rv = -EINVAL;
goto out_err;
}
@@ -1735,6 +1815,7 @@
retries,
retry_time_ms);
}
+EXPORT_SYMBOL(ipmi_request_settime);
int ipmi_request_supply_msgs(ipmi_user_t user,
struct ipmi_addr *addr,
@@ -1766,6 +1847,7 @@
lun,
-1, 0);
}
+EXPORT_SYMBOL(ipmi_request_supply_msgs);
#ifdef CONFIG_PROC_FS
static int ipmb_file_read_proc(char *page, char **start, off_t off,
@@ -1790,7 +1872,7 @@
char *out = (char *) page;
ipmi_smi_t intf = data;
- return sprintf(out, "%d.%d\n",
+ return sprintf(out, "%u.%u\n",
ipmi_version_major(&intf->bmc->id),
ipmi_version_minor(&intf->bmc->id));
}
@@ -1801,65 +1883,65 @@
char *out = (char *) page;
ipmi_smi_t intf = data;
- out += sprintf(out, "sent_invalid_commands: %d\n",
- intf->sent_invalid_commands);
- out += sprintf(out, "sent_local_commands: %d\n",
- intf->sent_local_commands);
- out += sprintf(out, "handled_local_responses: %d\n",
- intf->handled_local_responses);
- out += sprintf(out, "unhandled_local_responses: %d\n",
- intf->unhandled_local_responses);
- out += sprintf(out, "sent_ipmb_commands: %d\n",
- intf->sent_ipmb_commands);
- out += sprintf(out, "sent_ipmb_command_errs: %d\n",
- intf->sent_ipmb_command_errs);
- out += sprintf(out, "retransmitted_ipmb_commands: %d\n",
- intf->retransmitted_ipmb_commands);
- out += sprintf(out, "timed_out_ipmb_commands: %d\n",
- intf->timed_out_ipmb_commands);
- out += sprintf(out, "timed_out_ipmb_broadcasts: %d\n",
- intf->timed_out_ipmb_broadcasts);
- out += sprintf(out, "sent_ipmb_responses: %d\n",
- intf->sent_ipmb_responses);
- out += sprintf(out, "handled_ipmb_responses: %d\n",
- intf->handled_ipmb_responses);
- out += sprintf(out, "invalid_ipmb_responses: %d\n",
- intf->invalid_ipmb_responses);
- out += sprintf(out, "unhandled_ipmb_responses: %d\n",
- intf->unhandled_ipmb_responses);
- out += sprintf(out, "sent_lan_commands: %d\n",
- intf->sent_lan_commands);
- out += sprintf(out, "sent_lan_command_errs: %d\n",
- intf->sent_lan_command_errs);
- out += sprintf(out, "retransmitted_lan_commands: %d\n",
- intf->retransmitted_lan_commands);
- out += sprintf(out, "timed_out_lan_commands: %d\n",
- intf->timed_out_lan_commands);
- out += sprintf(out, "sent_lan_responses: %d\n",
- intf->sent_lan_responses);
- out += sprintf(out, "handled_lan_responses: %d\n",
- intf->handled_lan_responses);
- out += sprintf(out, "invalid_lan_responses: %d\n",
- intf->invalid_lan_responses);
- out += sprintf(out, "unhandled_lan_responses: %d\n",
- intf->unhandled_lan_responses);
- out += sprintf(out, "handled_commands: %d\n",
- intf->handled_commands);
- out += sprintf(out, "invalid_commands: %d\n",
- intf->invalid_commands);
- out += sprintf(out, "unhandled_commands: %d\n",
- intf->unhandled_commands);
- out += sprintf(out, "invalid_events: %d\n",
- intf->invalid_events);
- out += sprintf(out, "events: %d\n",
- intf->events);
+ out += sprintf(out, "sent_invalid_commands: %u\n",
+ ipmi_get_stat(intf, sent_invalid_commands));
+ out += sprintf(out, "sent_local_commands: %u\n",
+ ipmi_get_stat(intf, sent_local_commands));
+ out += sprintf(out, "handled_local_responses: %u\n",
+ ipmi_get_stat(intf, handled_local_responses));
+ out += sprintf(out, "unhandled_local_responses: %u\n",
+ ipmi_get_stat(intf, unhandled_local_responses));
+ out += sprintf(out, "sent_ipmb_commands: %u\n",
+ ipmi_get_stat(intf, sent_ipmb_commands));
+ out += sprintf(out, "sent_ipmb_command_errs: %u\n",
+ ipmi_get_stat(intf, sent_ipmb_command_errs));
+ out += sprintf(out, "retransmitted_ipmb_commands: %u\n",
+ ipmi_get_stat(intf, retransmitted_ipmb_commands));
+ out += sprintf(out, "timed_out_ipmb_commands: %u\n",
+ ipmi_get_stat(intf, timed_out_ipmb_commands));
+ out += sprintf(out, "timed_out_ipmb_broadcasts: %u\n",
+ ipmi_get_stat(intf, timed_out_ipmb_broadcasts));
+ out += sprintf(out, "sent_ipmb_responses: %u\n",
+ ipmi_get_stat(intf, sent_ipmb_responses));
+ out += sprintf(out, "handled_ipmb_responses: %u\n",
+ ipmi_get_stat(intf, handled_ipmb_responses));
+ out += sprintf(out, "invalid_ipmb_responses: %u\n",
+ ipmi_get_stat(intf, invalid_ipmb_responses));
+ out += sprintf(out, "unhandled_ipmb_responses: %u\n",
+ ipmi_get_stat(intf, unhandled_ipmb_responses));
+ out += sprintf(out, "sent_lan_commands: %u\n",
+ ipmi_get_stat(intf, sent_lan_commands));
+ out += sprintf(out, "sent_lan_command_errs: %u\n",
+ ipmi_get_stat(intf, sent_lan_command_errs));
+ out += sprintf(out, "retransmitted_lan_commands: %u\n",
+ ipmi_get_stat(intf, retransmitted_lan_commands));
+ out += sprintf(out, "timed_out_lan_commands: %u\n",
+ ipmi_get_stat(intf, timed_out_lan_commands));
+ out += sprintf(out, "sent_lan_responses: %u\n",
+ ipmi_get_stat(intf, sent_lan_responses));
+ out += sprintf(out, "handled_lan_responses: %u\n",
+ ipmi_get_stat(intf, handled_lan_responses));
+ out += sprintf(out, "invalid_lan_responses: %u\n",
+ ipmi_get_stat(intf, invalid_lan_responses));
+ out += sprintf(out, "unhandled_lan_responses: %u\n",
+ ipmi_get_stat(intf, unhandled_lan_responses));
+ out += sprintf(out, "handled_commands: %u\n",
+ ipmi_get_stat(intf, handled_commands));
+ out += sprintf(out, "invalid_commands: %u\n",
+ ipmi_get_stat(intf, invalid_commands));
+ out += sprintf(out, "unhandled_commands: %u\n",
+ ipmi_get_stat(intf, unhandled_commands));
+ out += sprintf(out, "invalid_events: %u\n",
+ ipmi_get_stat(intf, invalid_events));
+ out += sprintf(out, "events: %u\n",
+ ipmi_get_stat(intf, events));
return (out - ((char *) page));
}
#endif /* CONFIG_PROC_FS */
int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
- read_proc_t *read_proc, write_proc_t *write_proc,
+ read_proc_t *read_proc,
void *data, struct module *owner)
{
int rv = 0;
@@ -1886,7 +1968,6 @@
} else {
file->data = data;
file->read_proc = read_proc;
- file->write_proc = write_proc;
file->owner = owner;
mutex_lock(&smi->proc_entry_lock);
@@ -1899,6 +1980,7 @@
return rv;
}
+EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
static int add_proc_entries(ipmi_smi_t smi, int num)
{
@@ -1909,23 +1991,22 @@
smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
if (!smi->proc_dir)
rv = -ENOMEM;
- else {
+ else
smi->proc_dir->owner = THIS_MODULE;
- }
if (rv == 0)
rv = ipmi_smi_add_proc_entry(smi, "stats",
- stat_file_read_proc, NULL,
+ stat_file_read_proc,
smi, THIS_MODULE);
if (rv == 0)
rv = ipmi_smi_add_proc_entry(smi, "ipmb",
- ipmb_file_read_proc, NULL,
+ ipmb_file_read_proc,
smi, THIS_MODULE);
if (rv == 0)
rv = ipmi_smi_add_proc_entry(smi, "version",
- version_file_read_proc, NULL,
+ version_file_read_proc,
smi, THIS_MODULE);
#endif /* CONFIG_PROC_FS */
@@ -2210,37 +2291,47 @@
err = device_create_file(&bmc->dev->dev,
&bmc->device_id_attr);
- if (err) goto out;
+ if (err)
+ goto out;
err = device_create_file(&bmc->dev->dev,
&bmc->provides_dev_sdrs_attr);
- if (err) goto out_devid;
+ if (err)
+ goto out_devid;
err = device_create_file(&bmc->dev->dev,
&bmc->revision_attr);
- if (err) goto out_sdrs;
+ if (err)
+ goto out_sdrs;
err = device_create_file(&bmc->dev->dev,
&bmc->firmware_rev_attr);
- if (err) goto out_rev;
+ if (err)
+ goto out_rev;
err = device_create_file(&bmc->dev->dev,
&bmc->version_attr);
- if (err) goto out_firm;
+ if (err)
+ goto out_firm;
err = device_create_file(&bmc->dev->dev,
&bmc->add_dev_support_attr);
- if (err) goto out_version;
+ if (err)
+ goto out_version;
err = device_create_file(&bmc->dev->dev,
&bmc->manufacturer_id_attr);
- if (err) goto out_add_dev;
+ if (err)
+ goto out_add_dev;
err = device_create_file(&bmc->dev->dev,
&bmc->product_id_attr);
- if (err) goto out_manu;
+ if (err)
+ goto out_manu;
if (bmc->id.aux_firmware_revision_set) {
err = device_create_file(&bmc->dev->dev,
&bmc->aux_firmware_rev_attr);
- if (err) goto out_prod_id;
+ if (err)
+ goto out_prod_id;
}
if (bmc->guid_set) {
err = device_create_file(&bmc->dev->dev,
&bmc->guid_attr);
- if (err) goto out_aux_firm;
+ if (err)
+ goto out_aux_firm;
}
return 0;
@@ -2368,8 +2459,10 @@
"ipmi_msghandler:"
" Unable to register bmc device: %d\n",
rv);
- /* Don't go to out_err, you can only do that if
- the device is registered already. */
+ /*
+ * Don't go to out_err, you can only do that if
+ * the device is registered already.
+ */
return rv;
}
@@ -2560,17 +2653,18 @@
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))
- {
+ && (msg->msg.cmd == IPMI_GET_CHANNEL_INFO_CMD)) {
/* It's the one we want */
if (msg->msg.data[0] != 0) {
/* Got an error from the channel, just go on. */
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
- zero. */
+ /*
+ * If the MC does not support this
+ * command, that is legal. We just
+ * assume it has one IPMB at channel
+ * zero.
+ */
intf->channels[0].medium
= IPMI_CHANNEL_MEDIUM_IPMB;
intf->channels[0].protocol
@@ -2591,7 +2685,7 @@
intf->channels[chan].medium = msg->msg.data[2] & 0x7f;
intf->channels[chan].protocol = msg->msg.data[3] & 0x1f;
- next_channel:
+ next_channel:
intf->curr_channel++;
if (intf->curr_channel >= IPMI_MAX_CHANNELS)
wake_up(&intf->waitq);
@@ -2619,6 +2713,7 @@
if (intf->handlers->poll)
intf->handlers->poll(intf->send_info);
}
+EXPORT_SYMBOL(ipmi_poll_interface);
int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
void *send_info,
@@ -2633,14 +2728,18 @@
ipmi_smi_t tintf;
struct list_head *link;
- /* Make sure the driver is actually initialized, this handles
- problems with initialization order. */
+ /*
+ * Make sure the driver is actually initialized, this handles
+ * problems with initialization order.
+ */
if (!initialized) {
rv = ipmi_init_msghandler();
if (rv)
return rv;
- /* The init code doesn't return an error if it was turned
- off, but it won't initialize. Check that. */
+ /*
+ * The init code doesn't return an error if it was turned
+ * off, but it won't initialize. Check that.
+ */
if (!initialized)
return -ENODEV;
}
@@ -2688,8 +2787,9 @@
spin_lock_init(&intf->maintenance_mode_lock);
INIT_LIST_HEAD(&intf->cmd_rcvrs);
init_waitqueue_head(&intf->waitq);
+ for (i = 0; i < IPMI_NUM_STATS; i++)
+ atomic_set(&intf->stats[i], 0);
- spin_lock_init(&intf->counter_lock);
intf->proc_dir = NULL;
mutex_lock(&smi_watchers_mutex);
@@ -2717,11 +2817,12 @@
get_guid(intf);
if ((intf->ipmi_version_major > 1)
- || ((intf->ipmi_version_major == 1)
- && (intf->ipmi_version_minor >= 5)))
- {
- /* Start scanning the channels to see what is
- available. */
+ || ((intf->ipmi_version_major == 1)
+ && (intf->ipmi_version_minor >= 5))) {
+ /*
+ * Start scanning the channels to see what is
+ * available.
+ */
intf->null_user_handler = channel_handler;
intf->curr_channel = 0;
rv = send_channel_info_cmd(intf, 0);
@@ -2769,6 +2870,7 @@
return rv;
}
+EXPORT_SYMBOL(ipmi_register_smi);
static void cleanup_smi_msgs(ipmi_smi_t intf)
{
@@ -2803,8 +2905,10 @@
remove_proc_entries(intf);
- /* Call all the watcher interfaces to tell them that
- an interface is gone. */
+ /*
+ * Call all the watcher interfaces to tell them that
+ * an interface is gone.
+ */
list_for_each_entry(w, &smi_watchers, link)
w->smi_gone(intf_num);
mutex_unlock(&smi_watchers_mutex);
@@ -2812,22 +2916,21 @@
kref_put(&intf->refcount, intf_free);
return 0;
}
+EXPORT_SYMBOL(ipmi_unregister_smi);
static int handle_ipmb_get_msg_rsp(ipmi_smi_t intf,
struct ipmi_smi_msg *msg)
{
struct ipmi_ipmb_addr ipmb_addr;
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
-
- /* This is 11, not 10, because the response must contain a
- * completion code. */
+ /*
+ * This is 11, not 10, because the response must contain a
+ * completion code.
+ */
if (msg->rsp_size < 11) {
/* Message not big enough, just ignore it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_ipmb_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_ipmb_responses);
return 0;
}
@@ -2841,37 +2944,38 @@
ipmb_addr.channel = msg->rsp[3] & 0x0f;
ipmb_addr.lun = msg->rsp[7] & 3;
- /* It's a response from a remote entity. Look up the sequence
- number and handle the response. */
+ /*
+ * It's a response from a remote entity. Look up the sequence
+ * number and handle the response.
+ */
if (intf_find_seq(intf,
msg->rsp[7] >> 2,
msg->rsp[3] & 0x0f,
msg->rsp[8],
(msg->rsp[4] >> 2) & (~1),
(struct ipmi_addr *) &(ipmb_addr),
- &recv_msg))
- {
- /* We were unable to find the sequence number,
- so just nuke the message. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_ipmb_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ &recv_msg)) {
+ /*
+ * We were unable to find the sequence number,
+ * so just nuke the message.
+ */
+ ipmi_inc_stat(intf, unhandled_ipmb_responses);
return 0;
}
memcpy(recv_msg->msg_data,
&(msg->rsp[9]),
msg->rsp_size - 9);
- /* THe other fields matched, so no need to set them, except
- for netfn, which needs to be the response that was
- returned, not the request value. */
+ /*
+ * The other fields matched, so no need to set them, except
+ * for netfn, which needs to be the response that was
+ * returned, not the request value.
+ */
recv_msg->msg.netfn = msg->rsp[4] >> 2;
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = msg->rsp_size - 10;
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_ipmb_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_ipmb_responses);
deliver_response(recv_msg);
return 0;
@@ -2888,14 +2992,11 @@
ipmi_user_t user = NULL;
struct ipmi_ipmb_addr *ipmb_addr;
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
struct ipmi_smi_handlers *handlers;
if (msg->rsp_size < 10) {
/* Message not big enough, just ignore it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_commands);
return 0;
}
@@ -2919,19 +3020,17 @@
if (user == NULL) {
/* We didn't find a user, deliver an error response. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, unhandled_commands);
msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg->data[1] = IPMI_SEND_MSG_CMD;
msg->data[2] = msg->rsp[3];
msg->data[3] = msg->rsp[6];
- msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
+ msg->data[4] = ((netfn + 1) << 2) | (msg->rsp[7] & 0x3);
msg->data[5] = ipmb_checksum(&(msg->data[3]), 2);
msg->data[6] = intf->channels[msg->rsp[3] & 0xf].address;
- /* rqseq/lun */
- msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
+ /* rqseq/lun */
+ msg->data[7] = (msg->rsp[7] & 0xfc) | (msg->rsp[4] & 0x3);
msg->data[8] = msg->rsp[8]; /* cmd */
msg->data[9] = IPMI_INVALID_CMD_COMPLETION_CODE;
msg->data[10] = ipmb_checksum(&(msg->data[6]), 4);
@@ -2950,23 +3049,25 @@
handlers = intf->handlers;
if (handlers) {
handlers->sender(intf->send_info, msg, 0);
- /* We used the message, so return the value
- that causes it to not be freed or
- queued. */
+ /*
+ * We used the message, so return the value
+ * that causes it to not be freed or
+ * queued.
+ */
rv = -1;
}
rcu_read_unlock();
} else {
/* Deliver the message to the user. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_commands);
recv_msg = ipmi_alloc_recv_msg();
if (!recv_msg) {
- /* We couldn't allocate memory for the
- message, so requeue it for handling
- later. */
+ /*
+ * We couldn't allocate memory for the
+ * message, so requeue it for handling
+ * later.
+ */
rv = 1;
kref_put(&user->refcount, free_user);
} else {
@@ -2977,8 +3078,10 @@
ipmb_addr->lun = msg->rsp[7] & 3;
ipmb_addr->channel = msg->rsp[3] & 0xf;
- /* Extract the rest of the message information
- from the IPMB header.*/
+ /*
+ * Extract the rest of the message information
+ * from the IPMB header.
+ */
recv_msg->user = user;
recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
recv_msg->msgid = msg->rsp[7] >> 2;
@@ -2986,8 +3089,10 @@
recv_msg->msg.cmd = msg->rsp[8];
recv_msg->msg.data = recv_msg->msg_data;
- /* We chop off 10, not 9 bytes because the checksum
- at the end also needs to be removed. */
+ /*
+ * We chop off 10, not 9 bytes because the checksum
+ * at the end also needs to be removed.
+ */
recv_msg->msg.data_len = msg->rsp_size - 10;
memcpy(recv_msg->msg_data,
&(msg->rsp[9]),
@@ -3004,16 +3109,15 @@
{
struct ipmi_lan_addr lan_addr;
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
- /* This is 13, not 12, because the response must contain a
- * completion code. */
+ /*
+ * This is 13, not 12, because the response must contain a
+ * completion code.
+ */
if (msg->rsp_size < 13) {
/* Message not big enough, just ignore it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_lan_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_lan_responses);
return 0;
}
@@ -3030,37 +3134,38 @@
lan_addr.privilege = msg->rsp[3] >> 4;
lan_addr.lun = msg->rsp[9] & 3;
- /* It's a response from a remote entity. Look up the sequence
- number and handle the response. */
+ /*
+ * It's a response from a remote entity. Look up the sequence
+ * number and handle the response.
+ */
if (intf_find_seq(intf,
msg->rsp[9] >> 2,
msg->rsp[3] & 0x0f,
msg->rsp[10],
(msg->rsp[6] >> 2) & (~1),
(struct ipmi_addr *) &(lan_addr),
- &recv_msg))
- {
- /* We were unable to find the sequence number,
- so just nuke the message. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_lan_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ &recv_msg)) {
+ /*
+ * We were unable to find the sequence number,
+ * so just nuke the message.
+ */
+ ipmi_inc_stat(intf, unhandled_lan_responses);
return 0;
}
memcpy(recv_msg->msg_data,
&(msg->rsp[11]),
msg->rsp_size - 11);
- /* The other fields matched, so no need to set them, except
- for netfn, which needs to be the response that was
- returned, not the request value. */
+ /*
+ * The other fields matched, so no need to set them, except
+ * for netfn, which needs to be the response that was
+ * returned, not the request value.
+ */
recv_msg->msg.netfn = msg->rsp[6] >> 2;
recv_msg->msg.data = recv_msg->msg_data;
recv_msg->msg.data_len = msg->rsp_size - 12;
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_lan_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_lan_responses);
deliver_response(recv_msg);
return 0;
@@ -3077,13 +3182,10 @@
ipmi_user_t user = NULL;
struct ipmi_lan_addr *lan_addr;
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
if (msg->rsp_size < 12) {
/* Message not big enough, just ignore it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_commands);
return 0;
}
@@ -3107,23 +3209,23 @@
if (user == NULL) {
/* We didn't find a user, just give up. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->unhandled_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, unhandled_commands);
- rv = 0; /* Don't do anything with these messages, just
- allow them to be freed. */
+ /*
+ * Don't do anything with these messages, just allow
+ * them to be freed.
+ */
+ rv = 0;
} else {
/* Deliver the message to the user. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_commands++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_commands);
recv_msg = ipmi_alloc_recv_msg();
if (!recv_msg) {
- /* We couldn't allocate memory for the
- message, so requeue it for handling
- later. */
+ /*
+ * We couldn't allocate memory for the
+ * message, so requeue it for handling later.
+ */
rv = 1;
kref_put(&user->refcount, free_user);
} else {
@@ -3137,8 +3239,10 @@
lan_addr->channel = msg->rsp[3] & 0xf;
lan_addr->privilege = msg->rsp[3] >> 4;
- /* Extract the rest of the message information
- from the IPMB header.*/
+ /*
+ * Extract the rest of the message information
+ * from the IPMB header.
+ */
recv_msg->user = user;
recv_msg->recv_type = IPMI_CMD_RECV_TYPE;
recv_msg->msgid = msg->rsp[9] >> 2;
@@ -3146,8 +3250,10 @@
recv_msg->msg.cmd = msg->rsp[10];
recv_msg->msg.data = recv_msg->msg_data;
- /* We chop off 12, not 11 bytes because the checksum
- at the end also needs to be removed. */
+ /*
+ * We chop off 12, not 11 bytes because the checksum
+ * at the end also needs to be removed.
+ */
recv_msg->msg.data_len = msg->rsp_size - 12;
memcpy(recv_msg->msg_data,
&(msg->rsp[11]),
@@ -3163,7 +3269,7 @@
struct ipmi_smi_msg *msg)
{
struct ipmi_system_interface_addr *smi_addr;
-
+
recv_msg->msgid = 0;
smi_addr = (struct ipmi_system_interface_addr *) &(recv_msg->addr);
smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
@@ -3189,9 +3295,7 @@
if (msg->rsp_size < 19) {
/* Message is too small to be an IPMB event. */
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->invalid_events++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, invalid_events);
return 0;
}
@@ -3204,12 +3308,12 @@
spin_lock_irqsave(&intf->events_lock, flags);
- spin_lock(&intf->counter_lock);
- intf->events++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, events);
- /* Allocate and fill in one message for every user that is getting
- events. */
+ /*
+ * Allocate and fill in one message for every user that is
+ * getting events.
+ */
rcu_read_lock();
list_for_each_entry_rcu(user, &intf->users, link) {
if (!user->gets_events)
@@ -3223,9 +3327,11 @@
list_del(&recv_msg->link);
ipmi_free_recv_msg(recv_msg);
}
- /* We couldn't allocate memory for the
- message, so requeue it for handling
- later. */
+ /*
+ * We couldn't allocate memory for the
+ * message, so requeue it for handling
+ * later.
+ */
rv = 1;
goto out;
}
@@ -3246,13 +3352,17 @@
deliver_response(recv_msg);
}
} else if (intf->waiting_events_count < MAX_EVENTS_IN_QUEUE) {
- /* No one to receive the message, put it in queue if there's
- not already too many things in the queue. */
+ /*
+ * No one to receive the message, put it in queue if there's
+ * not already too many things in the queue.
+ */
recv_msg = ipmi_alloc_recv_msg();
if (!recv_msg) {
- /* We couldn't allocate memory for the
- message, so requeue it for handling
- later. */
+ /*
+ * We couldn't allocate memory for the
+ * message, so requeue it for handling
+ * later.
+ */
rv = 1;
goto out;
}
@@ -3260,11 +3370,14 @@
copy_event_into_recv_msg(recv_msg, msg);
list_add_tail(&(recv_msg->link), &(intf->waiting_events));
intf->waiting_events_count++;
- } else {
- /* There's too many things in the queue, discard this
- message. */
- printk(KERN_WARNING PFX "Event queue full, discarding an"
- " incoming event\n");
+ } else if (!intf->event_msg_printed) {
+ /*
+ * There's too many things in the queue, discard this
+ * message.
+ */
+ printk(KERN_WARNING PFX "Event queue full, discarding"
+ " incoming events\n");
+ intf->event_msg_printed = 1;
}
out:
@@ -3277,16 +3390,15 @@
struct ipmi_smi_msg *msg)
{
struct ipmi_recv_msg *recv_msg;
- unsigned long flags;
struct ipmi_user *user;
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");
+ 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;
}
@@ -3294,16 +3406,12 @@
/* Make sure the user still exists. */
if (user && !user->valid) {
/* 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_inc_stat(intf, unhandled_local_responses);
ipmi_free_recv_msg(recv_msg);
} else {
struct ipmi_system_interface_addr *smi_addr;
- spin_lock_irqsave(&intf->counter_lock, flags);
- intf->handled_local_responses++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, handled_local_responses);
recv_msg->recv_type = IPMI_RESPONSE_RECV_TYPE;
recv_msg->msgid = msg->msgid;
smi_addr = ((struct ipmi_system_interface_addr *)
@@ -3324,9 +3432,11 @@
return 0;
}
-/* Handle a new message. Return 1 if the message should be requeued,
- 0 if the message should be freed, or -1 if the message should not
- be freed or requeued. */
+/*
+ * Handle a new message. Return 1 if the message should be requeued,
+ * 0 if the message should be freed, or -1 if the message should not
+ * be freed or requeued.
+ */
static int handle_new_recv_msg(ipmi_smi_t intf,
struct ipmi_smi_msg *msg)
{
@@ -3351,10 +3461,12 @@
msg->rsp[1] = msg->data[1];
msg->rsp[2] = IPMI_ERR_UNSPECIFIED;
msg->rsp_size = 3;
- } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))/* Netfn */
- || (msg->rsp[1] != msg->data[1])) /* Command */
- {
- /* The response is not even marginally correct. */
+ } else if (((msg->rsp[0] >> 2) != ((msg->data[0] >> 2) | 1))
+ || (msg->rsp[1] != msg->data[1])) {
+ /*
+ * The NetFN and Command in the response is not even
+ * marginally correct.
+ */
printk(KERN_WARNING PFX "BMC returned incorrect response,"
" expected netfn %x cmd %x, got netfn %x cmd %x\n",
(msg->data[0] >> 2) | 1, msg->data[1],
@@ -3369,10 +3481,11 @@
if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
&& (msg->rsp[1] == IPMI_SEND_MSG_CMD)
- && (msg->user_data != NULL))
- {
- /* It's a response to a response we sent. For this we
- deliver a send message response to the user. */
+ && (msg->user_data != NULL)) {
+ /*
+ * It's a response to a response we sent. For this we
+ * deliver a send message response to the user.
+ */
struct ipmi_recv_msg *recv_msg = msg->user_data;
requeue = 0;
@@ -3398,8 +3511,7 @@
recv_msg->msg_data[0] = msg->rsp[2];
deliver_response(recv_msg);
} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
- && (msg->rsp[1] == IPMI_GET_MSG_CMD))
- {
+ && (msg->rsp[1] == IPMI_GET_MSG_CMD)) {
/* It's from the receive queue. */
chan = msg->rsp[3] & 0xf;
if (chan >= IPMI_MAX_CHANNELS) {
@@ -3411,12 +3523,16 @@
switch (intf->channels[chan].medium) {
case IPMI_CHANNEL_MEDIUM_IPMB:
if (msg->rsp[4] & 0x04) {
- /* It's a response, so find the
- requesting message and send it up. */
+ /*
+ * It's a response, so find the
+ * requesting message and send it up.
+ */
requeue = handle_ipmb_get_msg_rsp(intf, msg);
} else {
- /* It's a command to the SMS from some other
- entity. Handle that. */
+ /*
+ * It's a command to the SMS from some other
+ * entity. Handle that.
+ */
requeue = handle_ipmb_get_msg_cmd(intf, msg);
}
break;
@@ -3424,25 +3540,30 @@
case IPMI_CHANNEL_MEDIUM_8023LAN:
case IPMI_CHANNEL_MEDIUM_ASYNC:
if (msg->rsp[6] & 0x04) {
- /* It's a response, so find the
- requesting message and send it up. */
+ /*
+ * It's a response, so find the
+ * requesting message and send it up.
+ */
requeue = handle_lan_get_msg_rsp(intf, msg);
} else {
- /* It's a command to the SMS from some other
- entity. Handle that. */
+ /*
+ * It's a command to the SMS from some other
+ * entity. Handle that.
+ */
requeue = handle_lan_get_msg_cmd(intf, msg);
}
break;
default:
- /* We don't handle the channel type, so just
- * free the message. */
+ /*
+ * We don't handle the channel type, so just
+ * free the message.
+ */
requeue = 0;
}
} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
- && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD))
- {
+ && (msg->rsp[1] == IPMI_READ_EVENT_MSG_BUFFER_CMD)) {
/* It's an asyncronous event. */
requeue = handle_read_event_rsp(intf, msg);
} else {
@@ -3458,71 +3579,82 @@
void ipmi_smi_msg_received(ipmi_smi_t intf,
struct ipmi_smi_msg *msg)
{
- unsigned long flags;
+ unsigned long flags = 0; /* keep us warning-free. */
int rv;
+ int run_to_completion;
if ((msg->data_size >= 2)
&& (msg->data[0] == (IPMI_NETFN_APP_REQUEST << 2))
&& (msg->data[1] == IPMI_SEND_MSG_CMD)
- && (msg->user_data == NULL))
- {
- /* This is the local response to a command send, start
- the timer for these. The user_data will not be
- NULL if this is a response send, and we will let
- response sends just go through. */
+ && (msg->user_data == NULL)) {
+ /*
+ * This is the local response to a command send, start
+ * the timer for these. The user_data will not be
+ * NULL if this is a response send, and we will let
+ * response sends just go through.
+ */
- /* Check for errors, if we get certain errors (ones
- that mean basically we can try again later), we
- ignore them and start the timer. Otherwise we
- report the error immediately. */
+ /*
+ * Check for errors, if we get certain errors (ones
+ * that mean basically we can try again later), we
+ * ignore them and start the timer. Otherwise we
+ * report the error immediately.
+ */
if ((msg->rsp_size >= 3) && (msg->rsp[2] != 0)
&& (msg->rsp[2] != IPMI_NODE_BUSY_ERR)
&& (msg->rsp[2] != IPMI_LOST_ARBITRATION_ERR)
&& (msg->rsp[2] != IPMI_BUS_ERR)
- && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR))
- {
+ && (msg->rsp[2] != IPMI_NAK_ON_WRITE_ERR)) {
int chan = msg->rsp[3] & 0xf;
/* Got an error sending the message, handle it. */
- spin_lock_irqsave(&intf->counter_lock, flags);
if (chan >= IPMI_MAX_CHANNELS)
; /* This shouldn't happen */
else if ((intf->channels[chan].medium
== IPMI_CHANNEL_MEDIUM_8023LAN)
|| (intf->channels[chan].medium
== IPMI_CHANNEL_MEDIUM_ASYNC))
- intf->sent_lan_command_errs++;
+ ipmi_inc_stat(intf, sent_lan_command_errs);
else
- intf->sent_ipmb_command_errs++;
- spin_unlock_irqrestore(&intf->counter_lock, flags);
+ ipmi_inc_stat(intf, sent_ipmb_command_errs);
intf_err_seq(intf, msg->msgid, msg->rsp[2]);
- } else {
+ } else
/* The message was sent, start the timer. */
intf_start_seq_timer(intf, msg->msgid);
- }
ipmi_free_smi_msg(msg);
goto out;
}
- /* To preserve message order, if the list is not empty, we
- tack this message onto the end of the list. */
- spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+ /*
+ * To preserve message order, if the list is not empty, we
+ * tack this message onto the end of the list.
+ */
+ run_to_completion = intf->run_to_completion;
+ if (!run_to_completion)
+ spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
if (!list_empty(&intf->waiting_msgs)) {
list_add_tail(&msg->link, &intf->waiting_msgs);
- spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+ if (!run_to_completion)
+ spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
goto out;
}
- spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
-
+ if (!run_to_completion)
+ spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+
rv = handle_new_recv_msg(intf, msg);
if (rv > 0) {
- /* Could not handle the message now, just add it to a
- list to handle later. */
- spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
+ /*
+ * Could not handle the message now, just add it to a
+ * list to handle later.
+ */
+ run_to_completion = intf->run_to_completion;
+ if (!run_to_completion)
+ spin_lock_irqsave(&intf->waiting_msgs_lock, flags);
list_add_tail(&msg->link, &intf->waiting_msgs);
- spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
+ if (!run_to_completion)
+ spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
} else if (rv == 0) {
ipmi_free_smi_msg(msg);
}
@@ -3530,6 +3662,7 @@
out:
return;
}
+EXPORT_SYMBOL(ipmi_smi_msg_received);
void ipmi_smi_watchdog_pretimeout(ipmi_smi_t intf)
{
@@ -3544,7 +3677,7 @@
}
rcu_read_unlock();
}
-
+EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
static struct ipmi_smi_msg *
smi_from_recv_msg(ipmi_smi_t intf, struct ipmi_recv_msg *recv_msg,
@@ -3552,14 +3685,16 @@
{
struct ipmi_smi_msg *smi_msg = ipmi_alloc_smi_msg();
if (!smi_msg)
- /* If we can't allocate the message, then just return, we
- get 4 retries, so this should be ok. */
+ /*
+ * If we can't allocate the message, then just return, we
+ * get 4 retries, so this should be ok.
+ */
return NULL;
memcpy(smi_msg->data, recv_msg->msg.data, recv_msg->msg.data_len);
smi_msg->data_size = recv_msg->msg.data_len;
smi_msg->msgid = STORE_SEQ_IN_MSGID(seq, seqid);
-
+
#ifdef DEBUG_MSGING
{
int m;
@@ -3594,28 +3729,26 @@
ent->inuse = 0;
msg = ent->recv_msg;
list_add_tail(&msg->link, timeouts);
- spin_lock(&intf->counter_lock);
if (ent->broadcast)
- intf->timed_out_ipmb_broadcasts++;
+ ipmi_inc_stat(intf, timed_out_ipmb_broadcasts);
else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
- intf->timed_out_lan_commands++;
+ ipmi_inc_stat(intf, timed_out_lan_commands);
else
- intf->timed_out_ipmb_commands++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, timed_out_ipmb_commands);
} else {
struct ipmi_smi_msg *smi_msg;
/* More retries, send again. */
- /* Start with the max timer, set to normal
- timer after the message is sent. */
+ /*
+ * Start with the max timer, set to normal timer after
+ * the message is sent.
+ */
ent->timeout = MAX_MSG_TIMEOUT;
ent->retries_left--;
- spin_lock(&intf->counter_lock);
if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
- intf->retransmitted_lan_commands++;
+ ipmi_inc_stat(intf, retransmitted_lan_commands);
else
- intf->retransmitted_ipmb_commands++;
- spin_unlock(&intf->counter_lock);
+ ipmi_inc_stat(intf, retransmitted_ipmb_commands);
smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
ent->seqid);
@@ -3624,11 +3757,13 @@
spin_unlock_irqrestore(&intf->seq_lock, *flags);
- /* Send the new message. We send with a zero
- * priority. It timed out, I doubt time is
- * that critical now, and high priority
- * messages are really only for messages to the
- * local MC, which don't get resent. */
+ /*
+ * Send the new message. We send with a zero
+ * priority. It timed out, I doubt time is that
+ * critical now, and high priority messages are really
+ * only for messages to the local MC, which don't get
+ * resent.
+ */
handlers = intf->handlers;
if (handlers)
intf->handlers->sender(intf->send_info,
@@ -3659,16 +3794,20 @@
list_del(&smi_msg->link);
ipmi_free_smi_msg(smi_msg);
} else {
- /* To preserve message order, quit if we
- can't handle a message. */
+ /*
+ * To preserve message order, quit if we
+ * can't handle a message.
+ */
break;
}
}
spin_unlock_irqrestore(&intf->waiting_msgs_lock, flags);
- /* Go through the seq table and find any messages that
- have timed out, putting them in the timeouts
- list. */
+ /*
+ * Go through the seq table and find any messages that
+ * have timed out, putting them in the timeouts
+ * list.
+ */
INIT_LIST_HEAD(&timeouts);
spin_lock_irqsave(&intf->seq_lock, flags);
for (i = 0; i < IPMI_IPMB_NUM_SEQ; i++)
@@ -3694,8 +3833,7 @@
intf->auto_maintenance_timeout
-= timeout_period;
if (!intf->maintenance_mode
- && (intf->auto_maintenance_timeout <= 0))
- {
+ && (intf->auto_maintenance_timeout <= 0)) {
intf->maintenance_mode_enable = 0;
maintenance_mode_update(intf);
}
@@ -3713,8 +3851,10 @@
struct ipmi_smi_handlers *handlers;
rcu_read_lock();
- /* Called from the timer, no need to check if handlers is
- * valid. */
+ /*
+ * Called from the timer, no need to check if handlers is
+ * valid.
+ */
list_for_each_entry_rcu(intf, &ipmi_interfaces, link) {
/* No event requests when in maintenance mode. */
if (intf->maintenance_mode_enable)
@@ -3735,10 +3875,12 @@
/* How many jiffies does it take to get to the timeout time. */
#define IPMI_TIMEOUT_JIFFIES ((IPMI_TIMEOUT_TIME * HZ) / 1000)
-/* Request events from the queue every second (this is the number of
- IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
- future, IPMI will add a way to know immediately if an event is in
- the queue and this silliness can go away. */
+/*
+ * Request events from the queue every second (this is the number of
+ * IPMI_TIMEOUT_TIMES between event requests). Hopefully, in the
+ * future, IPMI will add a way to know immediately if an event is in
+ * the queue and this silliness can go away.
+ */
#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
static atomic_t stop_operation;
@@ -3782,6 +3924,7 @@
}
return rv;
}
+EXPORT_SYMBOL(ipmi_alloc_smi_msg);
static void free_recv_msg(struct ipmi_recv_msg *msg)
{
@@ -3789,7 +3932,7 @@
kfree(msg);
}
-struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
+static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
{
struct ipmi_recv_msg *rv;
@@ -3808,6 +3951,7 @@
kref_put(&msg->user->refcount, free_user);
msg->done(msg);
}
+EXPORT_SYMBOL(ipmi_free_recv_msg);
#ifdef CONFIG_IPMI_PANIC_EVENT
@@ -3825,8 +3969,7 @@
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))
- {
+ && (msg->msg.data[0] == IPMI_CC_NO_ERROR)) {
/* A get event receiver command, save it. */
intf->event_receiver = msg->msg.data[1];
intf->event_receiver_lun = msg->msg.data[2] & 0x3;
@@ -3838,10 +3981,11 @@
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. */
+ && (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->msg.data[6] >> 2) & 1;
intf->local_event_generator = (msg->msg.data[6] >> 5) & 1;
}
@@ -3874,8 +4018,10 @@
data[4] = 0x6f; /* Sensor specific, IPMI table 36-1 */
data[5] = 0xa1; /* Runtime stop OEM bytes 2 & 3. */
- /* Put a few breadcrumbs in. Hopefully later we can add more things
- to make the panic events more useful. */
+ /*
+ * Put a few breadcrumbs in. Hopefully later we can add more things
+ * to make the panic events more useful.
+ */
if (str) {
data[3] = str[0];
data[6] = str[1];
@@ -3891,6 +4037,7 @@
/* Interface is not ready. */
continue;
+ intf->run_to_completion = 1;
/* Send the event announcing the panic. */
intf->handlers->set_run_to_completion(intf->send_info, 1);
i_ipmi_request(NULL,
@@ -3908,9 +4055,11 @@
}
#ifdef CONFIG_IPMI_PANIC_STRING
- /* On every interface, dump a bunch of OEM event holding the
- string. */
- if (!str)
+ /*
+ * On every interface, dump a bunch of OEM event holding the
+ * string.
+ */
+ if (!str)
return;
/* For every registered interface, send the event. */
@@ -3931,11 +4080,13 @@
*/
smp_rmb();
- /* First job here is to figure out where to send the
- OEM events. There's no way in IPMI to send OEM
- events using an event send command, so we have to
- find the SEL to put them in and stick them in
- there. */
+ /*
+ * First job here is to figure out where to send the
+ * OEM events. There's no way in IPMI to send OEM
+ * events using an event send command, so we have to
+ * find the SEL to put them in and stick them in
+ * there.
+ */
/* Get capabilities from the get device id. */
intf->local_sel_device = 0;
@@ -3983,24 +4134,29 @@
}
intf->null_user_handler = NULL;
- /* Validate the event receiver. The low bit must not
- be 1 (it must be a valid IPMB address), it cannot
- be zero, and it must not be my address. */
- if (((intf->event_receiver & 1) == 0)
+ /*
+ * Validate the event receiver. The low bit must not
+ * be 1 (it must be a valid IPMB address), it cannot
+ * be zero, and it must not be my address.
+ */
+ if (((intf->event_receiver & 1) == 0)
&& (intf->event_receiver != 0)
- && (intf->event_receiver != intf->channels[0].address))
- {
- /* The event receiver is valid, send an IPMB
- message. */
+ && (intf->event_receiver != intf->channels[0].address)) {
+ /*
+ * The event receiver is valid, send an IPMB
+ * message.
+ */
ipmb = (struct ipmi_ipmb_addr *) &addr;
ipmb->addr_type = IPMI_IPMB_ADDR_TYPE;
ipmb->channel = 0; /* FIXME - is this right? */
ipmb->lun = intf->event_receiver_lun;
ipmb->slave_addr = intf->event_receiver;
} else if (intf->local_sel_device) {
- /* The event receiver was not valid (or was
- me), but I am an SEL device, just dump it
- in my SEL. */
+ /*
+ * The event receiver was not valid (or was
+ * me), but I am an SEL device, just dump it
+ * in my SEL.
+ */
si = (struct ipmi_system_interface_addr *) &addr;
si->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
si->channel = IPMI_BMC_CHANNEL;
@@ -4008,7 +4164,6 @@
} else
continue; /* No where to send the event. */
-
msg.netfn = IPMI_NETFN_STORAGE_REQUEST; /* Storage. */
msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
msg.data = data;
@@ -4025,8 +4180,10 @@
data[2] = 0xf0; /* OEM event without timestamp. */
data[3] = intf->channels[0].address;
data[4] = j++; /* sequence # */
- /* Always give 11 bytes, so strncpy will fill
- it with zeroes for me. */
+ /*
+ * Always give 11 bytes, so strncpy will fill
+ * it with zeroes for me.
+ */
strncpy(data+5, p, 11);
p += size;
@@ -4043,7 +4200,7 @@
intf->channels[0].lun,
0, 1); /* no retry, and no wait. */
}
- }
+ }
#endif /* CONFIG_IPMI_PANIC_STRING */
}
#endif /* CONFIG_IPMI_PANIC_EVENT */
@@ -4052,7 +4209,7 @@
static int panic_event(struct notifier_block *this,
unsigned long event,
- void *ptr)
+ void *ptr)
{
ipmi_smi_t intf;
@@ -4066,6 +4223,7 @@
/* Interface is not ready. */
continue;
+ intf->run_to_completion = 1;
intf->handlers->set_run_to_completion(intf->send_info, 1);
}
@@ -4133,11 +4291,16 @@
atomic_notifier_chain_unregister(&panic_notifier_list, &panic_block);
- /* This can't be called if any interfaces exist, so no worry about
- shutting down the interfaces. */
+ /*
+ * This can't be called if any interfaces exist, so no worry
+ * about shutting down the interfaces.
+ */
- /* Tell the timer to stop, then wait for it to stop. This avoids
- problems with race conditions removing the timer here. */
+ /*
+ * Tell the timer to stop, then wait for it to stop. This
+ * avoids problems with race conditions removing the timer
+ * here.
+ */
atomic_inc(&stop_operation);
del_timer_sync(&ipmi_timer);
@@ -4164,31 +4327,6 @@
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_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);
-EXPORT_SYMBOL(ipmi_get_version);
-EXPORT_SYMBOL(ipmi_request_settime);
-EXPORT_SYMBOL(ipmi_request_supply_msgs);
-EXPORT_SYMBOL(ipmi_poll_interface);
-EXPORT_SYMBOL(ipmi_register_smi);
-EXPORT_SYMBOL(ipmi_unregister_smi);
-EXPORT_SYMBOL(ipmi_register_for_cmd);
-EXPORT_SYMBOL(ipmi_unregister_for_cmd);
-EXPORT_SYMBOL(ipmi_smi_msg_received);
-EXPORT_SYMBOL(ipmi_smi_watchdog_pretimeout);
-EXPORT_SYMBOL(ipmi_alloc_smi_msg);
-EXPORT_SYMBOL(ipmi_addr_length);
-EXPORT_SYMBOL(ipmi_validate_addr);
-EXPORT_SYMBOL(ipmi_set_gets_events);
-EXPORT_SYMBOL(ipmi_smi_watcher_register);
-EXPORT_SYMBOL(ipmi_smi_watcher_unregister);
-EXPORT_SYMBOL(ipmi_set_my_address);
-EXPORT_SYMBOL(ipmi_get_my_address);
-EXPORT_SYMBOL(ipmi_set_my_LUN);
-EXPORT_SYMBOL(ipmi_get_my_LUN);
-EXPORT_SYMBOL(ipmi_smi_add_proc_entry);
-EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
-EXPORT_SYMBOL(ipmi_free_recv_msg);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index b86186d..a261bd7 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -87,7 +87,10 @@
/* parameter definition to allow user to flag power cycle */
module_param(poweroff_powercycle, int, 0644);
-MODULE_PARM_DESC(poweroff_powercycle, " 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.");
+MODULE_PARM_DESC(poweroff_powercycle,
+ " 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;
@@ -95,22 +98,25 @@
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
- thing is single-threaded, anyway, so multiple messages are not
- required. */
+/*
+ * 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
+ * thing is single-threaded, anyway, so multiple messages are not
+ * required.
+ */
+static atomic_t dummy_count = ATOMIC_INIT(0);
static void dummy_smi_free(struct ipmi_smi_msg *msg)
{
+ atomic_dec(&dummy_count);
}
static void dummy_recv_free(struct ipmi_recv_msg *msg)
{
+ atomic_dec(&dummy_count);
}
-static struct ipmi_smi_msg halt_smi_msg =
-{
+static struct ipmi_smi_msg halt_smi_msg = {
.done = dummy_smi_free
};
-static struct ipmi_recv_msg halt_recv_msg =
-{
+static struct ipmi_recv_msg halt_recv_msg = {
.done = dummy_recv_free
};
@@ -127,8 +133,7 @@
complete(comp);
}
-static struct ipmi_user_hndl ipmi_poweroff_handler =
-{
+static struct ipmi_user_hndl ipmi_poweroff_handler = {
.ipmi_recv_hndl = receive_handler
};
@@ -152,17 +157,28 @@
return halt_recv_msg.msg.data[0];
}
-/* We are in run-to-completion mode, no completion is desired. */
+/* Wait for message to complete, spinning. */
static int ipmi_request_in_rc_mode(ipmi_user_t user,
struct ipmi_addr *addr,
struct kernel_ipmi_msg *send_msg)
{
int rv;
+ atomic_set(&dummy_count, 2);
rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
&halt_smi_msg, &halt_recv_msg, 0);
- if (rv)
+ if (rv) {
+ atomic_set(&dummy_count, 0);
return rv;
+ }
+
+ /*
+ * Spin until our message is done.
+ */
+ while (atomic_read(&dummy_count) > 0) {
+ ipmi_poll_interface(user);
+ cpu_relax();
+ }
return halt_recv_msg.msg.data[0];
}
@@ -184,47 +200,47 @@
static void (*atca_oem_poweroff_hook)(ipmi_user_t user);
-static void pps_poweroff_atca (ipmi_user_t user)
+static void pps_poweroff_atca(ipmi_user_t user)
{
- struct ipmi_system_interface_addr smi_addr;
- struct kernel_ipmi_msg send_msg;
- int rv;
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ struct ipmi_system_interface_addr smi_addr;
+ struct kernel_ipmi_msg send_msg;
+ int rv;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
- printk(KERN_INFO PFX "PPS powerdown hook used");
+ printk(KERN_INFO PFX "PPS powerdown hook used");
- send_msg.netfn = IPMI_NETFN_OEM;
- send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART;
- send_msg.data = IPMI_ATCA_PPS_IANA;
- send_msg.data_len = 3;
- rv = ipmi_request_in_rc_mode(user,
- (struct ipmi_addr *) &smi_addr,
- &send_msg);
- if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
- printk(KERN_ERR PFX "Unable to send ATCA ,"
- " IPMI error 0x%x\n", rv);
- }
+ send_msg.netfn = IPMI_NETFN_OEM;
+ send_msg.cmd = IPMI_ATCA_PPS_GRACEFUL_RESTART;
+ send_msg.data = IPMI_ATCA_PPS_IANA;
+ send_msg.data_len = 3;
+ rv = ipmi_request_in_rc_mode(user,
+ (struct ipmi_addr *) &smi_addr,
+ &send_msg);
+ if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
+ printk(KERN_ERR PFX "Unable to send ATCA ,"
+ " IPMI error 0x%x\n", rv);
+ }
return;
}
-static int ipmi_atca_detect (ipmi_user_t user)
+static int ipmi_atca_detect(ipmi_user_t user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
int rv;
unsigned char data[1];
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
/*
* Use get address info to check and see if we are ATCA
@@ -238,28 +254,30 @@
(struct ipmi_addr *) &smi_addr,
&send_msg);
- printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n", mfg_id, prod_id);
- if((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID)
- && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) {
- printk(KERN_INFO PFX "Installing Pigeon Point Systems Poweroff Hook\n");
+ printk(KERN_INFO PFX "ATCA Detect mfg 0x%X prod 0x%X\n",
+ mfg_id, prod_id);
+ if ((mfg_id == IPMI_MOTOROLA_MANUFACTURER_ID)
+ && (prod_id == IPMI_MOTOROLA_PPS_IPMC_PRODUCT_ID)) {
+ printk(KERN_INFO PFX
+ "Installing Pigeon Point Systems Poweroff Hook\n");
atca_oem_poweroff_hook = pps_poweroff_atca;
}
return !rv;
}
-static void ipmi_poweroff_atca (ipmi_user_t user)
+static void ipmi_poweroff_atca(ipmi_user_t user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
int rv;
unsigned char data[4];
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
printk(KERN_INFO PFX "Powering down via ATCA power command\n");
@@ -273,23 +291,24 @@
data[2] = 0; /* Power Level */
data[3] = 0; /* Don't change saved presets */
send_msg.data = data;
- send_msg.data_len = sizeof (data);
+ send_msg.data_len = sizeof(data);
rv = ipmi_request_in_rc_mode(user,
(struct ipmi_addr *) &smi_addr,
&send_msg);
- /** At this point, the system may be shutting down, and most
- ** serial drivers (if used) will have interrupts turned off
- ** it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE
- ** return code
- **/
- if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
+ /*
+ * At this point, the system may be shutting down, and most
+ * serial drivers (if used) will have interrupts turned off
+ * it may be better to ignore IPMI_UNKNOWN_ERR_COMPLETION_CODE
+ * return code
+ */
+ if (rv && rv != IPMI_UNKNOWN_ERR_COMPLETION_CODE) {
printk(KERN_ERR PFX "Unable to send ATCA powerdown message,"
" IPMI error 0x%x\n", rv);
goto out;
}
- if(atca_oem_poweroff_hook)
- return atca_oem_poweroff_hook(user);
+ if (atca_oem_poweroff_hook)
+ atca_oem_poweroff_hook(user);
out:
return;
}
@@ -310,13 +329,13 @@
#define IPMI_CPI1_PRODUCT_ID 0x000157
#define IPMI_CPI1_MANUFACTURER_ID 0x0108
-static int ipmi_cpi1_detect (ipmi_user_t user)
+static int ipmi_cpi1_detect(ipmi_user_t user)
{
return ((mfg_id == IPMI_CPI1_MANUFACTURER_ID)
&& (prod_id == IPMI_CPI1_PRODUCT_ID));
}
-static void ipmi_poweroff_cpi1 (ipmi_user_t user)
+static void ipmi_poweroff_cpi1(ipmi_user_t user)
{
struct ipmi_system_interface_addr smi_addr;
struct ipmi_ipmb_addr ipmb_addr;
@@ -328,12 +347,12 @@
unsigned char aer_addr;
unsigned char aer_lun;
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
printk(KERN_INFO PFX "Powering down via CPI1 power command\n");
@@ -425,7 +444,7 @@
*/
#define DELL_IANA_MFR_ID {0xA2, 0x02, 0x00}
-static int ipmi_dell_chassis_detect (ipmi_user_t user)
+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;
@@ -444,25 +463,25 @@
#define IPMI_NETFN_CHASSIS_REQUEST 0
#define IPMI_CHASSIS_CONTROL_CMD 0x02
-static int ipmi_chassis_detect (ipmi_user_t user)
+static int ipmi_chassis_detect(ipmi_user_t user)
{
/* Chassis support, use it. */
return (capabilities & 0x80);
}
-static void ipmi_poweroff_chassis (ipmi_user_t user)
+static void ipmi_poweroff_chassis(ipmi_user_t user)
{
struct ipmi_system_interface_addr smi_addr;
struct kernel_ipmi_msg send_msg;
int rv;
unsigned char data[1];
- /*
- * Configure IPMI address for local access
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ /*
+ * Configure IPMI address for local access
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
powercyclefailed:
printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
@@ -525,15 +544,13 @@
/* Called on a powerdown request. */
-static void ipmi_poweroff_function (void)
+static void ipmi_poweroff_function(void)
{
if (!ready)
return;
/* Use run-to-completion mode, since interrupts may be off. */
- ipmi_user_set_run_to_completion(ipmi_user, 1);
specific_poweroff_func(ipmi_user);
- ipmi_user_set_run_to_completion(ipmi_user, 0);
}
/* Wait for an IPMI interface to be installed, the first one installed
@@ -561,13 +578,13 @@
ipmi_ifnum = if_num;
- /*
- * Do a get device ide and store some results, since this is
+ /*
+ * Do a get device ide and store some results, since this is
* used by several functions.
- */
- smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
- smi_addr.channel = IPMI_BMC_CHANNEL;
- smi_addr.lun = 0;
+ */
+ smi_addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+ smi_addr.channel = IPMI_BMC_CHANNEL;
+ smi_addr.lun = 0;
send_msg.netfn = IPMI_NETFN_APP_REQUEST;
send_msg.cmd = IPMI_GET_DEVICE_ID_CMD;
@@ -632,8 +649,7 @@
pm_power_off = old_poweroff_func;
}
-static struct ipmi_smi_watcher smi_watcher =
-{
+static struct ipmi_smi_watcher smi_watcher = {
.owner = THIS_MODULE,
.new_smi = ipmi_po_new_smi,
.smi_gone = ipmi_po_smi_gone
@@ -675,12 +691,12 @@
/*
* Startup and shutdown functions.
*/
-static int ipmi_poweroff_init (void)
+static int ipmi_poweroff_init(void)
{
int rv;
- printk (KERN_INFO "Copyright (C) 2004 MontaVista Software -"
- " IPMI Powerdown via sys_reboot.\n");
+ printk(KERN_INFO "Copyright (C) 2004 MontaVista Software -"
+ " IPMI Powerdown via sys_reboot.\n");
if (poweroff_powercycle)
printk(KERN_INFO PFX "Power cycle is enabled.\n");
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 4f560d0..5a54555 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -80,7 +80,7 @@
#define SI_USEC_PER_JIFFY (1000000/HZ)
#define SI_TIMEOUT_JIFFIES (SI_TIMEOUT_TIME_USEC/SI_USEC_PER_JIFFY)
#define SI_SHORT_TIMEOUT_USEC 250 /* .25ms when the SM request a
- short timeout */
+ short timeout */
/* Bit for BMC global enables. */
#define IPMI_BMC_RCV_MSG_INTR 0x01
@@ -114,14 +114,61 @@
#define DEVICE_NAME "ipmi_si"
-static struct device_driver ipmi_driver =
-{
+static struct device_driver ipmi_driver = {
.name = DEVICE_NAME,
.bus = &platform_bus_type
};
-struct smi_info
-{
+
+/*
+ * Indexes into stats[] in smi_info below.
+ */
+enum si_stat_indexes {
+ /*
+ * Number of times the driver requested a timer while an operation
+ * was in progress.
+ */
+ SI_STAT_short_timeouts = 0,
+
+ /*
+ * Number of times the driver requested a timer while nothing was in
+ * progress.
+ */
+ SI_STAT_long_timeouts,
+
+ /* Number of times the interface was idle while being polled. */
+ SI_STAT_idles,
+
+ /* Number of interrupts the driver handled. */
+ SI_STAT_interrupts,
+
+ /* Number of time the driver got an ATTN from the hardware. */
+ SI_STAT_attentions,
+
+ /* Number of times the driver requested flags from the hardware. */
+ SI_STAT_flag_fetches,
+
+ /* Number of times the hardware didn't follow the state machine. */
+ SI_STAT_hosed_count,
+
+ /* Number of completed messages. */
+ SI_STAT_complete_transactions,
+
+ /* Number of IPMI events received from the hardware. */
+ SI_STAT_events,
+
+ /* Number of watchdog pretimeouts. */
+ SI_STAT_watchdog_pretimeouts,
+
+ /* Number of asyncronous messages received. */
+ SI_STAT_incoming_messages,
+
+
+ /* This *must* remain last, add new values above this. */
+ SI_NUM_STATS
+};
+
+struct smi_info {
int intf_num;
ipmi_smi_t intf;
struct si_sm_data *si_sm;
@@ -134,8 +181,10 @@
struct ipmi_smi_msg *curr_msg;
enum si_intf_state si_state;
- /* Used to handle the various types of I/O that can occur with
- IPMI */
+ /*
+ * Used to handle the various types of I/O that can occur with
+ * IPMI
+ */
struct si_sm_io io;
int (*io_setup)(struct smi_info *info);
void (*io_cleanup)(struct smi_info *info);
@@ -146,15 +195,18 @@
void (*addr_source_cleanup)(struct smi_info *info);
void *addr_source_data;
- /* 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.
- */
+ /*
+ * 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. */
+ /*
+ * 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
@@ -162,25 +214,31 @@
#define OEM1_DATA_AVAIL 0x40
#define OEM2_DATA_AVAIL 0x80
#define OEM_DATA_AVAIL (OEM0_DATA_AVAIL | \
- OEM1_DATA_AVAIL | \
- OEM2_DATA_AVAIL)
+ OEM1_DATA_AVAIL | \
+ OEM2_DATA_AVAIL)
unsigned char msg_flags;
- /* If set to true, this will request events the next time the
- state machine is idle. */
+ /*
+ * If set to true, this will request events the next time the
+ * state machine is idle.
+ */
atomic_t req_events;
- /* If true, run the state machine to completion on every send
- call. Generally used after a panic to make sure stuff goes
- out. */
+ /*
+ * If true, run the state machine to completion on every send
+ * call. Generally used after a panic to make sure stuff goes
+ * out.
+ */
int run_to_completion;
/* The I/O port of an SI interface. */
int port;
- /* The space between start addresses of the two ports. For
- instance, if the first port is 0xca2 and the spacing is 4, then
- the second port is 0xca6. */
+ /*
+ * The space between start addresses of the two ports. For
+ * instance, if the first port is 0xca2 and the spacing is 4, then
+ * the second port is 0xca6.
+ */
unsigned int spacing;
/* zero if no irq; */
@@ -195,10 +253,12 @@
/* Used to gracefully stop the timer without race conditions. */
atomic_t stop_operation;
- /* The driver will disable interrupts when it gets into a
- situation where it cannot handle messages due to lack of
- memory. Once that situation clears up, it will re-enable
- interrupts. */
+ /*
+ * The driver will disable interrupts when it gets into a
+ * situation where it cannot handle messages due to lack of
+ * memory. Once that situation clears up, it will re-enable
+ * interrupts.
+ */
int interrupt_disabled;
/* From the get device id response... */
@@ -208,33 +268,28 @@
struct device *dev;
struct platform_device *pdev;
- /* True if we allocated the device, false if it came from
- * someplace else (like PCI). */
+ /*
+ * True if we allocated the device, false if it came from
+ * someplace else (like PCI).
+ */
int dev_registered;
/* Slave address, could be reported from DMI. */
unsigned char slave_addr;
/* Counters and things for the proc filesystem. */
- spinlock_t count_lock;
- unsigned long short_timeouts;
- unsigned long long_timeouts;
- unsigned long timeout_restarts;
- unsigned long idles;
- unsigned long interrupts;
- unsigned long attentions;
- unsigned long flag_fetches;
- unsigned long hosed_count;
- unsigned long complete_transactions;
- unsigned long events;
- unsigned long watchdog_pretimeouts;
- unsigned long incoming_messages;
+ atomic_t stats[SI_NUM_STATS];
- struct task_struct *thread;
+ struct task_struct *thread;
struct list_head link;
};
+#define smi_inc_stat(smi, stat) \
+ atomic_inc(&(smi)->stats[SI_STAT_ ## stat])
+#define smi_get_stat(smi, stat) \
+ ((unsigned int) atomic_read(&(smi)->stats[SI_STAT_ ## stat]))
+
#define SI_MAX_PARMS 4
static int force_kipmid[SI_MAX_PARMS];
@@ -246,7 +301,7 @@
static void cleanup_one_si(struct smi_info *to_clean);
static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
-static int register_xaction_notifier(struct notifier_block * nb)
+static int register_xaction_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&xaction_notifier_list, nb);
}
@@ -255,7 +310,7 @@
struct ipmi_smi_msg *msg)
{
/* Deliver the message to the upper layer with the lock
- released. */
+ released. */
spin_unlock(&(smi_info->si_lock));
ipmi_smi_msg_received(smi_info->intf, msg);
spin_lock(&(smi_info->si_lock));
@@ -287,9 +342,12 @@
struct timeval t;
#endif
- /* No need to save flags, we aleady have interrupts off and we
- already hold the SMI lock. */
- spin_lock(&(smi_info->msg_lock));
+ /*
+ * No need to save flags, we aleady have interrupts off and we
+ * already hold the SMI lock.
+ */
+ if (!smi_info->run_to_completion)
+ spin_lock(&(smi_info->msg_lock));
/* Pick the high priority queue first. */
if (!list_empty(&(smi_info->hp_xmit_msgs))) {
@@ -310,7 +368,7 @@
link);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
- printk("**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+ printk(KERN_DEBUG "**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
err = atomic_notifier_call_chain(&xaction_notifier_list,
0, smi_info);
@@ -322,14 +380,14 @@
smi_info->si_sm,
smi_info->curr_msg->data,
smi_info->curr_msg->data_size);
- if (err) {
+ if (err)
return_hosed_msg(smi_info, err);
- }
rv = SI_SM_CALL_WITHOUT_DELAY;
}
- out:
- spin_unlock(&(smi_info->msg_lock));
+ out:
+ if (!smi_info->run_to_completion)
+ spin_unlock(&(smi_info->msg_lock));
return rv;
}
@@ -338,8 +396,10 @@
{
unsigned char msg[2];
- /* If we are enabling interrupts, we have to tell the
- BMC to use them. */
+ /*
+ * If we are enabling interrupts, we have to tell the
+ * BMC to use them.
+ */
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
@@ -371,10 +431,12 @@
smi_info->si_state = SI_CLEARING_FLAGS;
}
-/* When we have a situtaion where we run out of memory and cannot
- allocate messages, we just leave them in the BMC and run the system
- polled until we can allocate some memory. Once we have some
- memory, we will re-enable the interrupt. */
+/*
+ * When we have a situtaion where we run out of memory and cannot
+ * allocate messages, we just leave them in the BMC and run the system
+ * polled until we can allocate some memory. Once we have some
+ * 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)) {
@@ -396,9 +458,7 @@
retry:
if (smi_info->msg_flags & WDT_PRE_TIMEOUT_INT) {
/* Watchdog pre-timeout */
- spin_lock(&smi_info->count_lock);
- smi_info->watchdog_pretimeouts++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, watchdog_pretimeouts);
start_clear_flags(smi_info);
smi_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
@@ -444,12 +504,11 @@
smi_info->curr_msg->data_size);
smi_info->si_state = SI_GETTING_EVENTS;
} else if (smi_info->msg_flags & OEM_DATA_AVAIL &&
- smi_info->oem_data_avail_handler) {
+ smi_info->oem_data_avail_handler) {
if (smi_info->oem_data_avail_handler(smi_info))
goto retry;
- } else {
+ } else
smi_info->si_state = SI_NORMAL;
- }
}
static void handle_transaction_done(struct smi_info *smi_info)
@@ -459,7 +518,7 @@
struct timeval t;
do_gettimeofday(&t);
- printk("**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+ printk(KERN_DEBUG "**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
switch (smi_info->si_state) {
case SI_NORMAL:
@@ -472,9 +531,11 @@
smi_info->curr_msg->rsp,
IPMI_MAX_MSG_LENGTH);
- /* Do this here becase deliver_recv_msg() releases the
- lock, and a new message can be put in during the
- time the lock is released. */
+ /*
+ * Do this here becase deliver_recv_msg() releases the
+ * lock, and a new message can be put in during the
+ * time the lock is released.
+ */
msg = smi_info->curr_msg;
smi_info->curr_msg = NULL;
deliver_recv_msg(smi_info, msg);
@@ -488,12 +549,13 @@
/* We got the flags from the SMI, now handle them. */
len = smi_info->handlers->get_result(smi_info->si_sm, msg, 4);
if (msg[2] != 0) {
- /* Error fetching flags, just give up for
- now. */
+ /* Error fetching flags, just give up for now. */
smi_info->si_state = SI_NORMAL;
} else if (len < 4) {
- /* Hmm, no flags. That's technically illegal, but
- don't use uninitialized data. */
+ /*
+ * Hmm, no flags. That's technically illegal, but
+ * don't use uninitialized data.
+ */
smi_info->si_state = SI_NORMAL;
} else {
smi_info->msg_flags = msg[3];
@@ -530,9 +592,11 @@
smi_info->curr_msg->rsp,
IPMI_MAX_MSG_LENGTH);
- /* Do this here becase deliver_recv_msg() releases the
- lock, and a new message can be put in during the
- time the lock is released. */
+ /*
+ * Do this here becase deliver_recv_msg() releases the
+ * lock, and a new message can be put in during the
+ * time the lock is released.
+ */
msg = smi_info->curr_msg;
smi_info->curr_msg = NULL;
if (msg->rsp[2] != 0) {
@@ -543,14 +607,14 @@
smi_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
handle_flags(smi_info);
} else {
- spin_lock(&smi_info->count_lock);
- smi_info->events++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, events);
- /* Do this before we deliver the message
- because delivering the message releases the
- lock and something else can mess with the
- state. */
+ /*
+ * Do this before we deliver the message
+ * because delivering the message releases the
+ * lock and something else can mess with the
+ * state.
+ */
handle_flags(smi_info);
deliver_recv_msg(smi_info, msg);
@@ -566,9 +630,11 @@
smi_info->curr_msg->rsp,
IPMI_MAX_MSG_LENGTH);
- /* Do this here becase deliver_recv_msg() releases the
- lock, and a new message can be put in during the
- time the lock is released. */
+ /*
+ * Do this here becase deliver_recv_msg() releases the
+ * lock, and a new message can be put in during the
+ * time the lock is released.
+ */
msg = smi_info->curr_msg;
smi_info->curr_msg = NULL;
if (msg->rsp[2] != 0) {
@@ -579,14 +645,14 @@
smi_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
handle_flags(smi_info);
} else {
- spin_lock(&smi_info->count_lock);
- smi_info->incoming_messages++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, incoming_messages);
- /* Do this before we deliver the message
- because delivering the message releases the
- lock and something else can mess with the
- state. */
+ /*
+ * Do this before we deliver the message
+ * because delivering the message releases the
+ * lock and something else can mess with the
+ * state.
+ */
handle_flags(smi_info);
deliver_recv_msg(smi_info, msg);
@@ -674,69 +740,70 @@
}
}
-/* Called on timeouts and events. Timeouts should pass the elapsed
- time, interrupts should pass in zero. Must be called with
- si_lock held and interrupts disabled. */
+/*
+ * Called on timeouts and events. Timeouts should pass the elapsed
+ * time, interrupts should pass in zero. Must be called with
+ * si_lock held and interrupts disabled.
+ */
static enum si_sm_result smi_event_handler(struct smi_info *smi_info,
int time)
{
enum si_sm_result si_sm_result;
restart:
- /* There used to be a loop here that waited a little while
- (around 25us) before giving up. That turned out to be
- pointless, the minimum delays I was seeing were in the 300us
- range, which is far too long to wait in an interrupt. So
- we just run until the state machine tells us something
- happened or it needs a delay. */
+ /*
+ * There used to be a loop here that waited a little while
+ * (around 25us) before giving up. That turned out to be
+ * pointless, the minimum delays I was seeing were in the 300us
+ * range, which is far too long to wait in an interrupt. So
+ * we just run until the state machine tells us something
+ * happened or it needs a delay.
+ */
si_sm_result = smi_info->handlers->event(smi_info->si_sm, time);
time = 0;
while (si_sm_result == SI_SM_CALL_WITHOUT_DELAY)
- {
si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
- }
- if (si_sm_result == SI_SM_TRANSACTION_COMPLETE)
- {
- spin_lock(&smi_info->count_lock);
- smi_info->complete_transactions++;
- spin_unlock(&smi_info->count_lock);
+ if (si_sm_result == SI_SM_TRANSACTION_COMPLETE) {
+ smi_inc_stat(smi_info, complete_transactions);
handle_transaction_done(smi_info);
si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
- }
- else if (si_sm_result == SI_SM_HOSED)
- {
- spin_lock(&smi_info->count_lock);
- smi_info->hosed_count++;
- spin_unlock(&smi_info->count_lock);
+ } else if (si_sm_result == SI_SM_HOSED) {
+ smi_inc_stat(smi_info, hosed_count);
- /* Do the before return_hosed_msg, because that
- releases the lock. */
+ /*
+ * Do the before return_hosed_msg, because that
+ * releases the lock.
+ */
smi_info->si_state = SI_NORMAL;
if (smi_info->curr_msg != NULL) {
- /* If we were handling a user message, format
- a response to send to the upper layer to
- tell it about the error. */
+ /*
+ * If we were handling a user message, format
+ * a response to send to the upper layer to
+ * tell it about the error.
+ */
return_hosed_msg(smi_info, IPMI_ERR_UNSPECIFIED);
}
si_sm_result = smi_info->handlers->event(smi_info->si_sm, 0);
}
- /* We prefer handling attn over new messages. */
- if (si_sm_result == SI_SM_ATTN)
- {
+ /*
+ * We prefer handling attn over new messages. But don't do
+ * this if there is not yet an upper layer to handle anything.
+ */
+ if (likely(smi_info->intf) && si_sm_result == SI_SM_ATTN) {
unsigned char msg[2];
- spin_lock(&smi_info->count_lock);
- smi_info->attentions++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, attentions);
- /* Got a attn, send down a get message flags to see
- what's causing it. It would be better to handle
- this in the upper layer, but due to the way
- interrupts work with the SMI, that's not really
- possible. */
+ /*
+ * Got a attn, send down a get message flags to see
+ * what's causing it. It would be better to handle
+ * this in the upper layer, but due to the way
+ * interrupts work with the SMI, that's not really
+ * possible.
+ */
msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
msg[1] = IPMI_GET_MSG_FLAGS_CMD;
@@ -748,20 +815,19 @@
/* If we are currently idle, try to start the next message. */
if (si_sm_result == SI_SM_IDLE) {
- spin_lock(&smi_info->count_lock);
- smi_info->idles++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, idles);
si_sm_result = start_next_msg(smi_info);
if (si_sm_result != SI_SM_IDLE)
goto restart;
- }
+ }
if ((si_sm_result == SI_SM_IDLE)
- && (atomic_read(&smi_info->req_events)))
- {
- /* We are idle and the upper layer requested that I fetch
- events, so do so. */
+ && (atomic_read(&smi_info->req_events))) {
+ /*
+ * We are idle and the upper layer requested that I fetch
+ * events, so do so.
+ */
atomic_set(&smi_info->req_events, 0);
smi_info->curr_msg = ipmi_alloc_smi_msg();
@@ -803,56 +869,50 @@
return;
}
- spin_lock_irqsave(&(smi_info->msg_lock), flags);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
if (smi_info->run_to_completion) {
- /* If we are running to completion, then throw it in
- the list and run transactions until everything is
- clear. Priority doesn't matter here. */
+ /*
+ * If we are running to completion, then throw it in
+ * the list and run transactions until everything is
+ * clear. Priority doesn't matter here.
+ */
+
+ /*
+ * Run to completion means we are single-threaded, no
+ * need for locks.
+ */
list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
- /* We have to release the msg lock and claim the smi
- lock in this case, because of race conditions. */
- spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
-
- spin_lock_irqsave(&(smi_info->si_lock), flags);
result = smi_event_handler(smi_info, 0);
while (result != SI_SM_IDLE) {
udelay(SI_SHORT_TIMEOUT_USEC);
result = smi_event_handler(smi_info,
SI_SHORT_TIMEOUT_USEC);
}
- spin_unlock_irqrestore(&(smi_info->si_lock), flags);
return;
- } else {
- if (priority > 0) {
- list_add_tail(&(msg->link), &(smi_info->hp_xmit_msgs));
- } else {
- list_add_tail(&(msg->link), &(smi_info->xmit_msgs));
- }
}
- spin_unlock_irqrestore(&(smi_info->msg_lock), flags);
- spin_lock_irqsave(&(smi_info->si_lock), flags);
- if ((smi_info->si_state == SI_NORMAL)
- && (smi_info->curr_msg == NULL))
- {
+ spin_lock_irqsave(&smi_info->msg_lock, flags);
+ if (priority > 0)
+ list_add_tail(&msg->link, &smi_info->hp_xmit_msgs);
+ else
+ list_add_tail(&msg->link, &smi_info->xmit_msgs);
+ spin_unlock_irqrestore(&smi_info->msg_lock, flags);
+
+ spin_lock_irqsave(&smi_info->si_lock, flags);
+ if (smi_info->si_state == SI_NORMAL && smi_info->curr_msg == NULL)
start_next_msg(smi_info);
- }
- spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+ spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
static void set_run_to_completion(void *send_info, int i_run_to_completion)
{
struct smi_info *smi_info = send_info;
enum si_sm_result result;
- unsigned long flags;
-
- spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_info->run_to_completion = i_run_to_completion;
if (i_run_to_completion) {
@@ -863,8 +923,6 @@
SI_SHORT_TIMEOUT_USEC);
}
}
-
- spin_unlock_irqrestore(&(smi_info->si_lock), flags);
}
static int ipmi_thread(void *data)
@@ -878,9 +936,8 @@
spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_result = smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
- if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
- /* do nothing */
- }
+ if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
+ ; /* do nothing */
else if (smi_result == SI_SM_CALL_WITH_DELAY)
schedule();
else
@@ -931,7 +988,7 @@
spin_lock_irqsave(&(smi_info->si_lock), flags);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
- printk("**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+ printk(KERN_DEBUG "**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
jiffies_now = jiffies;
time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
@@ -945,23 +1002,19 @@
if ((smi_info->irq) && (!smi_info->interrupt_disabled)) {
/* Running with interrupts, only do long timeouts. */
smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
- spin_lock_irqsave(&smi_info->count_lock, flags);
- smi_info->long_timeouts++;
- spin_unlock_irqrestore(&smi_info->count_lock, flags);
+ smi_inc_stat(smi_info, long_timeouts);
goto do_add_timer;
}
- /* If the state machine asks for a short delay, then shorten
- the timer timeout. */
+ /*
+ * If the state machine asks for a short delay, then shorten
+ * the timer timeout.
+ */
if (smi_result == SI_SM_CALL_WITH_DELAY) {
- spin_lock_irqsave(&smi_info->count_lock, flags);
- smi_info->short_timeouts++;
- spin_unlock_irqrestore(&smi_info->count_lock, flags);
+ smi_inc_stat(smi_info, short_timeouts);
smi_info->si_timer.expires = jiffies + 1;
} else {
- spin_lock_irqsave(&smi_info->count_lock, flags);
- smi_info->long_timeouts++;
- spin_unlock_irqrestore(&smi_info->count_lock, flags);
+ smi_inc_stat(smi_info, long_timeouts);
smi_info->si_timer.expires = jiffies + SI_TIMEOUT_JIFFIES;
}
@@ -979,13 +1032,11 @@
spin_lock_irqsave(&(smi_info->si_lock), flags);
- spin_lock(&smi_info->count_lock);
- smi_info->interrupts++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, interrupts);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
- printk("**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
+ printk(KERN_DEBUG "**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
#endif
smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
@@ -1028,7 +1079,7 @@
* The BT interface is efficient enough to not need a thread,
* and there is no need for a thread if we have interrupts.
*/
- else if ((new_smi->si_type != SI_BT) && (!new_smi->irq))
+ else if ((new_smi->si_type != SI_BT) && (!new_smi->irq))
enable = 1;
if (enable) {
@@ -1054,8 +1105,7 @@
atomic_set(&smi_info->req_events, 0);
}
-static struct ipmi_smi_handlers handlers =
-{
+static struct ipmi_smi_handlers handlers = {
.owner = THIS_MODULE,
.start_processing = smi_start_processing,
.sender = sender,
@@ -1065,8 +1115,10 @@
.poll = poll,
};
-/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
- a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS */
+/*
+ * There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
+ * a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS.
+ */
static LIST_HEAD(smi_infos);
static DEFINE_MUTEX(smi_infos_lock);
@@ -1257,10 +1309,9 @@
int idx;
if (addr) {
- for (idx = 0; idx < info->io_size; idx++) {
+ for (idx = 0; idx < info->io_size; idx++)
release_region(addr + idx * info->io.regspacing,
info->io.regsize);
- }
}
}
@@ -1274,8 +1325,10 @@
info->io_cleanup = port_cleanup;
- /* Figure out the actual inb/inw/inl/etc routine to use based
- upon the register size. */
+ /*
+ * Figure out the actual inb/inw/inl/etc routine to use based
+ * upon the register size.
+ */
switch (info->io.regsize) {
case 1:
info->io.inputb = port_inb;
@@ -1290,17 +1343,18 @@
info->io.outputb = port_outl;
break;
default:
- printk("ipmi_si: Invalid register size: %d\n",
+ printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n",
info->io.regsize);
return -EINVAL;
}
- /* Some BIOSes reserve disjoint I/O regions in their ACPI
+ /*
+ * Some BIOSes reserve disjoint I/O regions in their ACPI
* tables. This causes problems when trying to register the
* entire I/O region. Therefore we must register each I/O
* port separately.
*/
- for (idx = 0; idx < info->io_size; idx++) {
+ for (idx = 0; idx < info->io_size; idx++) {
if (request_region(addr + idx * info->io.regspacing,
info->io.regsize, DEVICE_NAME) == NULL) {
/* Undo allocations */
@@ -1388,8 +1442,10 @@
info->io_cleanup = mem_cleanup;
- /* Figure out the actual readb/readw/readl/etc routine to use based
- upon the register size. */
+ /*
+ * Figure out the actual readb/readw/readl/etc routine to use based
+ * upon the register size.
+ */
switch (info->io.regsize) {
case 1:
info->io.inputb = intf_mem_inb;
@@ -1410,16 +1466,18 @@
break;
#endif
default:
- printk("ipmi_si: Invalid register size: %d\n",
+ printk(KERN_WARNING "ipmi_si: Invalid register size: %d\n",
info->io.regsize);
return -EINVAL;
}
- /* Calculate the total amount of memory to claim. This is an
+ /*
+ * Calculate the total amount of memory to claim. This is an
* unusual looking calculation, but it avoids claiming any
* more memory than it has to. It will claim everything
* between the first address to the end of the last full
- * register. */
+ * register.
+ */
mapsize = ((info->io_size * info->io.regspacing)
- (info->io.regspacing - info->io.regsize));
@@ -1749,9 +1807,11 @@
#include <linux/acpi.h>
-/* Once we get an ACPI failure, we don't try any more, because we go
- through the tables sequentially. Once we don't find a table, there
- are no more. */
+/*
+ * Once we get an ACPI failure, we don't try any more, because we go
+ * through the tables sequentially. Once we don't find a table, there
+ * are no more.
+ */
static int acpi_failure;
/* For GPE-type interrupts. */
@@ -1765,9 +1825,7 @@
spin_lock_irqsave(&(smi_info->si_lock), flags);
- spin_lock(&smi_info->count_lock);
- smi_info->interrupts++;
- spin_unlock(&smi_info->count_lock);
+ smi_inc_stat(smi_info, interrupts);
#ifdef DEBUG_TIMING
do_gettimeofday(&t);
@@ -1816,7 +1874,8 @@
/*
* Defined at
- * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/Docs/TechPapers/IA64/hpspmi.pdf
+ * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/
+ * Docs/TechPapers/IA64/hpspmi.pdf
*/
struct SPMITable {
s8 Signature[4];
@@ -1838,14 +1897,18 @@
*/
u8 InterruptType;
- /* If bit 0 of InterruptType is set, then this is the SCI
- interrupt in the GPEx_STS register. */
+ /*
+ * If bit 0 of InterruptType is set, then this is the SCI
+ * interrupt in the GPEx_STS register.
+ */
u8 GPE;
s16 Reserved;
- /* If bit 1 of InterruptType is set, then this is the I/O
- APIC/SAPIC interrupt. */
+ /*
+ * If bit 1 of InterruptType is set, then this is the I/O
+ * APIC/SAPIC interrupt.
+ */
u32 GlobalSystemInterrupt;
/* The actual register address. */
@@ -1863,7 +1926,7 @@
if (spmi->IPMIlegacy != 1) {
printk(KERN_INFO "IPMI: Bad SPMI legacy %d\n", spmi->IPMIlegacy);
- return -ENODEV;
+ return -ENODEV;
}
if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
@@ -1880,8 +1943,7 @@
info->addr_source = "ACPI";
/* Figure out the interface type. */
- switch (spmi->InterfaceType)
- {
+ switch (spmi->InterfaceType) {
case 1: /* KCS */
info->si_type = SI_KCS;
break;
@@ -1929,7 +1991,8 @@
info->io.addr_type = IPMI_IO_ADDR_SPACE;
} else {
kfree(info);
- printk("ipmi_si: Unknown ACPI I/O Address type\n");
+ printk(KERN_WARNING
+ "ipmi_si: Unknown ACPI I/O Address type\n");
return -EIO;
}
info->io.addr_data = spmi->addr.address;
@@ -1963,8 +2026,7 @@
#endif
#ifdef CONFIG_DMI
-struct dmi_ipmi_data
-{
+struct dmi_ipmi_data {
u8 type;
u8 addr_space;
unsigned long base_addr;
@@ -1989,11 +2051,10 @@
/* I/O */
base_addr &= 0xFFFE;
dmi->addr_space = IPMI_IO_ADDR_SPACE;
- }
- else {
+ } else
/* Memory */
dmi->addr_space = IPMI_MEM_ADDR_SPACE;
- }
+
/* If bit 4 of byte 0x10 is set, then the lsb for the address
is odd. */
dmi->base_addr = base_addr | ((data[0x10] & 0x10) >> 4);
@@ -2002,7 +2063,7 @@
/* The top two bits of byte 0x10 hold the register spacing. */
reg_spacing = (data[0x10] & 0xC0) >> 6;
- switch(reg_spacing){
+ switch (reg_spacing) {
case 0x00: /* Byte boundaries */
dmi->offset = 1;
break;
@@ -2018,12 +2079,14 @@
}
} else {
/* Old DMI spec. */
- /* Note that technically, the lower bit of the base
+ /*
+ * Note that technically, the lower bit of the base
* address should be 1 if the address is I/O and 0 if
* the address is in memory. So many systems get that
* wrong (and all that I have seen are I/O) so we just
* ignore that bit and assume I/O. Systems that use
- * memory should use the newer spec, anyway. */
+ * memory should use the newer spec, anyway.
+ */
dmi->base_addr = base_addr & 0xfffe;
dmi->addr_space = IPMI_IO_ADDR_SPACE;
dmi->offset = 1;
@@ -2230,13 +2293,13 @@
MODULE_DEVICE_TABLE(pci, ipmi_pci_devices);
static struct pci_driver ipmi_pci_driver = {
- .name = DEVICE_NAME,
- .id_table = ipmi_pci_devices,
- .probe = ipmi_pci_probe,
- .remove = __devexit_p(ipmi_pci_remove),
+ .name = DEVICE_NAME,
+ .id_table = ipmi_pci_devices,
+ .probe = ipmi_pci_probe,
+ .remove = __devexit_p(ipmi_pci_remove),
#ifdef CONFIG_PM
- .suspend = ipmi_pci_suspend,
- .resume = ipmi_pci_resume,
+ .suspend = ipmi_pci_suspend,
+ .resume = ipmi_pci_resume,
#endif
};
#endif /* CONFIG_PCI */
@@ -2306,7 +2369,7 @@
info->io.addr_data, info->io.regsize, info->io.regspacing,
info->irq);
- dev->dev.driver_data = (void*) info;
+ dev->dev.driver_data = (void *) info;
return try_smi_init(info);
}
@@ -2319,14 +2382,16 @@
static struct of_device_id ipmi_match[] =
{
- { .type = "ipmi", .compatible = "ipmi-kcs", .data = (void *)(unsigned long) SI_KCS },
- { .type = "ipmi", .compatible = "ipmi-smic", .data = (void *)(unsigned long) SI_SMIC },
- { .type = "ipmi", .compatible = "ipmi-bt", .data = (void *)(unsigned long) SI_BT },
+ { .type = "ipmi", .compatible = "ipmi-kcs",
+ .data = (void *)(unsigned long) SI_KCS },
+ { .type = "ipmi", .compatible = "ipmi-smic",
+ .data = (void *)(unsigned long) SI_SMIC },
+ { .type = "ipmi", .compatible = "ipmi-bt",
+ .data = (void *)(unsigned long) SI_BT },
{},
};
-static struct of_platform_driver ipmi_of_platform_driver =
-{
+static struct of_platform_driver ipmi_of_platform_driver = {
.name = "ipmi",
.match_table = ipmi_match,
.probe = ipmi_of_probe,
@@ -2347,32 +2412,32 @@
if (!resp)
return -ENOMEM;
- /* Do a Get Device ID command, since it comes back with some
- useful info. */
+ /*
+ * Do a Get Device ID command, since it comes back with some
+ * useful info.
+ */
msg[0] = IPMI_NETFN_APP_REQUEST << 2;
msg[1] = IPMI_GET_DEVICE_ID_CMD;
smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
- for (;;)
- {
+ for (;;) {
if (smi_result == SI_SM_CALL_WITH_DELAY ||
smi_result == SI_SM_CALL_WITH_TICK_DELAY) {
schedule_timeout_uninterruptible(1);
smi_result = smi_info->handlers->event(
smi_info->si_sm, 100);
- }
- else if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
- {
+ } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
smi_result = smi_info->handlers->event(
smi_info->si_sm, 0);
- }
- else
+ } else
break;
}
if (smi_result == SI_SM_HOSED) {
- /* We couldn't get the state machine to run, so whatever's at
- the port is probably not an IPMI SMI interface. */
+ /*
+ * We couldn't get the state machine to run, so whatever's at
+ * the port is probably not an IPMI SMI interface.
+ */
rv = -ENODEV;
goto out;
}
@@ -2405,30 +2470,28 @@
out += sprintf(out, "interrupts_enabled: %d\n",
smi->irq && !smi->interrupt_disabled);
- out += sprintf(out, "short_timeouts: %ld\n",
- smi->short_timeouts);
- out += sprintf(out, "long_timeouts: %ld\n",
- smi->long_timeouts);
- out += sprintf(out, "timeout_restarts: %ld\n",
- smi->timeout_restarts);
- out += sprintf(out, "idles: %ld\n",
- smi->idles);
- out += sprintf(out, "interrupts: %ld\n",
- smi->interrupts);
- out += sprintf(out, "attentions: %ld\n",
- smi->attentions);
- out += sprintf(out, "flag_fetches: %ld\n",
- smi->flag_fetches);
- out += sprintf(out, "hosed_count: %ld\n",
- smi->hosed_count);
- out += sprintf(out, "complete_transactions: %ld\n",
- smi->complete_transactions);
- out += sprintf(out, "events: %ld\n",
- smi->events);
- out += sprintf(out, "watchdog_pretimeouts: %ld\n",
- smi->watchdog_pretimeouts);
- out += sprintf(out, "incoming_messages: %ld\n",
- smi->incoming_messages);
+ out += sprintf(out, "short_timeouts: %u\n",
+ smi_get_stat(smi, short_timeouts));
+ out += sprintf(out, "long_timeouts: %u\n",
+ smi_get_stat(smi, long_timeouts));
+ out += sprintf(out, "idles: %u\n",
+ smi_get_stat(smi, idles));
+ out += sprintf(out, "interrupts: %u\n",
+ smi_get_stat(smi, interrupts));
+ out += sprintf(out, "attentions: %u\n",
+ smi_get_stat(smi, attentions));
+ out += sprintf(out, "flag_fetches: %u\n",
+ smi_get_stat(smi, flag_fetches));
+ out += sprintf(out, "hosed_count: %u\n",
+ smi_get_stat(smi, hosed_count));
+ out += sprintf(out, "complete_transactions: %u\n",
+ smi_get_stat(smi, complete_transactions));
+ out += sprintf(out, "events: %u\n",
+ smi_get_stat(smi, events));
+ out += sprintf(out, "watchdog_pretimeouts: %u\n",
+ smi_get_stat(smi, watchdog_pretimeouts));
+ out += sprintf(out, "incoming_messages: %u\n",
+ smi_get_stat(smi, incoming_messages));
return out - page;
}
@@ -2460,7 +2523,7 @@
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);
+ RECEIVE_MSG_AVAIL);
return 1;
}
@@ -2502,10 +2565,9 @@
id->ipmi_version == DELL_POWEREDGE_8G_BMC_IPMI_VERSION) {
smi_info->oem_data_avail_handler =
oem_data_avail_to_receive_msg_avail;
- }
- else if (ipmi_version_major(id) < 1 ||
- (ipmi_version_major(id) == 1 &&
- ipmi_version_minor(id) < 5)) {
+ } else if (ipmi_version_major(id) < 1 ||
+ (ipmi_version_major(id) == 1 &&
+ ipmi_version_minor(id) < 5)) {
smi_info->oem_data_avail_handler =
oem_data_avail_to_receive_msg_avail;
}
@@ -2597,8 +2659,10 @@
static inline void wait_for_timer_and_thread(struct smi_info *smi_info)
{
if (smi_info->intf) {
- /* The timer and thread are only running if the
- interface has been started up and registered. */
+ /*
+ * The timer and thread are only running if the
+ * interface has been started up and registered.
+ */
if (smi_info->thread != NULL)
kthread_stop(smi_info->thread);
del_timer_sync(&smi_info->si_timer);
@@ -2676,6 +2740,7 @@
static int try_smi_init(struct smi_info *new_smi)
{
int rv;
+ int i;
if (new_smi->addr_source) {
printk(KERN_INFO "ipmi_si: Trying %s-specified %s state"
@@ -2722,7 +2787,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) {
- printk(" Could not allocate state machine memory\n");
+ printk(KERN_ERR "Could not allocate state machine memory\n");
rv = -ENOMEM;
goto out_err;
}
@@ -2732,13 +2797,12 @@
/* Now that we know the I/O size, we can set up the I/O. */
rv = new_smi->io_setup(new_smi);
if (rv) {
- printk(" Could not set up I/O space\n");
+ printk(KERN_ERR "Could not set up I/O space\n");
goto out_err;
}
spin_lock_init(&(new_smi->si_lock));
spin_lock_init(&(new_smi->msg_lock));
- spin_lock_init(&(new_smi->count_lock));
/* Do low-level detection first. */
if (new_smi->handlers->detect(new_smi->si_sm)) {
@@ -2749,8 +2813,10 @@
goto out_err;
}
- /* Attempt a get device id command. If it fails, we probably
- don't have a BMC here. */
+ /*
+ * Attempt a get device id command. If it fails, we probably
+ * don't have a BMC here.
+ */
rv = try_get_dev_id(new_smi);
if (rv) {
if (new_smi->addr_source)
@@ -2767,22 +2833,28 @@
new_smi->curr_msg = NULL;
atomic_set(&new_smi->req_events, 0);
new_smi->run_to_completion = 0;
+ for (i = 0; i < SI_NUM_STATS; i++)
+ atomic_set(&new_smi->stats[i], 0);
new_smi->interrupt_disabled = 0;
atomic_set(&new_smi->stop_operation, 0);
new_smi->intf_num = smi_num;
smi_num++;
- /* Start clearing the flags before we enable interrupts or the
- timer to avoid racing with the timer. */
+ /*
+ * Start clearing the flags before we enable interrupts or the
+ * timer to avoid racing with the timer.
+ */
start_clear_flags(new_smi);
/* IRQ is defined to be set when non-zero. */
if (new_smi->irq)
new_smi->si_state = SI_CLEARING_FLAGS_THEN_SET_IRQ;
if (!new_smi->dev) {
- /* If we don't already have a device from something
- * else (like PCI), then register a new one. */
+ /*
+ * If we don't already have a device from something
+ * else (like PCI), then register a new one.
+ */
new_smi->pdev = platform_device_alloc("ipmi_si",
new_smi->intf_num);
if (rv) {
@@ -2820,7 +2892,7 @@
}
rv = ipmi_smi_add_proc_entry(new_smi->intf, "type",
- type_file_read_proc, NULL,
+ type_file_read_proc,
new_smi, THIS_MODULE);
if (rv) {
printk(KERN_ERR
@@ -2830,7 +2902,7 @@
}
rv = ipmi_smi_add_proc_entry(new_smi->intf, "si_stats",
- stat_file_read_proc, NULL,
+ stat_file_read_proc,
new_smi, THIS_MODULE);
if (rv) {
printk(KERN_ERR
@@ -2840,7 +2912,7 @@
}
rv = ipmi_smi_add_proc_entry(new_smi->intf, "params",
- param_read_proc, NULL,
+ param_read_proc,
new_smi, THIS_MODULE);
if (rv) {
printk(KERN_ERR
@@ -2853,7 +2925,8 @@
mutex_unlock(&smi_infos_lock);
- printk(KERN_INFO "IPMI %s interface initialized\n",si_to_str[new_smi->si_type]);
+ printk(KERN_INFO "IPMI %s interface initialized\n",
+ si_to_str[new_smi->si_type]);
return 0;
@@ -2868,9 +2941,11 @@
if (new_smi->irq_cleanup)
new_smi->irq_cleanup(new_smi);
- /* Wait until we know that we are out of any interrupt
- handlers might have been running before we freed the
- interrupt. */
+ /*
+ * Wait until we know that we are out of any interrupt
+ * handlers might have been running before we freed the
+ * interrupt.
+ */
synchronize_sched();
if (new_smi->si_sm) {
@@ -2942,11 +3017,10 @@
#ifdef CONFIG_PCI
rv = pci_register_driver(&ipmi_pci_driver);
- if (rv){
+ if (rv)
printk(KERN_ERR
"init_ipmi_si: Unable to register PCI driver: %d\n",
rv);
- }
#endif
#ifdef CONFIG_PPC_OF
@@ -2975,7 +3049,8 @@
of_unregister_platform_driver(&ipmi_of_platform_driver);
#endif
driver_unregister(&ipmi_driver);
- printk("ipmi_si: Unable to find any System Interface(s)\n");
+ printk(KERN_WARNING
+ "ipmi_si: Unable to find any System Interface(s)\n");
return -ENODEV;
} else {
mutex_unlock(&smi_infos_lock);
@@ -2997,13 +3072,17 @@
/* Tell the driver that we are shutting down. */
atomic_inc(&to_clean->stop_operation);
- /* Make sure the timer and thread are stopped and will not run
- again. */
+ /*
+ * Make sure the timer and thread are stopped and will not run
+ * again.
+ */
wait_for_timer_and_thread(to_clean);
- /* Timeouts are stopped, now make sure the interrupts are off
- for the device. A little tricky with locks to make sure
- there are no races. */
+ /*
+ * Timeouts are stopped, now make sure the interrupts are off
+ * for the device. A little tricky with locks to make sure
+ * there are no races.
+ */
spin_lock_irqsave(&to_clean->si_lock, flags);
while (to_clean->curr_msg || (to_clean->si_state != SI_NORMAL)) {
spin_unlock_irqrestore(&to_clean->si_lock, flags);
@@ -3074,4 +3153,5 @@
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.");
+MODULE_DESCRIPTION("Interface to the IPMI driver for the KCS, SMIC, and BT"
+ " system interfaces.");
diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h
index 4b731b2..df89f73 100644
--- a/drivers/char/ipmi/ipmi_si_sm.h
+++ b/drivers/char/ipmi/ipmi_si_sm.h
@@ -34,22 +34,27 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* This is defined by the state machines themselves, it is an opaque
- data type for them to use. */
+/*
+ * This is defined by the state machines themselves, it is an opaque
+ * data type for them to use.
+ */
struct si_sm_data;
-/* The structure for doing I/O in the state machine. The state
- machine doesn't have the actual I/O routines, they are done through
- this interface. */
-struct si_sm_io
-{
+/*
+ * The structure for doing I/O in the state machine. The state
+ * machine doesn't have the actual I/O routines, they are done through
+ * this interface.
+ */
+struct si_sm_io {
unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset);
void (*outputb)(struct si_sm_io *io,
unsigned int offset,
unsigned char b);
- /* Generic info used by the actual handling routines, the
- state machine shouldn't touch these. */
+ /*
+ * Generic info used by the actual handling routines, the
+ * state machine shouldn't touch these.
+ */
void __iomem *addr;
int regspacing;
int regsize;
@@ -59,53 +64,67 @@
};
/* Results of SMI events. */
-enum si_sm_result
-{
+enum si_sm_result {
SI_SM_CALL_WITHOUT_DELAY, /* Call the driver again immediately */
SI_SM_CALL_WITH_DELAY, /* Delay some before calling again. */
- SI_SM_CALL_WITH_TICK_DELAY, /* Delay at least 1 tick before calling again. */
+ SI_SM_CALL_WITH_TICK_DELAY,/* Delay >=1 tick before calling again. */
SI_SM_TRANSACTION_COMPLETE, /* A transaction is finished. */
SI_SM_IDLE, /* The SM is in idle state. */
SI_SM_HOSED, /* The hardware violated the state machine. */
- SI_SM_ATTN /* The hardware is asserting attn and the
- state machine is idle. */
+
+ /*
+ * The hardware is asserting attn and the state machine is
+ * idle.
+ */
+ SI_SM_ATTN
};
/* Handlers for the SMI state machine. */
-struct si_sm_handlers
-{
- /* Put the version number of the state machine here so the
- upper layer can print it. */
+struct si_sm_handlers {
+ /*
+ * Put the version number of the state machine here so the
+ * upper layer can print it.
+ */
char *version;
- /* Initialize the data and return the amount of I/O space to
- reserve for the space. */
+ /*
+ * Initialize the data and return the amount of I/O space to
+ * reserve for the space.
+ */
unsigned int (*init_data)(struct si_sm_data *smi,
struct si_sm_io *io);
- /* Start a new transaction in the state machine. This will
- return -2 if the state machine is not idle, -1 if the size
- is invalid (to large or too small), or 0 if the transaction
- is successfully completed. */
+ /*
+ * Start a new transaction in the state machine. This will
+ * return -2 if the state machine is not idle, -1 if the size
+ * is invalid (to large or too small), or 0 if the transaction
+ * is successfully completed.
+ */
int (*start_transaction)(struct si_sm_data *smi,
unsigned char *data, unsigned int size);
- /* Return the results after the transaction. This will return
- -1 if the buffer is too small, zero if no transaction is
- present, or the actual length of the result data. */
+ /*
+ * Return the results after the transaction. This will return
+ * -1 if the buffer is too small, zero if no transaction is
+ * present, or the actual length of the result data.
+ */
int (*get_result)(struct si_sm_data *smi,
unsigned char *data, unsigned int length);
- /* Call this periodically (for a polled interface) or upon
- receiving an interrupt (for a interrupt-driven interface).
- If interrupt driven, you should probably poll this
- periodically when not in idle state. This should be called
- with the time that passed since the last call, if it is
- significant. Time is in microseconds. */
+ /*
+ * Call this periodically (for a polled interface) or upon
+ * receiving an interrupt (for a interrupt-driven interface).
+ * If interrupt driven, you should probably poll this
+ * periodically when not in idle state. This should be called
+ * with the time that passed since the last call, if it is
+ * significant. Time is in microseconds.
+ */
enum si_sm_result (*event)(struct si_sm_data *smi, long time);
- /* Attempt to detect an SMI. Returns 0 on success or nonzero
- on failure. */
+ /*
+ * Attempt to detect an SMI. Returns 0 on success or nonzero
+ * on failure.
+ */
int (*detect)(struct si_sm_data *smi);
/* The interface is shutting down, so clean it up. */
diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c
index e64ea7d..faed929 100644
--- a/drivers/char/ipmi/ipmi_smic_sm.c
+++ b/drivers/char/ipmi/ipmi_smic_sm.c
@@ -85,6 +85,7 @@
/* SMIC Flags Register Bits */
#define SMIC_RX_DATA_READY 0x80
#define SMIC_TX_DATA_READY 0x40
+
/*
* SMIC_SMI and SMIC_EVM_DATA_AVAIL are only used by
* a few systems, and then only by Systems Management
@@ -104,23 +105,22 @@
#define EC_ILLEGAL_COMMAND 0x04
#define EC_BUFFER_FULL 0x05
-struct si_sm_data
-{
+struct si_sm_data {
enum smic_states state;
struct si_sm_io *io;
- unsigned char write_data[MAX_SMIC_WRITE_SIZE];
- int write_pos;
- int write_count;
- int orig_write_count;
- unsigned char read_data[MAX_SMIC_READ_SIZE];
- int read_pos;
- int truncated;
- unsigned int error_retries;
- long smic_timeout;
+ unsigned char write_data[MAX_SMIC_WRITE_SIZE];
+ int write_pos;
+ int write_count;
+ int orig_write_count;
+ unsigned char read_data[MAX_SMIC_READ_SIZE];
+ int read_pos;
+ int truncated;
+ unsigned int error_retries;
+ long smic_timeout;
};
-static unsigned int init_smic_data (struct si_sm_data *smic,
- struct si_sm_io *io)
+static unsigned int init_smic_data(struct si_sm_data *smic,
+ struct si_sm_io *io)
{
smic->state = SMIC_IDLE;
smic->io = io;
@@ -150,11 +150,10 @@
return IPMI_NOT_IN_MY_STATE_ERR;
if (smic_debug & SMIC_DEBUG_MSG) {
- printk(KERN_INFO "start_smic_transaction -");
- for (i = 0; i < size; i ++) {
- printk (" %02x", (unsigned char) (data [i]));
- }
- printk ("\n");
+ printk(KERN_DEBUG "start_smic_transaction -");
+ for (i = 0; i < size; i++)
+ printk(" %02x", (unsigned char) data[i]);
+ printk("\n");
}
smic->error_retries = 0;
memcpy(smic->write_data, data, size);
@@ -173,11 +172,10 @@
int i;
if (smic_debug & SMIC_DEBUG_MSG) {
- printk (KERN_INFO "smic_get result -");
- for (i = 0; i < smic->read_pos; i ++) {
- printk (" %02x", (smic->read_data [i]));
- }
- printk ("\n");
+ printk(KERN_DEBUG "smic_get result -");
+ for (i = 0; i < smic->read_pos; i++)
+ printk(" %02x", smic->read_data[i]);
+ printk("\n");
}
if (length < smic->read_pos) {
smic->read_pos = length;
@@ -223,8 +221,8 @@
smic->io->outputb(smic->io, 1, control);
}
-static inline void write_si_sm_data (struct si_sm_data *smic,
- unsigned char data)
+static inline void write_si_sm_data(struct si_sm_data *smic,
+ unsigned char data)
{
smic->io->outputb(smic->io, 0, data);
}
@@ -233,10 +231,9 @@
{
(smic->error_retries)++;
if (smic->error_retries > SMIC_MAX_ERROR_RETRIES) {
- if (smic_debug & SMIC_DEBUG_ENABLE) {
+ if (smic_debug & SMIC_DEBUG_ENABLE)
printk(KERN_WARNING
"ipmi_smic_drv: smic hosed: %s\n", reason);
- }
smic->state = SMIC_HOSED;
} else {
smic->write_count = smic->orig_write_count;
@@ -254,14 +251,14 @@
(smic->write_count)--;
}
-static inline void read_next_byte (struct si_sm_data *smic)
+static inline void read_next_byte(struct si_sm_data *smic)
{
if (smic->read_pos >= MAX_SMIC_READ_SIZE) {
- read_smic_data (smic);
+ read_smic_data(smic);
smic->truncated = 1;
} else {
smic->read_data[smic->read_pos] = read_smic_data(smic);
- (smic->read_pos)++;
+ smic->read_pos++;
}
}
@@ -336,7 +333,7 @@
SMIC_SC_SMS_RD_END 0xC6
*/
-static enum si_sm_result smic_event (struct si_sm_data *smic, long time)
+static enum si_sm_result smic_event(struct si_sm_data *smic, long time)
{
unsigned char status;
unsigned char flags;
@@ -347,13 +344,15 @@
return SI_SM_HOSED;
}
if (smic->state != SMIC_IDLE) {
- if (smic_debug & SMIC_DEBUG_STATES) {
- printk(KERN_INFO
+ if (smic_debug & SMIC_DEBUG_STATES)
+ printk(KERN_DEBUG
"smic_event - smic->smic_timeout = %ld,"
" time = %ld\n",
smic->smic_timeout, time);
- }
-/* FIXME: smic_event is sometimes called with time > SMIC_RETRY_TIMEOUT */
+ /*
+ * FIXME: smic_event is sometimes called with time >
+ * SMIC_RETRY_TIMEOUT
+ */
if (time < SMIC_RETRY_TIMEOUT) {
smic->smic_timeout -= time;
if (smic->smic_timeout < 0) {
@@ -366,9 +365,9 @@
if (flags & SMIC_FLAG_BSY)
return SI_SM_CALL_WITH_DELAY;
- status = read_smic_status (smic);
+ status = read_smic_status(smic);
if (smic_debug & SMIC_DEBUG_STATES)
- printk(KERN_INFO
+ printk(KERN_DEBUG
"smic_event - state = %d, flags = 0x%02x,"
" status = 0x%02x\n",
smic->state, flags, status);
@@ -377,9 +376,7 @@
case SMIC_IDLE:
/* in IDLE we check for available messages */
if (flags & SMIC_SMS_DATA_AVAIL)
- {
return SI_SM_ATTN;
- }
return SI_SM_IDLE;
case SMIC_START_OP:
@@ -391,7 +388,7 @@
case SMIC_OP_OK:
if (status != SMIC_SC_SMS_READY) {
- /* this should not happen */
+ /* this should not happen */
start_error_recovery(smic,
"state = SMIC_OP_OK,"
" status != SMIC_SC_SMS_READY");
@@ -411,8 +408,10 @@
"status != SMIC_SC_SMS_WR_START");
return SI_SM_CALL_WITH_DELAY;
}
- /* we must not issue WR_(NEXT|END) unless
- TX_DATA_READY is set */
+ /*
+ * we must not issue WR_(NEXT|END) unless
+ * TX_DATA_READY is set
+ * */
if (flags & SMIC_TX_DATA_READY) {
if (smic->write_count == 1) {
/* last byte */
@@ -424,10 +423,8 @@
}
write_next_byte(smic);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
- }
- else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
case SMIC_WRITE_NEXT:
@@ -442,52 +439,48 @@
if (smic->write_count == 1) {
write_smic_control(smic, SMIC_CC_SMS_WR_END);
smic->state = SMIC_WRITE_END;
- }
- else {
+ } else {
write_smic_control(smic, SMIC_CC_SMS_WR_NEXT);
smic->state = SMIC_WRITE_NEXT;
}
write_next_byte(smic);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
- }
- else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
case SMIC_WRITE_END:
if (status != SMIC_SC_SMS_WR_END) {
- start_error_recovery (smic,
- "state = SMIC_WRITE_END, "
- "status != SMIC_SC_SMS_WR_END");
+ start_error_recovery(smic,
+ "state = SMIC_WRITE_END, "
+ "status != SMIC_SC_SMS_WR_END");
return SI_SM_CALL_WITH_DELAY;
}
/* data register holds an error code */
data = read_smic_data(smic);
if (data != 0) {
- if (smic_debug & SMIC_DEBUG_ENABLE) {
- printk(KERN_INFO
+ if (smic_debug & SMIC_DEBUG_ENABLE)
+ printk(KERN_DEBUG
"SMIC_WRITE_END: data = %02x\n", data);
- }
start_error_recovery(smic,
"state = SMIC_WRITE_END, "
"data != SUCCESS");
return SI_SM_CALL_WITH_DELAY;
- } else {
+ } else
smic->state = SMIC_WRITE2READ;
- }
break;
case SMIC_WRITE2READ:
- /* we must wait for RX_DATA_READY to be set before we
- can continue */
+ /*
+ * we must wait for RX_DATA_READY to be set before we
+ * can continue
+ */
if (flags & SMIC_RX_DATA_READY) {
write_smic_control(smic, SMIC_CC_SMS_RD_START);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_START;
- } else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
case SMIC_READ_START:
@@ -502,15 +495,16 @@
write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_NEXT;
- } else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
case SMIC_READ_NEXT:
switch (status) {
- /* smic tells us that this is the last byte to be read
- --> clean up */
+ /*
+ * smic tells us that this is the last byte to be read
+ * --> clean up
+ */
case SMIC_SC_SMS_RD_END:
read_next_byte(smic);
write_smic_control(smic, SMIC_CC_SMS_RD_END);
@@ -523,9 +517,8 @@
write_smic_control(smic, SMIC_CC_SMS_RD_NEXT);
write_smic_flags(smic, flags | SMIC_FLAG_BSY);
smic->state = SMIC_READ_NEXT;
- } else {
+ } else
return SI_SM_CALL_WITH_DELAY;
- }
break;
default:
start_error_recovery(
@@ -546,10 +539,9 @@
data = read_smic_data(smic);
/* data register holds an error code */
if (data != 0) {
- if (smic_debug & SMIC_DEBUG_ENABLE) {
- printk(KERN_INFO
+ if (smic_debug & SMIC_DEBUG_ENABLE)
+ printk(KERN_DEBUG
"SMIC_READ_END: data = %02x\n", data);
- }
start_error_recovery(smic,
"state = SMIC_READ_END, "
"data != SUCCESS");
@@ -565,7 +557,7 @@
default:
if (smic_debug & SMIC_DEBUG_ENABLE) {
- printk(KERN_WARNING "smic->state = %d\n", smic->state);
+ printk(KERN_DEBUG "smic->state = %d\n", smic->state);
start_error_recovery(smic, "state = UNKNOWN");
return SI_SM_CALL_WITH_DELAY;
}
@@ -576,10 +568,12 @@
static int smic_detect(struct si_sm_data *smic)
{
- /* It's impossible for the SMIC fnags register to be all 1's,
- (assuming a properly functioning, self-initialized BMC)
- but that's what you get from reading a bogus address, so we
- test that first. */
+ /*
+ * It's impossible for the SMIC fnags register to be all 1's,
+ * (assuming a properly functioning, self-initialized BMC)
+ * but that's what you get from reading a bogus address, so we
+ * test that first.
+ */
if (read_smic_flags(smic) == 0xff)
return 1;
@@ -595,8 +589,7 @@
return sizeof(struct si_sm_data);
}
-struct si_sm_handlers smic_smi_handlers =
-{
+struct si_sm_handlers smic_smi_handlers = {
.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 8f45ca9..1b9a870 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -54,13 +54,15 @@
#include <asm/atomic.h>
#ifdef CONFIG_X86
-/* This is ugly, but I've determined that x86 is the only architecture
- that can reasonably support the IPMI NMI watchdog timeout at this
- time. If another architecture adds this capability somehow, it
- will have to be a somewhat different mechanism and I have no idea
- how it will work. So in the unlikely event that another
- architecture supports this, we can figure out a good generic
- mechanism for it at that time. */
+/*
+ * This is ugly, but I've determined that x86 is the only architecture
+ * that can reasonably support the IPMI NMI watchdog timeout at this
+ * time. If another architecture adds this capability somehow, it
+ * will have to be a somewhat different mechanism and I have no idea
+ * how it will work. So in the unlikely event that another
+ * architecture supports this, we can figure out a good generic
+ * mechanism for it at that time.
+ */
#include <asm/kdebug.h>
#define HAVE_DIE_NMI
#endif
@@ -95,9 +97,8 @@
/* Operations that can be performed on a pretimout. */
#define WDOG_PREOP_NONE 0
#define WDOG_PREOP_PANIC 1
-#define WDOG_PREOP_GIVE_DATA 2 /* Cause data to be available to
- read. Doesn't work in NMI
- mode. */
+/* Cause data to be available to read. Doesn't work in NMI mode. */
+#define WDOG_PREOP_GIVE_DATA 2
/* Actions to perform on a full timeout. */
#define WDOG_SET_TIMEOUT_ACT(byte, use) \
@@ -108,8 +109,10 @@
#define WDOG_TIMEOUT_POWER_DOWN 2
#define WDOG_TIMEOUT_POWER_CYCLE 3
-/* Byte 3 of the get command, byte 4 of the get response is the
- pre-timeout in seconds. */
+/*
+ * Byte 3 of the get command, byte 4 of the get response is the
+ * pre-timeout in seconds.
+ */
/* Bits for setting byte 4 of the set command, byte 5 of the get response. */
#define WDOG_EXPIRE_CLEAR_BIOS_FRB2 (1 << 1)
@@ -118,11 +121,13 @@
#define WDOG_EXPIRE_CLEAR_SMS_OS (1 << 4)
#define WDOG_EXPIRE_CLEAR_OEM (1 << 5)
-/* Setting/getting the watchdog timer value. This is for bytes 5 and
- 6 (the timeout time) of the set command, and bytes 6 and 7 (the
- timeout time) and 8 and 9 (the current countdown value) of the
- response. The timeout value is given in seconds (in the command it
- is 100ms intervals). */
+/*
+ * Setting/getting the watchdog timer value. This is for bytes 5 and
+ * 6 (the timeout time) of the set command, and bytes 6 and 7 (the
+ * timeout time) and 8 and 9 (the current countdown value) of the
+ * response. The timeout value is given in seconds (in the command it
+ * is 100ms intervals).
+ */
#define WDOG_SET_TIMEOUT(byte1, byte2, val) \
(byte1) = (((val) * 10) & 0xff), (byte2) = (((val) * 10) >> 8)
#define WDOG_GET_TIMEOUT(byte1, byte2) \
@@ -184,8 +189,10 @@
static void ipmi_register_watchdog(int ipmi_intf);
static void ipmi_unregister_watchdog(int ipmi_intf);
-/* If true, the driver will start running as soon as it is configured
- and ready. */
+/*
+ * If true, the driver will start running as soon as it is configured
+ * and ready.
+ */
static int start_now;
static int set_param_int(const char *val, struct kernel_param *kp)
@@ -309,10 +316,12 @@
/* Is someone using the watchdog? Only one user is allowed. */
static unsigned long ipmi_wdog_open;
-/* If set to 1, the heartbeat command will set the state to reset and
- start the timer. The timer doesn't normally run when the driver is
- first opened until the heartbeat is set the first time, this
- variable is used to accomplish this. */
+/*
+ * If set to 1, the heartbeat command will set the state to reset and
+ * start the timer. The timer doesn't normally run when the driver is
+ * first opened until the heartbeat is set the first time, this
+ * variable is used to accomplish this.
+ */
static int ipmi_start_timer_on_heartbeat;
/* IPMI version of the BMC. */
@@ -329,10 +338,12 @@
static int ipmi_heartbeat(void);
-/* We use a mutex to make sure that only one thing can send a set
- timeout at one time, because we only have one copy of the data.
- The mutex is claimed when the set_timeout is sent and freed
- when both messages are free. */
+/*
+ * We use a mutex to make sure that only one thing can send a set
+ * timeout at one time, because we only have one copy of the data.
+ * The mutex is claimed when the set_timeout is sent and freed
+ * when both messages are free.
+ */
static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
static DEFINE_MUTEX(set_timeout_lock);
static DECLARE_COMPLETION(set_timeout_wait);
@@ -346,15 +357,13 @@
if (atomic_dec_and_test(&set_timeout_tofree))
complete(&set_timeout_wait);
}
-static struct ipmi_smi_msg set_timeout_smi_msg =
-{
+static struct ipmi_smi_msg set_timeout_smi_msg = {
.done = set_timeout_free_smi
};
-static struct ipmi_recv_msg set_timeout_recv_msg =
-{
+static struct ipmi_recv_msg set_timeout_recv_msg = {
.done = set_timeout_free_recv
};
-
+
static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
struct ipmi_recv_msg *recv_msg,
int *send_heartbeat_now)
@@ -373,13 +382,14 @@
WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
if ((ipmi_version_major > 1)
- || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5)))
- {
+ || ((ipmi_version_major == 1) && (ipmi_version_minor >= 5))) {
/* This is an IPMI 1.5-only feature. */
data[0] |= WDOG_DONT_STOP_ON_SET;
} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
- /* In ipmi 1.0, setting the timer stops the watchdog, we
- need to start it back up again. */
+ /*
+ * In ipmi 1.0, setting the timer stops the watchdog, we
+ * need to start it back up again.
+ */
hbnow = 1;
}
@@ -465,12 +475,10 @@
atomic_dec(&panic_done_count);
}
-static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg =
-{
+static struct ipmi_smi_msg panic_halt_heartbeat_smi_msg = {
.done = panic_smi_free
};
-static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg =
-{
+static struct ipmi_recv_msg panic_halt_heartbeat_recv_msg = {
.done = panic_recv_free
};
@@ -480,8 +488,10 @@
struct ipmi_system_interface_addr addr;
int rv;
- /* Don't reset the timer if we have the timer turned off, that
- re-enables the watchdog. */
+ /*
+ * Don't reset the timer if we have the timer turned off, that
+ * re-enables the watchdog.
+ */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
return;
@@ -505,19 +515,19 @@
atomic_add(2, &panic_done_count);
}
-static struct ipmi_smi_msg panic_halt_smi_msg =
-{
+static struct ipmi_smi_msg panic_halt_smi_msg = {
.done = panic_smi_free
};
-static struct ipmi_recv_msg panic_halt_recv_msg =
-{
+static struct ipmi_recv_msg panic_halt_recv_msg = {
.done = panic_recv_free
};
-/* Special call, doesn't claim any locks. This is only to be called
- at panic or halt time, in run-to-completion mode, when the caller
- is the only CPU and the only thing that will be going is these IPMI
- calls. */
+/*
+ * Special call, doesn't claim any locks. This is only to be called
+ * at panic or halt time, in run-to-completion mode, when the caller
+ * is the only CPU and the only thing that will be going is these IPMI
+ * calls.
+ */
static void panic_halt_ipmi_set_timeout(void)
{
int send_heartbeat_now;
@@ -540,10 +550,12 @@
ipmi_poll_interface(watchdog_user);
}
-/* We use a semaphore to make sure that only one thing can send a
- heartbeat at one time, because we only have one copy of the data.
- The semaphore is claimed when the set_timeout is sent and freed
- when both messages are free. */
+/*
+ * We use a mutex to make sure that only one thing can send a
+ * heartbeat at one time, because we only have one copy of the data.
+ * The semaphore is claimed when the set_timeout is sent and freed
+ * when both messages are free.
+ */
static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
static DEFINE_MUTEX(heartbeat_lock);
static DECLARE_COMPLETION(heartbeat_wait);
@@ -557,15 +569,13 @@
if (atomic_dec_and_test(&heartbeat_tofree))
complete(&heartbeat_wait);
}
-static struct ipmi_smi_msg heartbeat_smi_msg =
-{
+static struct ipmi_smi_msg heartbeat_smi_msg = {
.done = heartbeat_free_smi
};
-static struct ipmi_recv_msg heartbeat_recv_msg =
-{
+static struct ipmi_recv_msg heartbeat_recv_msg = {
.done = heartbeat_free_recv
};
-
+
static int ipmi_heartbeat(void)
{
struct kernel_ipmi_msg msg;
@@ -580,10 +590,12 @@
ipmi_watchdog_state = action_val;
return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
} else if (pretimeout_since_last_heartbeat) {
- /* A pretimeout occurred, make sure we set the timeout.
- We don't want to set the action, though, we want to
- leave that alone (thus it can't be combined with the
- above operation. */
+ /*
+ * A pretimeout occurred, make sure we set the timeout.
+ * We don't want to set the action, though, we want to
+ * leave that alone (thus it can't be combined with the
+ * above operation.
+ */
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
}
@@ -591,8 +603,10 @@
atomic_set(&heartbeat_tofree, 2);
- /* Don't reset the timer if we have the timer turned off, that
- re-enables the watchdog. */
+ /*
+ * Don't reset the timer if we have the timer turned off, that
+ * re-enables the watchdog.
+ */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
mutex_unlock(&heartbeat_lock);
return 0;
@@ -625,10 +639,12 @@
wait_for_completion(&heartbeat_wait);
if (heartbeat_recv_msg.msg.data[0] != 0) {
- /* Got an error in the heartbeat response. It was already
- reported in ipmi_wdog_msg_handler, but we should return
- an error here. */
- rv = -EINVAL;
+ /*
+ * Got an error in the heartbeat response. It was already
+ * reported in ipmi_wdog_msg_handler, but we should return
+ * an error here.
+ */
+ rv = -EINVAL;
}
mutex_unlock(&heartbeat_lock);
@@ -636,8 +652,7 @@
return rv;
}
-static struct watchdog_info ident =
-{
+static struct watchdog_info ident = {
.options = 0, /* WDIOF_SETTIMEOUT, */
.firmware_version = 1,
.identity = "IPMI"
@@ -650,7 +665,7 @@
int i;
int val;
- switch(cmd) {
+ switch (cmd) {
case WDIOC_GETSUPPORT:
i = copy_to_user(argp, &ident, sizeof(ident));
return i ? -EFAULT : 0;
@@ -690,15 +705,13 @@
i = copy_from_user(&val, argp, sizeof(int));
if (i)
return -EFAULT;
- if (val & WDIOS_DISABLECARD)
- {
+ if (val & WDIOS_DISABLECARD) {
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
ipmi_start_timer_on_heartbeat = 0;
}
- if (val & WDIOS_ENABLECARD)
- {
+ if (val & WDIOS_ENABLECARD) {
ipmi_watchdog_state = action_val;
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
}
@@ -724,13 +737,13 @@
int rv;
if (len) {
- if (!nowayout) {
- size_t i;
+ if (!nowayout) {
+ size_t i;
/* In case it was set long ago */
expect_close = 0;
- for (i = 0; i != len; i++) {
+ for (i = 0; i != len; i++) {
char c;
if (get_user(c, buf + i))
@@ -758,15 +771,17 @@
if (count <= 0)
return 0;
- /* Reading returns if the pretimeout has gone off, and it only does
- it once per pretimeout. */
+ /*
+ * Reading returns if the pretimeout has gone off, and it only does
+ * it once per pretimeout.
+ */
spin_lock(&ipmi_read_lock);
if (!data_to_read) {
if (file->f_flags & O_NONBLOCK) {
rv = -EAGAIN;
goto out;
}
-
+
init_waitqueue_entry(&wait, current);
add_wait_queue(&read_q, &wait);
while (!data_to_read) {
@@ -776,7 +791,7 @@
spin_lock(&ipmi_read_lock);
}
remove_wait_queue(&read_q, &wait);
-
+
if (signal_pending(current)) {
rv = -ERESTARTSYS;
goto out;
@@ -799,25 +814,27 @@
static int ipmi_open(struct inode *ino, struct file *filep)
{
- switch (iminor(ino)) {
- case WATCHDOG_MINOR:
+ switch (iminor(ino)) {
+ case WATCHDOG_MINOR:
if (test_and_set_bit(0, &ipmi_wdog_open))
- return -EBUSY;
+ return -EBUSY;
- /* Don't start the timer now, let it start on the
- first heartbeat. */
+ /*
+ * 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);
- }
+ }
}
static unsigned int ipmi_poll(struct file *file, poll_table *wait)
{
unsigned int mask = 0;
-
+
poll_wait(file, &read_q, wait);
spin_lock(&ipmi_read_lock);
@@ -851,7 +868,7 @@
clear_bit(0, &ipmi_wdog_open);
}
- ipmi_fasync (-1, filep, 0);
+ ipmi_fasync(-1, filep, 0);
expect_close = 0;
return 0;
@@ -882,7 +899,7 @@
msg->msg.data[0],
msg->msg.cmd);
}
-
+
ipmi_free_recv_msg(msg);
}
@@ -902,14 +919,14 @@
}
}
- /* On some machines, the heartbeat will give
- an error and not work unless we re-enable
- the timer. So do so. */
+ /*
+ * 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;
}
-static struct ipmi_user_hndl ipmi_hndlrs =
-{
+static struct ipmi_user_hndl ipmi_hndlrs = {
.ipmi_recv_hndl = ipmi_wdog_msg_handler,
.ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler
};
@@ -949,8 +966,10 @@
int old_timeout = timeout;
int old_preop_val = preop_val;
- /* Set the pretimeout to go off in a second and give
- ourselves plenty of time to stop the timer. */
+ /*
+ * Set the pretimeout to go off in a second and give
+ * ourselves plenty of time to stop the timer.
+ */
ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */
pretimeout = 99;
@@ -974,7 +993,7 @@
" occur. The NMI pretimeout will"
" likely not work\n");
}
- out_restore:
+ out_restore:
testing_nmi = 0;
preop_val = old_preop_val;
pretimeout = old_pretimeout;
@@ -1009,9 +1028,11 @@
/* Make sure no one can call us any more. */
misc_deregister(&ipmi_wdog_miscdev);
- /* Wait to make sure the message makes it out. The lower layer has
- pointers to our buffers, we want to make sure they are done before
- we release our memory. */
+ /*
+ * Wait to make sure the message makes it out. The lower layer has
+ * pointers to our buffers, we want to make sure they are done before
+ * we release our memory.
+ */
while (atomic_read(&set_timeout_tofree))
schedule_timeout_uninterruptible(1);
@@ -1052,15 +1073,17 @@
return NOTIFY_STOP;
}
- /* If we are not expecting a timeout, ignore it. */
+ /* If we are not expecting a timeout, ignore it. */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
return NOTIFY_OK;
if (preaction_val != WDOG_PRETIMEOUT_NMI)
return NOTIFY_OK;
- /* If no one else handled the NMI, we assume it was the IPMI
- watchdog. */
+ /*
+ * If no one else handled the NMI, we assume it was the IPMI
+ * watchdog.
+ */
if (preop_val == WDOG_PREOP_PANIC) {
/* On some machines, the heartbeat will give
an error and not work unless we re-enable
@@ -1082,7 +1105,7 @@
unsigned long code,
void *unused)
{
- static int reboot_event_handled = 0;
+ static int reboot_event_handled;
if ((watchdog_user) && (!reboot_event_handled)) {
/* Make sure we only do this once. */
@@ -1115,7 +1138,7 @@
unsigned long event,
void *unused)
{
- static int panic_event_handled = 0;
+ static int panic_event_handled;
/* On a panic, if we have a panic timeout, make sure to extend
the watchdog timer to a reasonable value to complete the
@@ -1125,7 +1148,7 @@
ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {
/* Make sure we do this only once. */
panic_event_handled = 1;
-
+
timeout = 255;
pretimeout = 0;
panic_halt_ipmi_set_timeout();
@@ -1151,8 +1174,7 @@
ipmi_unregister_watchdog(if_num);
}
-static struct ipmi_smi_watcher smi_watcher =
-{
+static struct ipmi_smi_watcher smi_watcher = {
.owner = THIS_MODULE,
.new_smi = ipmi_new_smi,
.smi_gone = ipmi_smi_gone
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index eba2883..4f3cefa 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -126,8 +126,8 @@
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
#include <asm/system.h>
#include <linux/pci.h>
@@ -189,7 +189,7 @@
unsigned short status;
unsigned short port_status; /* each bit for each port */
unsigned short shift_count;
- struct isi_port * ports;
+ struct isi_port *ports;
signed char count;
spinlock_t card_lock; /* Card wide lock 11/5/00 -sameer */
unsigned long flags;
@@ -205,11 +205,11 @@
u16 channel;
u16 status;
u16 closing_wait;
- struct isi_board * card;
- struct tty_struct * tty;
+ struct isi_board *card;
+ struct tty_struct *tty;
wait_queue_head_t close_wait;
wait_queue_head_t open_wait;
- unsigned char * xmit_buf;
+ unsigned char *xmit_buf;
int xmit_head;
int xmit_tail;
int xmit_cnt;
@@ -405,7 +405,7 @@
/* find next active board */
card = (prev_card + 1) & 0x0003;
- while(count-- > 0) {
+ while (count-- > 0) {
if (isi_card[card].status & BOARD_ACTIVE)
break;
card = (card + 1) & 0x0003;
@@ -428,7 +428,7 @@
if (retries >= 100)
goto unlock;
- for (;count > 0;count--, port++) {
+ for (; count > 0; count--, port++) {
/* port not active or tx disabled to force flow control */
if (!(port->flags & ASYNC_INITIALIZED) ||
!(port->status & ISI_TXOK))
@@ -471,9 +471,10 @@
break;
}
}
- if (cnt <= 0) break;
+ if (cnt <= 0)
+ break;
word_count = cnt >> 1;
- outsw(base, port->xmit_buf+port->xmit_tail,word_count);
+ outsw(base, port->xmit_buf+port->xmit_tail, word_count);
port->xmit_tail = (port->xmit_tail
+ (word_count << 1)) & (SERIAL_XMIT_SIZE - 1);
txcount -= (word_count << 1);
@@ -556,7 +557,7 @@
tty = port->tty;
if (tty == NULL) {
word_count = byte_count >> 1;
- while(byte_count > 1) {
+ while (byte_count > 1) {
inw(base);
byte_count -= 2;
}
@@ -569,7 +570,7 @@
if (header & 0x8000) { /* Status Packet */
header = inw(base);
- switch(header & 0xff) {
+ switch (header & 0xff) {
case 0: /* Change in EIA signals */
if (port->flags & ASYNC_CHECK_CD) {
if (port->status & ISI_DCD) {
@@ -656,7 +657,8 @@
if (byte_count > 0) {
pr_dbg("Intr(0x%lx:%d): Flip buffer overflow! dropping "
"bytes...\n", base, channel + 1);
- while(byte_count > 0) { /* drain out unread xtra data */
+ /* drain out unread xtra data */
+ while (byte_count > 0) {
inw(base);
byte_count -= 2;
}
@@ -679,8 +681,11 @@
shift_count = card->shift_count;
unsigned char flow_ctrl;
- if (!(tty = port->tty) || !tty->termios)
+ tty = port->tty;
+
+ if (tty == NULL)
return;
+ /* FIXME: Switch to new tty baud API */
baud = C_BAUD(tty);
if (baud & CBAUDEX) {
baud &= ~CBAUDEX;
@@ -706,7 +711,7 @@
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
baud++; /* 57.6 Kbps */
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- baud +=2; /* 115 Kbps */
+ baud += 2; /* 115 Kbps */
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI)
baud += 3; /* 230 kbps*/
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
@@ -716,15 +721,14 @@
/* hang up */
drop_dtr(port);
return;
- }
- else
+ } else
raise_dtr(port);
if (WaitTillCardIsFree(base) == 0) {
- outw(0x8000 | (channel << shift_count) |0x03, base);
+ outw(0x8000 | (channel << shift_count) | 0x03, base);
outw(linuxb_to_isib[baud] << 8 | 0x03, base);
channel_setup = 0;
- switch(C_CSIZE(tty)) {
+ switch (C_CSIZE(tty)) {
case CS5:
channel_setup |= ISICOM_CS5;
break;
@@ -767,7 +771,7 @@
flow_ctrl |= ISICOM_INITIATE_XONXOFF;
if (WaitTillCardIsFree(base) == 0) {
- outw(0x8000 | (channel << shift_count) |0x04, base);
+ outw(0x8000 | (channel << shift_count) | 0x04, base);
outw(flow_ctrl << 8 | 0x05, base);
outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);
InterruptTheCard(base);
@@ -805,20 +809,17 @@
struct isi_board *card = port->card;
unsigned long flags;
- if (port->flags & ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED)
return 0;
- }
if (!port->xmit_buf) {
- unsigned long page;
-
- if (!(page = get_zeroed_page(GFP_KERNEL)))
+ /* Relies on BKL */
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ if (page == 0)
return -ENOMEM;
-
- if (port->xmit_buf) {
+ if (port->xmit_buf)
free_page(page);
- return -ERESTARTSYS;
- }
- port->xmit_buf = (unsigned char *) page;
+ else
+ port->xmit_buf = (unsigned char *) page;
}
spin_lock_irqsave(&card->card_lock, flags);
@@ -949,21 +950,18 @@
port->count++;
tty->driver_data = port;
port->tty = tty;
- if ((error = isicom_setup_port(port))!=0)
- return error;
- if ((error = block_til_ready(tty, filp, port))!=0)
- return error;
-
- return 0;
+ error = isicom_setup_port(port);
+ if (error == 0)
+ error = block_til_ready(tty, filp, port);
+ return error;
}
/* close et all */
static inline void isicom_shutdown_board(struct isi_board *bp)
{
- if (bp->status & BOARD_ACTIVE) {
+ if (bp->status & BOARD_ACTIVE)
bp->status &= ~BOARD_ACTIVE;
- }
}
/* card->lock HAS to be held */
@@ -1012,6 +1010,22 @@
}
}
+static void isicom_flush_buffer(struct tty_struct *tty)
+{
+ struct isi_port *port = tty->driver_data;
+ struct isi_board *card = port->card;
+ unsigned long flags;
+
+ if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
+ return;
+
+ spin_lock_irqsave(&card->card_lock, flags);
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ spin_unlock_irqrestore(&card->card_lock, flags);
+
+ tty_wakeup(tty);
+}
+
static void isicom_close(struct tty_struct *tty, struct file *filp)
{
struct isi_port *port = tty->driver_data;
@@ -1065,8 +1079,7 @@
isicom_shutdown_port(port);
spin_unlock_irqrestore(&card->card_lock, flags);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ isicom_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&card->card_lock, flags);
@@ -1104,7 +1117,7 @@
spin_lock_irqsave(&card->card_lock, flags);
- while(1) {
+ while (1) {
cnt = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt
- 1, SERIAL_XMIT_SIZE - port->xmit_head));
if (cnt <= 0)
@@ -1125,28 +1138,29 @@
}
/* put_char et all */
-static void isicom_put_char(struct tty_struct *tty, unsigned char ch)
+static int isicom_put_char(struct tty_struct *tty, unsigned char ch)
{
struct isi_port *port = tty->driver_data;
struct isi_board *card = port->card;
unsigned long flags;
if (isicom_paranoia_check(port, tty->name, "isicom_put_char"))
- return;
+ return 0;
if (!port->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&card->card_lock, flags);
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
spin_unlock_irqrestore(&card->card_lock, flags);
- return;
+ return 0;
}
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= (SERIAL_XMIT_SIZE - 1);
port->xmit_cnt++;
spin_unlock_irqrestore(&card->card_lock, flags);
+ return 1;
}
/* flush_chars et all */
@@ -1258,6 +1272,8 @@
if (copy_from_user(&newinfo, info, sizeof(newinfo)))
return -EFAULT;
+ lock_kernel();
+
reconfig_port = ((port->flags & ASYNC_SPD_MASK) !=
(newinfo.flags & ASYNC_SPD_MASK));
@@ -1265,12 +1281,13 @@
if ((newinfo.close_delay != port->close_delay) ||
(newinfo.closing_wait != port->closing_wait) ||
((newinfo.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
+ (port->flags & ~ASYNC_USR_MASK))) {
+ unlock_kernel();
return -EPERM;
- port->flags = ((port->flags & ~ ASYNC_USR_MASK) |
+ }
+ port->flags = ((port->flags & ~ASYNC_USR_MASK) |
(newinfo.flags & ASYNC_USR_MASK));
- }
- else {
+ } else {
port->close_delay = newinfo.close_delay;
port->closing_wait = newinfo.closing_wait;
port->flags = ((port->flags & ~ASYNC_FLAGS) |
@@ -1282,6 +1299,7 @@
isicom_config_port(port);
spin_unlock_irqrestore(&port->card->card_lock, flags);
}
+ unlock_kernel();
return 0;
}
@@ -1290,6 +1308,7 @@
{
struct serial_struct out_info;
+ lock_kernel();
memset(&out_info, 0, sizeof(out_info));
/* out_info.type = ? */
out_info.line = port - isi_ports;
@@ -1299,6 +1318,7 @@
/* out_info.baud_base = ? */
out_info.close_delay = port->close_delay;
out_info.closing_wait = port->closing_wait;
+ unlock_kernel();
if (copy_to_user(info, &out_info, sizeof(out_info)))
return -EFAULT;
return 0;
@@ -1314,7 +1334,7 @@
if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))
return -ENODEV;
- switch(cmd) {
+ switch (cmd) {
case TCSBRK:
retval = tty_check_change(tty);
if (retval)
@@ -1331,19 +1351,6 @@
tty_wait_until_sent(tty, 0);
isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);
return 0;
-
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long __user *)argp);
-
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *) argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
-
case TIOCGSERIAL:
return isicom_get_serial_info(port, argp);
@@ -1453,22 +1460,6 @@
wake_up_interruptible(&port->open_wait);
}
-/* flush_buffer et all */
-static void isicom_flush_buffer(struct tty_struct *tty)
-{
- struct isi_port *port = tty->driver_data;
- struct isi_board *card = port->card;
- unsigned long flags;
-
- if (isicom_paranoia_check(port, tty->name, "isicom_flush_buffer"))
- return;
-
- spin_lock_irqsave(&card->card_lock, flags);
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- spin_unlock_irqrestore(&card->card_lock, flags);
-
- tty_wakeup(tty);
-}
/*
* Driver init and deinit functions
@@ -1592,7 +1583,7 @@
default:
dev_err(&pdev->dev, "Unknown signature.\n");
goto end;
- }
+ }
retval = request_firmware(&fw, name, &pdev->dev);
if (retval)
@@ -1620,7 +1611,8 @@
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_warn(&pdev->dev, "Card%d rejected load header:\n"
KERN_WARNING "Address:0x%x\n"
KERN_WARNING "Count:0x%x\n"
@@ -1637,12 +1629,13 @@
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_err(&pdev->dev, "Card%d got out of sync.Card "
"Status:0x%x\n", index + 1, status);
goto errrelfw;
}
- }
+ }
/* XXX: should we test it by reading it back and comparing with original like
* in load firmware package? */
@@ -1666,7 +1659,8 @@
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
KERN_WARNING "Address:0x%x\n"
KERN_WARNING "Count:0x%x\n"
@@ -1699,7 +1693,8 @@
if (WaitTillCardIsFree(base))
goto errrelfw;
- if ((status = inw(base + 0x4)) != 0) {
+ status = inw(base + 0x4);
+ if (status != 0) {
dev_err(&pdev->dev, "Card%d verify got out of sync. "
"Card Status:0x%x\n", index + 1, status);
goto errrelfw;
@@ -1764,7 +1759,7 @@
index + 1);
retval = -EBUSY;
goto errdec;
- }
+ }
retval = request_irq(board->irq, isicom_interrupt,
IRQF_SHARED | IRQF_DISABLED, ISICOM_NAME, board);
@@ -1818,7 +1813,7 @@
int retval, idx, channel;
struct isi_port *port;
- for(idx = 0; idx < BOARD_COUNT; idx++) {
+ for (idx = 0; idx < BOARD_COUNT; idx++) {
port = &isi_ports[idx * 16];
isi_card[idx].ports = port;
spin_lock_init(&isi_card[idx].card_lock);
@@ -1832,7 +1827,7 @@
init_waitqueue_head(&port->open_wait);
init_waitqueue_head(&port->close_wait);
/* . . . */
- }
+ }
isi_card[idx].base = 0;
isi_card[idx].irq = 0;
}
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index c645455..7c8b62f 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -1682,16 +1682,6 @@
rc = 0;
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *) arg);
- break;
- case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned __user *) arg)) == 0)
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- break;
case TIOCGSERIAL:
rc = stli_getserial(portp, argp);
break;
@@ -3267,7 +3257,7 @@
*/
EBRDINIT(brdp);
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL) {
retval = -ENOMEM;
goto err_reg;
@@ -3424,7 +3414,7 @@
*/
EBRDINIT(brdp);
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL) {
retval = -ENOMEM;
goto err_reg;
@@ -3675,7 +3665,7 @@
*/
for (i = 0; (i < stli_eisamempsize); i++) {
brdp->memaddr = stli_eisamemprobeaddrs[i];
- brdp->membase = ioremap(brdp->memaddr, brdp->memsize);
+ brdp->membase = ioremap_nocache(brdp->memaddr, brdp->memsize);
if (brdp->membase == NULL)
continue;
@@ -4433,6 +4423,8 @@
done = 0;
rc = 0;
+ lock_kernel();
+
switch (cmd) {
case COM_GETPORTSTATS:
rc = stli_getportstats(NULL, argp);
@@ -4455,6 +4447,7 @@
done++;
break;
}
+ unlock_kernel();
if (done)
return rc;
@@ -4472,6 +4465,8 @@
if (brdp->state == 0)
return -ENODEV;
+ lock_kernel();
+
switch (cmd) {
case STL_BINTR:
EBRDINTR(brdp);
@@ -4494,6 +4489,7 @@
rc = -ENOIOCTLCMD;
break;
}
+ unlock_kernel();
return rc;
}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 60b934a..7f7e798 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -110,6 +110,7 @@
const int NR_TYPES = ARRAY_SIZE(max_vals);
struct kbd_struct kbd_table[MAX_NR_CONSOLES];
+EXPORT_SYMBOL_GPL(kbd_table);
static struct kbd_struct *kbd = kbd_table;
struct vt_spawn_console vt_spawn_con = {
@@ -260,6 +261,7 @@
} else
kd_nosound(0);
}
+EXPORT_SYMBOL(kd_mksound);
/*
* Setting the keyboard rate.
@@ -1230,7 +1232,7 @@
if (rep &&
(!vc_kbd_mode(kbd, VC_REPEAT) ||
- (tty && !L_ECHO(tty) && tty->driver->chars_in_buffer(tty)))) {
+ (tty && !L_ECHO(tty) && tty_chars_in_buffer(tty)))) {
/*
* Don't repeat a key if the input buffers are not empty and the
* characters get aren't echoed locally. This makes key repeat
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e83623e..934ffaf 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -364,6 +364,7 @@
return 0;
}
+#ifdef CONFIG_DEVKMEM
static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
{
unsigned long pfn;
@@ -384,6 +385,7 @@
vma->vm_pgoff = pfn;
return mmap_mem(file, vma);
}
+#endif
#ifdef CONFIG_CRASH_DUMP
/*
@@ -422,6 +424,7 @@
extern long vread(char *buf, char *addr, unsigned long count);
extern long vwrite(char *buf, char *addr, unsigned long count);
+#ifdef CONFIG_DEVKMEM
/*
* This function reads the *virtual* memory as seen by the kernel.
*/
@@ -626,6 +629,7 @@
*ppos = p;
return virtr + wrote;
}
+#endif
#ifdef CONFIG_DEVPORT
static ssize_t read_port(struct file * file, char __user * buf,
@@ -803,6 +807,7 @@
.get_unmapped_area = get_unmapped_area_mem,
};
+#ifdef CONFIG_DEVKMEM
static const struct file_operations kmem_fops = {
.llseek = memory_lseek,
.read = read_kmem,
@@ -811,6 +816,7 @@
.open = open_kmem,
.get_unmapped_area = get_unmapped_area_mem,
};
+#endif
static const struct file_operations null_fops = {
.llseek = null_lseek,
@@ -889,11 +895,13 @@
filp->f_mapping->backing_dev_info =
&directly_mappable_cdev_bdi;
break;
+#ifdef CONFIG_DEVKMEM
case 2:
filp->f_op = &kmem_fops;
filp->f_mapping->backing_dev_info =
&directly_mappable_cdev_bdi;
break;
+#endif
case 3:
filp->f_op = &null_fops;
break;
@@ -942,7 +950,9 @@
const struct file_operations *fops;
} devlist[] = { /* list of minor devices */
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
+#ifdef CONFIG_DEVKMEM
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
+#endif
{3, "null", S_IRUGO | S_IWUGO, &null_fops},
#ifdef CONFIG_DEVPORT
{4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 4d058da..eaace0d 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -263,23 +263,26 @@
static int __init misc_init(void)
{
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *ent;
+ int err;
- ent = create_proc_entry("misc", 0, NULL);
- if (ent)
- ent->proc_fops = &misc_proc_fops;
+#ifdef CONFIG_PROC_FS
+ proc_create("misc", 0, NULL, &misc_proc_fops);
#endif
misc_class = class_create(THIS_MODULE, "misc");
+ err = PTR_ERR(misc_class);
if (IS_ERR(misc_class))
- return PTR_ERR(misc_class);
+ goto fail_remove;
- if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
- printk("unable to get major %d for misc devices\n",
- MISC_MAJOR);
- class_destroy(misc_class);
- return -EIO;
- }
+ err = -EIO;
+ if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
+ goto fail_printk;
return 0;
+
+fail_printk:
+ printk("unable to get major %d for misc devices\n", MISC_MAJOR);
+ class_destroy(misc_class);
+fail_remove:
+ remove_proc_entry("misc", NULL);
+ return err;
}
subsys_initcall(misc_init);
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index e60a74c..192961f 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -30,6 +30,8 @@
#include <linux/miscdevice.h>
#include <linux/posix-timers.h>
#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/math64.h>
#include <asm/uaccess.h>
#include <asm/sn/addrs.h>
@@ -74,9 +76,8 @@
* We only have comparison registers RTC1-4 currently available per
* node. RTC0 is used by SAL.
*/
-#define NUM_COMPARATORS 3
/* Check for an RTC interrupt pending */
-static int inline mmtimer_int_pending(int comparator)
+static int mmtimer_int_pending(int comparator)
{
if (HUB_L((unsigned long *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED)) &
SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator)
@@ -84,15 +85,16 @@
else
return 0;
}
+
/* Clear the RTC interrupt pending bit */
-static void inline mmtimer_clr_int_pending(int comparator)
+static void mmtimer_clr_int_pending(int comparator)
{
HUB_S((u64 *)LOCAL_MMR_ADDR(SH_EVENT_OCCURRED_ALIAS),
SH_EVENT_OCCURRED_RTC1_INT_MASK << comparator);
}
/* Setup timer on comparator RTC1 */
-static void inline mmtimer_setup_int_0(u64 expires)
+static void mmtimer_setup_int_0(int cpu, u64 expires)
{
u64 val;
@@ -106,7 +108,7 @@
mmtimer_clr_int_pending(0);
val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC1_INT_CONFIG_IDX_SHFT) |
- ((u64)cpu_physical_id(smp_processor_id()) <<
+ ((u64)cpu_physical_id(cpu) <<
SH_RTC1_INT_CONFIG_PID_SHFT);
/* Set configuration */
@@ -122,7 +124,7 @@
}
/* Setup timer on comparator RTC2 */
-static void inline mmtimer_setup_int_1(u64 expires)
+static void mmtimer_setup_int_1(int cpu, u64 expires)
{
u64 val;
@@ -133,7 +135,7 @@
mmtimer_clr_int_pending(1);
val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC2_INT_CONFIG_IDX_SHFT) |
- ((u64)cpu_physical_id(smp_processor_id()) <<
+ ((u64)cpu_physical_id(cpu) <<
SH_RTC2_INT_CONFIG_PID_SHFT);
HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC2_INT_CONFIG), val);
@@ -144,7 +146,7 @@
}
/* Setup timer on comparator RTC3 */
-static void inline mmtimer_setup_int_2(u64 expires)
+static void mmtimer_setup_int_2(int cpu, u64 expires)
{
u64 val;
@@ -155,7 +157,7 @@
mmtimer_clr_int_pending(2);
val = ((u64)SGI_MMTIMER_VECTOR << SH_RTC3_INT_CONFIG_IDX_SHFT) |
- ((u64)cpu_physical_id(smp_processor_id()) <<
+ ((u64)cpu_physical_id(cpu) <<
SH_RTC3_INT_CONFIG_PID_SHFT);
HUB_S((u64 *)LOCAL_MMR_ADDR(SH_RTC3_INT_CONFIG), val);
@@ -170,22 +172,22 @@
* in order to insure that the setup succeeds in a deterministic time frame.
* It will check if the interrupt setup succeeded.
*/
-static int inline mmtimer_setup(int comparator, unsigned long expires)
+static int mmtimer_setup(int cpu, int comparator, unsigned long expires)
{
switch (comparator) {
case 0:
- mmtimer_setup_int_0(expires);
+ mmtimer_setup_int_0(cpu, expires);
break;
case 1:
- mmtimer_setup_int_1(expires);
+ mmtimer_setup_int_1(cpu, expires);
break;
case 2:
- mmtimer_setup_int_2(expires);
+ mmtimer_setup_int_2(cpu, expires);
break;
}
/* We might've missed our expiration time */
- if (rtc_time() < expires)
+ if (rtc_time() <= expires)
return 1;
/*
@@ -195,7 +197,7 @@
return mmtimer_int_pending(comparator);
}
-static int inline mmtimer_disable_int(long nasid, int comparator)
+static int mmtimer_disable_int(long nasid, int comparator)
{
switch (comparator) {
case 0:
@@ -216,18 +218,124 @@
return 0;
}
-#define TIMER_OFF 0xbadcabLL
+#define COMPARATOR 1 /* The comparator to use */
-/* There is one of these for each comparator */
-typedef struct mmtimer {
- spinlock_t lock ____cacheline_aligned;
+#define TIMER_OFF 0xbadcabLL /* Timer is not setup */
+#define TIMER_SET 0 /* Comparator is set for this timer */
+
+/* There is one of these for each timer */
+struct mmtimer {
+ struct rb_node list;
struct k_itimer *timer;
- int i;
int cpu;
- struct tasklet_struct tasklet;
-} mmtimer_t;
+};
-static mmtimer_t ** timers;
+struct mmtimer_node {
+ spinlock_t lock ____cacheline_aligned;
+ struct rb_root timer_head;
+ struct rb_node *next;
+ struct tasklet_struct tasklet;
+};
+static struct mmtimer_node *timers;
+
+
+/*
+ * Add a new mmtimer struct to the node's mmtimer list.
+ * This function assumes the struct mmtimer_node is locked.
+ */
+static void mmtimer_add_list(struct mmtimer *n)
+{
+ int nodeid = n->timer->it.mmtimer.node;
+ unsigned long expires = n->timer->it.mmtimer.expires;
+ struct rb_node **link = &timers[nodeid].timer_head.rb_node;
+ struct rb_node *parent = NULL;
+ struct mmtimer *x;
+
+ /*
+ * Find the right place in the rbtree:
+ */
+ while (*link) {
+ parent = *link;
+ x = rb_entry(parent, struct mmtimer, list);
+
+ if (expires < x->timer->it.mmtimer.expires)
+ link = &(*link)->rb_left;
+ else
+ link = &(*link)->rb_right;
+ }
+
+ /*
+ * Insert the timer to the rbtree and check whether it
+ * replaces the first pending timer
+ */
+ rb_link_node(&n->list, parent, link);
+ rb_insert_color(&n->list, &timers[nodeid].timer_head);
+
+ if (!timers[nodeid].next || expires < rb_entry(timers[nodeid].next,
+ struct mmtimer, list)->timer->it.mmtimer.expires)
+ timers[nodeid].next = &n->list;
+}
+
+/*
+ * Set the comparator for the next timer.
+ * This function assumes the struct mmtimer_node is locked.
+ */
+static void mmtimer_set_next_timer(int nodeid)
+{
+ struct mmtimer_node *n = &timers[nodeid];
+ struct mmtimer *x;
+ struct k_itimer *t;
+ int o;
+
+restart:
+ if (n->next == NULL)
+ return;
+
+ x = rb_entry(n->next, struct mmtimer, list);
+ t = x->timer;
+ if (!t->it.mmtimer.incr) {
+ /* Not an interval timer */
+ if (!mmtimer_setup(x->cpu, COMPARATOR,
+ t->it.mmtimer.expires)) {
+ /* Late setup, fire now */
+ tasklet_schedule(&n->tasklet);
+ }
+ return;
+ }
+
+ /* Interval timer */
+ o = 0;
+ while (!mmtimer_setup(x->cpu, COMPARATOR, t->it.mmtimer.expires)) {
+ unsigned long e, e1;
+ struct rb_node *next;
+ t->it.mmtimer.expires += t->it.mmtimer.incr << o;
+ t->it_overrun += 1 << o;
+ o++;
+ if (o > 20) {
+ printk(KERN_ALERT "mmtimer: cannot reschedule timer\n");
+ t->it.mmtimer.clock = TIMER_OFF;
+ n->next = rb_next(&x->list);
+ rb_erase(&x->list, &n->timer_head);
+ kfree(x);
+ goto restart;
+ }
+
+ e = t->it.mmtimer.expires;
+ next = rb_next(&x->list);
+
+ if (next == NULL)
+ continue;
+
+ e1 = rb_entry(next, struct mmtimer, list)->
+ timer->it.mmtimer.expires;
+ if (e > e1) {
+ n->next = next;
+ rb_erase(&x->list, &n->timer_head);
+ mmtimer_add_list(x);
+ goto restart;
+ }
+ }
+}
/**
* mmtimer_ioctl - ioctl interface for /dev/mmtimer
@@ -366,8 +474,8 @@
nsec = rtc_time() * sgi_clock_period
+ sgi_clock_offset.tv_nsec;
- tp->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tp->tv_nsec)
- + sgi_clock_offset.tv_sec;
+ *tp = ns_to_timespec(nsec);
+ tp->tv_sec += sgi_clock_offset.tv_sec;
return 0;
};
@@ -375,11 +483,11 @@
{
u64 nsec;
- u64 rem;
+ u32 rem;
nsec = rtc_time() * sgi_clock_period;
- sgi_clock_offset.tv_sec = tp->tv_sec - div_long_long_rem(nsec, NSEC_PER_SEC, &rem);
+ sgi_clock_offset.tv_sec = tp->tv_sec - div_u64_rem(nsec, NSEC_PER_SEC, &rem);
if (rem <= tp->tv_nsec)
sgi_clock_offset.tv_nsec = tp->tv_sec - rem;
@@ -390,35 +498,6 @@
return 0;
}
-/*
- * Schedule the next periodic interrupt. This function will attempt
- * to schedule a periodic interrupt later if necessary. If the scheduling
- * of an interrupt fails then the time to skip is lengthened
- * exponentially in order to ensure that the next interrupt
- * can be properly scheduled..
- */
-static int inline reschedule_periodic_timer(mmtimer_t *x)
-{
- int n;
- struct k_itimer *t = x->timer;
-
- t->it.mmtimer.clock = x->i;
- t->it_overrun--;
-
- n = 0;
- do {
-
- t->it.mmtimer.expires += t->it.mmtimer.incr << n;
- t->it_overrun += 1 << n;
- n++;
- if (n > 20)
- return 1;
-
- } while (!mmtimer_setup(x->i, t->it.mmtimer.expires));
-
- return 0;
-}
-
/**
* mmtimer_interrupt - timer interrupt handler
* @irq: irq received
@@ -435,71 +514,75 @@
static irqreturn_t
mmtimer_interrupt(int irq, void *dev_id)
{
- int i;
unsigned long expires = 0;
int result = IRQ_NONE;
unsigned indx = cpu_to_node(smp_processor_id());
+ struct mmtimer *base;
- /*
- * Do this once for each comparison register
- */
- for (i = 0; i < NUM_COMPARATORS; i++) {
- mmtimer_t *base = timers[indx] + i;
- /* Make sure this doesn't get reused before tasklet_sched */
- spin_lock(&base->lock);
- if (base->cpu == smp_processor_id()) {
- if (base->timer)
- expires = base->timer->it.mmtimer.expires;
- /* expires test won't work with shared irqs */
- if ((mmtimer_int_pending(i) > 0) ||
- (expires && (expires < rtc_time()))) {
- mmtimer_clr_int_pending(i);
- tasklet_schedule(&base->tasklet);
- result = IRQ_HANDLED;
- }
- }
- spin_unlock(&base->lock);
- expires = 0;
+ spin_lock(&timers[indx].lock);
+ base = rb_entry(timers[indx].next, struct mmtimer, list);
+ if (base == NULL) {
+ spin_unlock(&timers[indx].lock);
+ return result;
}
+
+ if (base->cpu == smp_processor_id()) {
+ if (base->timer)
+ expires = base->timer->it.mmtimer.expires;
+ /* expires test won't work with shared irqs */
+ if ((mmtimer_int_pending(COMPARATOR) > 0) ||
+ (expires && (expires <= rtc_time()))) {
+ mmtimer_clr_int_pending(COMPARATOR);
+ tasklet_schedule(&timers[indx].tasklet);
+ result = IRQ_HANDLED;
+ }
+ }
+ spin_unlock(&timers[indx].lock);
return result;
}
-void mmtimer_tasklet(unsigned long data) {
- mmtimer_t *x = (mmtimer_t *)data;
- struct k_itimer *t = x->timer;
+static void mmtimer_tasklet(unsigned long data)
+{
+ int nodeid = data;
+ struct mmtimer_node *mn = &timers[nodeid];
+ struct mmtimer *x = rb_entry(mn->next, struct mmtimer, list);
+ struct k_itimer *t;
unsigned long flags;
- if (t == NULL)
- return;
-
/* Send signal and deal with periodic signals */
- spin_lock_irqsave(&t->it_lock, flags);
- spin_lock(&x->lock);
- /* If timer was deleted between interrupt and here, leave */
- if (t != x->timer)
+ spin_lock_irqsave(&mn->lock, flags);
+ if (!mn->next)
goto out;
+
+ x = rb_entry(mn->next, struct mmtimer, list);
+ t = x->timer;
+
+ if (t->it.mmtimer.clock == TIMER_OFF)
+ goto out;
+
t->it_overrun = 0;
- if (posix_timer_event(t, 0) != 0) {
+ mn->next = rb_next(&x->list);
+ rb_erase(&x->list, &mn->timer_head);
- // printk(KERN_WARNING "mmtimer: cannot deliver signal.\n");
-
+ if (posix_timer_event(t, 0) != 0)
t->it_overrun++;
- }
+
if(t->it.mmtimer.incr) {
- /* Periodic timer */
- if (reschedule_periodic_timer(x)) {
- printk(KERN_WARNING "mmtimer: unable to reschedule\n");
- x->timer = NULL;
- }
+ t->it.mmtimer.expires += t->it.mmtimer.incr;
+ mmtimer_add_list(x);
} else {
/* Ensure we don't false trigger in mmtimer_interrupt */
+ t->it.mmtimer.clock = TIMER_OFF;
t->it.mmtimer.expires = 0;
+ kfree(x);
}
+ /* Set comparator for next timer, if there is one */
+ mmtimer_set_next_timer(nodeid);
+
t->it_overrun_last = t->it_overrun;
out:
- spin_unlock(&x->lock);
- spin_unlock_irqrestore(&t->it_lock, flags);
+ spin_unlock_irqrestore(&mn->lock, flags);
}
static int sgi_timer_create(struct k_itimer *timer)
@@ -516,25 +599,53 @@
*/
static int sgi_timer_del(struct k_itimer *timr)
{
- int i = timr->it.mmtimer.clock;
cnodeid_t nodeid = timr->it.mmtimer.node;
- mmtimer_t *t = timers[nodeid] + i;
unsigned long irqflags;
- if (i != TIMER_OFF) {
- spin_lock_irqsave(&t->lock, irqflags);
- mmtimer_disable_int(cnodeid_to_nasid(nodeid),i);
- t->timer = NULL;
+ spin_lock_irqsave(&timers[nodeid].lock, irqflags);
+ if (timr->it.mmtimer.clock != TIMER_OFF) {
+ unsigned long expires = timr->it.mmtimer.expires;
+ struct rb_node *n = timers[nodeid].timer_head.rb_node;
+ struct mmtimer *uninitialized_var(t);
+ int r = 0;
+
timr->it.mmtimer.clock = TIMER_OFF;
timr->it.mmtimer.expires = 0;
- spin_unlock_irqrestore(&t->lock, irqflags);
+
+ while (n) {
+ t = rb_entry(n, struct mmtimer, list);
+ if (t->timer == timr)
+ break;
+
+ if (expires < t->timer->it.mmtimer.expires)
+ n = n->rb_left;
+ else
+ n = n->rb_right;
+ }
+
+ if (!n) {
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
+ return 0;
+ }
+
+ if (timers[nodeid].next == n) {
+ timers[nodeid].next = rb_next(n);
+ r = 1;
+ }
+
+ rb_erase(n, &timers[nodeid].timer_head);
+ kfree(t);
+
+ if (r) {
+ mmtimer_disable_int(cnodeid_to_nasid(nodeid),
+ COMPARATOR);
+ mmtimer_set_next_timer(nodeid);
+ }
}
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
return 0;
}
-#define timespec_to_ns(x) ((x).tv_nsec + (x).tv_sec * NSEC_PER_SEC)
-#define ns_to_timespec(ts, nsec) (ts).tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &(ts).tv_nsec)
-
/* Assumption: it_lock is already held with irq's disabled */
static void sgi_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting)
{
@@ -547,9 +658,8 @@
return;
}
- ns_to_timespec(cur_setting->it_interval, timr->it.mmtimer.incr * sgi_clock_period);
- ns_to_timespec(cur_setting->it_value, (timr->it.mmtimer.expires - rtc_time())* sgi_clock_period);
- return;
+ cur_setting->it_interval = ns_to_timespec(timr->it.mmtimer.incr * sgi_clock_period);
+ cur_setting->it_value = ns_to_timespec((timr->it.mmtimer.expires - rtc_time()) * sgi_clock_period);
}
@@ -557,30 +667,33 @@
struct itimerspec * new_setting,
struct itimerspec * old_setting)
{
-
- int i;
unsigned long when, period, irqflags;
int err = 0;
cnodeid_t nodeid;
- mmtimer_t *base;
+ struct mmtimer *base;
+ struct rb_node *n;
if (old_setting)
sgi_timer_get(timr, old_setting);
sgi_timer_del(timr);
- when = timespec_to_ns(new_setting->it_value);
- period = timespec_to_ns(new_setting->it_interval);
+ when = timespec_to_ns(&new_setting->it_value);
+ period = timespec_to_ns(&new_setting->it_interval);
if (when == 0)
/* Clear timer */
return 0;
+ base = kmalloc(sizeof(struct mmtimer), GFP_KERNEL);
+ if (base == NULL)
+ return -ENOMEM;
+
if (flags & TIMER_ABSTIME) {
struct timespec n;
unsigned long now;
getnstimeofday(&n);
- now = timespec_to_ns(n);
+ now = timespec_to_ns(&n);
if (when > now)
when -= now;
else
@@ -604,47 +717,38 @@
preempt_disable();
nodeid = cpu_to_node(smp_processor_id());
-retry:
- /* Don't use an allocated timer, or a deleted one that's pending */
- for(i = 0; i< NUM_COMPARATORS; i++) {
- base = timers[nodeid] + i;
- if (!base->timer && !base->tasklet.state) {
- break;
- }
- }
- if (i == NUM_COMPARATORS) {
- preempt_enable();
- return -EBUSY;
- }
+ /* Lock the node timer structure */
+ spin_lock_irqsave(&timers[nodeid].lock, irqflags);
- spin_lock_irqsave(&base->lock, irqflags);
-
- if (base->timer || base->tasklet.state != 0) {
- spin_unlock_irqrestore(&base->lock, irqflags);
- goto retry;
- }
base->timer = timr;
base->cpu = smp_processor_id();
- timr->it.mmtimer.clock = i;
+ timr->it.mmtimer.clock = TIMER_SET;
timr->it.mmtimer.node = nodeid;
timr->it.mmtimer.incr = period;
timr->it.mmtimer.expires = when;
- if (period == 0) {
- if (!mmtimer_setup(i, when)) {
- mmtimer_disable_int(-1, i);
- posix_timer_event(timr, 0);
- timr->it.mmtimer.expires = 0;
- }
- } else {
- timr->it.mmtimer.expires -= period;
- if (reschedule_periodic_timer(base))
- err = -EINVAL;
+ n = timers[nodeid].next;
+
+ /* Add the new struct mmtimer to node's timer list */
+ mmtimer_add_list(base);
+
+ if (timers[nodeid].next == n) {
+ /* No need to reprogram comparator for now */
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
+ preempt_enable();
+ return err;
}
- spin_unlock_irqrestore(&base->lock, irqflags);
+ /* We need to reprogram the comparator */
+ if (n)
+ mmtimer_disable_int(cnodeid_to_nasid(nodeid), COMPARATOR);
+
+ mmtimer_set_next_timer(nodeid);
+
+ /* Unlock the node timer structure */
+ spin_unlock_irqrestore(&timers[nodeid].lock, irqflags);
preempt_enable();
@@ -669,7 +773,6 @@
*/
static int __init mmtimer_init(void)
{
- unsigned i;
cnodeid_t node, maxn = -1;
if (!ia64_platform_is("sn2"))
@@ -706,31 +809,18 @@
maxn++;
/* Allocate list of node ptrs to mmtimer_t's */
- timers = kzalloc(sizeof(mmtimer_t *)*maxn, GFP_KERNEL);
+ timers = kzalloc(sizeof(struct mmtimer_node)*maxn, GFP_KERNEL);
if (timers == NULL) {
printk(KERN_ERR "%s: failed to allocate memory for device\n",
MMTIMER_NAME);
goto out3;
}
- /* Allocate mmtimer_t's for each online node */
+ /* Initialize struct mmtimer's for each online node */
for_each_online_node(node) {
- timers[node] = kmalloc_node(sizeof(mmtimer_t)*NUM_COMPARATORS, GFP_KERNEL, node);
- if (timers[node] == NULL) {
- printk(KERN_ERR "%s: failed to allocate memory for device\n",
- MMTIMER_NAME);
- goto out4;
- }
- for (i=0; i< NUM_COMPARATORS; i++) {
- mmtimer_t * base = timers[node] + i;
-
- spin_lock_init(&base->lock);
- base->timer = NULL;
- base->cpu = 0;
- base->i = i;
- tasklet_init(&base->tasklet, mmtimer_tasklet,
- (unsigned long) (base));
- }
+ spin_lock_init(&timers[node].lock);
+ tasklet_init(&timers[node].tasklet, mmtimer_tasklet,
+ (unsigned long) node);
}
sgi_clock_period = sgi_clock.res = NSEC_PER_SEC / sn_rtc_cycles_per_second;
@@ -741,11 +831,8 @@
return 0;
-out4:
- for_each_online_node(node) {
- kfree(timers[node]);
- }
out3:
+ kfree(timers);
misc_deregister(&mmtimer_miscdev);
out2:
free_irq(SGI_MMTIMER_VECTOR, NULL);
@@ -754,4 +841,3 @@
}
module_init(mmtimer_init);
-
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 64b7b2b..d57d3a6 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -2,7 +2,8 @@
/*
* moxa.c -- MOXA Intellio family multiport serial driver.
*
- * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com.tw).
+ * Copyright (C) 1999-2000 Moxa Technologies (support@moxa.com).
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
*
* This code is loosely based on the Linux serial driver, written by
* Linus Torvalds, Theodore T'so and others.
@@ -25,6 +26,7 @@
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/errno.h>
+#include <linux/firmware.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
@@ -41,21 +43,26 @@
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/bitops.h>
-#include <linux/completion.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#define MOXA_VERSION "5.1k"
+#include "moxa.h"
+
+#define MOXA_VERSION "6.0k"
+
+#define MOXA_FW_HDRLEN 32
#define MOXAMAJOR 172
-#define MOXACUMAJOR 173
#define MAX_BOARDS 4 /* Don't change this value */
#define MAX_PORTS_PER_BOARD 32 /* Don't change this value */
#define MAX_PORTS (MAX_BOARDS * MAX_PORTS_PER_BOARD)
+#define MOXA_IS_320(brd) ((brd)->boardType == MOXA_BOARD_C320_ISA || \
+ (brd)->boardType == MOXA_BOARD_C320_PCI)
+
/*
* Define the Moxa PCI vendor and device IDs.
*/
@@ -92,24 +99,16 @@
MODULE_DEVICE_TABLE(pci, moxa_pcibrds);
#endif /* CONFIG_PCI */
-struct moxa_isa_board_conf {
- int boardType;
- int numPorts;
- unsigned long baseAddr;
-};
-
-static struct moxa_isa_board_conf moxa_isa_boards[] =
-{
-/* {MOXA_BOARD_C218_ISA,8,0xDC000}, */
-};
+struct moxa_port;
static struct moxa_board_conf {
int boardType;
int numPorts;
- unsigned long baseAddr;
int busType;
- int loadstat;
+ unsigned int ready;
+
+ struct moxa_port *ports;
void __iomem *basemem;
void __iomem *intNdx;
@@ -131,30 +130,27 @@
};
struct moxa_port {
- int type;
- int port;
- int close_delay;
- unsigned short closing_wait;
- int count;
- int blocked_open;
- long event; /* long req'd for set_bit --RR */
- int asyncflags;
- unsigned long statusflags;
+ struct moxa_board_conf *board;
struct tty_struct *tty;
- int cflag;
- wait_queue_head_t open_wait;
- struct completion close_wait;
-
- struct timer_list emptyTimer;
-
- char chkPort;
- char lineCtrl;
void __iomem *tableAddr;
- long curBaud;
- char DCDState;
- char lowChkFlag;
- ushort breakCnt;
+ int type;
+ int close_delay;
+ unsigned int count;
+ int asyncflags;
+ int cflag;
+ unsigned long statusflags;
+ wait_queue_head_t open_wait;
+
+ u8 DCDState;
+ u8 lineCtrl;
+ u8 lowChkFlag;
+};
+
+struct mon_str {
+ int tick;
+ int rxcnt[MAX_PORTS];
+ int txcnt[MAX_PORTS];
};
/* statusflags */
@@ -168,20 +164,27 @@
#define WAKEUP_CHARS 256
static int ttymajor = MOXAMAJOR;
+static struct mon_str moxaLog;
+static unsigned int moxaFuncTout = HZ / 2;
+static unsigned int moxaLowWaterChk;
+static DEFINE_MUTEX(moxa_openlock);
/* Variables for insmod */
#ifdef MODULE
-static int baseaddr[4];
-static int type[4];
-static int numports[4];
+static unsigned long baseaddr[MAX_BOARDS];
+static unsigned int type[MAX_BOARDS];
+static unsigned int numports[MAX_BOARDS];
#endif
MODULE_AUTHOR("William Chen");
MODULE_DESCRIPTION("MOXA Intellio Family Multiport Board Device Driver");
MODULE_LICENSE("GPL");
#ifdef MODULE
-module_param_array(type, int, NULL, 0);
-module_param_array(baseaddr, int, NULL, 0);
-module_param_array(numports, int, NULL, 0);
+module_param_array(type, uint, NULL, 0);
+MODULE_PARM_DESC(type, "card type: C218=2, C320=4");
+module_param_array(baseaddr, ulong, NULL, 0);
+MODULE_PARM_DESC(baseaddr, "base address");
+module_param_array(numports, uint, NULL, 0);
+MODULE_PARM_DESC(numports, "numports (ignored for C218)");
#endif
module_param(ttymajor, int, 0);
@@ -194,9 +197,6 @@
static int moxa_write_room(struct tty_struct *);
static void moxa_flush_buffer(struct tty_struct *);
static int moxa_chars_in_buffer(struct tty_struct *);
-static void moxa_flush_chars(struct tty_struct *);
-static void moxa_put_char(struct tty_struct *, unsigned char);
-static int moxa_ioctl(struct tty_struct *, struct file *, unsigned int, unsigned long);
static void moxa_throttle(struct tty_struct *);
static void moxa_unthrottle(struct tty_struct *);
static void moxa_set_termios(struct tty_struct *, struct ktermios *);
@@ -208,44 +208,183 @@
unsigned int set, unsigned int clear);
static void moxa_poll(unsigned long);
static void moxa_set_tty_param(struct tty_struct *, struct ktermios *);
-static int moxa_block_till_ready(struct tty_struct *, struct file *,
- struct moxa_port *);
static void moxa_setup_empty_event(struct tty_struct *);
-static void moxa_check_xmit_empty(unsigned long);
static void moxa_shut_down(struct moxa_port *);
-static void moxa_receive_data(struct moxa_port *);
/*
* moxa board interface functions:
*/
-static void MoxaDriverInit(void);
-static int MoxaDriverIoctl(unsigned int, unsigned long, int);
-static int MoxaDriverPoll(void);
-static int MoxaPortsOfCard(int);
-static int MoxaPortIsValid(int);
-static void MoxaPortEnable(int);
-static void MoxaPortDisable(int);
-static long MoxaPortGetMaxBaud(int);
-static long MoxaPortSetBaud(int, long);
-static int MoxaPortSetTermio(int, struct ktermios *, speed_t);
-static int MoxaPortGetLineOut(int, int *, int *);
-static void MoxaPortLineCtrl(int, int, int);
-static void MoxaPortFlowCtrl(int, int, int, int, int, int);
-static int MoxaPortLineStatus(int);
-static int MoxaPortDCDChange(int);
-static int MoxaPortDCDON(int);
-static void MoxaPortFlushData(int, int);
-static int MoxaPortWriteData(int, unsigned char *, int);
-static int MoxaPortReadData(int, struct tty_struct *tty);
-static int MoxaPortTxQueue(int);
-static int MoxaPortRxQueue(int);
-static int MoxaPortTxFree(int);
-static void MoxaPortTxDisable(int);
-static void MoxaPortTxEnable(int);
-static int MoxaPortResetBrkCnt(int);
-static void MoxaPortSendBreak(int, int);
+static void MoxaPortEnable(struct moxa_port *);
+static void MoxaPortDisable(struct moxa_port *);
+static int MoxaPortSetTermio(struct moxa_port *, struct ktermios *, speed_t);
+static int MoxaPortGetLineOut(struct moxa_port *, int *, int *);
+static void MoxaPortLineCtrl(struct moxa_port *, int, int);
+static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int);
+static int MoxaPortLineStatus(struct moxa_port *);
+static void MoxaPortFlushData(struct moxa_port *, int);
+static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int);
+static int MoxaPortReadData(struct moxa_port *);
+static int MoxaPortTxQueue(struct moxa_port *);
+static int MoxaPortRxQueue(struct moxa_port *);
+static int MoxaPortTxFree(struct moxa_port *);
+static void MoxaPortTxDisable(struct moxa_port *);
+static void MoxaPortTxEnable(struct moxa_port *);
static int moxa_get_serial_info(struct moxa_port *, struct serial_struct __user *);
static int moxa_set_serial_info(struct moxa_port *, struct serial_struct __user *);
-static void MoxaSetFifo(int port, int enable);
+static void MoxaSetFifo(struct moxa_port *port, int enable);
+
+/*
+ * I/O functions
+ */
+
+static void moxa_wait_finish(void __iomem *ofsAddr)
+{
+ unsigned long end = jiffies + moxaFuncTout;
+
+ while (readw(ofsAddr + FuncCode) != 0)
+ if (time_after(jiffies, end))
+ return;
+ if (readw(ofsAddr + FuncCode) != 0 && printk_ratelimit())
+ printk(KERN_WARNING "moxa function expired\n");
+}
+
+static void moxafunc(void __iomem *ofsAddr, u16 cmd, u16 arg)
+{
+ writew(arg, ofsAddr + FuncArg);
+ writew(cmd, ofsAddr + FuncCode);
+ moxa_wait_finish(ofsAddr);
+}
+
+static void moxa_low_water_check(void __iomem *ofsAddr)
+{
+ u16 rptr, wptr, mask, len;
+
+ if (readb(ofsAddr + FlagStat) & Xoff_state) {
+ rptr = readw(ofsAddr + RXrptr);
+ wptr = readw(ofsAddr + RXwptr);
+ mask = readw(ofsAddr + RX_mask);
+ len = (wptr - rptr) & mask;
+ if (len <= Low_water)
+ moxafunc(ofsAddr, FC_SendXon, 0);
+ }
+}
+
+/*
+ * TTY operations
+ */
+
+static int moxa_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct moxa_port *ch = tty->driver_data;
+ void __user *argp = (void __user *)arg;
+ int status, ret = 0;
+
+ if (tty->index == MAX_PORTS) {
+ if (cmd != MOXA_GETDATACOUNT && cmd != MOXA_GET_IOQUEUE &&
+ cmd != MOXA_GETMSTATUS)
+ return -EINVAL;
+ } else if (!ch)
+ return -ENODEV;
+
+ switch (cmd) {
+ case MOXA_GETDATACOUNT:
+ moxaLog.tick = jiffies;
+ if (copy_to_user(argp, &moxaLog, sizeof(moxaLog)))
+ ret = -EFAULT;
+ break;
+ case MOXA_FLUSH_QUEUE:
+ MoxaPortFlushData(ch, arg);
+ break;
+ case MOXA_GET_IOQUEUE: {
+ struct moxaq_str __user *argm = argp;
+ struct moxaq_str tmp;
+ struct moxa_port *p;
+ unsigned int i, j;
+
+ mutex_lock(&moxa_openlock);
+ for (i = 0; i < MAX_BOARDS; i++) {
+ p = moxa_boards[i].ports;
+ for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+ memset(&tmp, 0, sizeof(tmp));
+ if (moxa_boards[i].ready) {
+ tmp.inq = MoxaPortRxQueue(p);
+ tmp.outq = MoxaPortTxQueue(p);
+ }
+ if (copy_to_user(argm, &tmp, sizeof(tmp))) {
+ mutex_unlock(&moxa_openlock);
+ return -EFAULT;
+ }
+ }
+ }
+ mutex_unlock(&moxa_openlock);
+ break;
+ } case MOXA_GET_OQUEUE:
+ status = MoxaPortTxQueue(ch);
+ ret = put_user(status, (unsigned long __user *)argp);
+ break;
+ case MOXA_GET_IQUEUE:
+ status = MoxaPortRxQueue(ch);
+ ret = put_user(status, (unsigned long __user *)argp);
+ break;
+ case MOXA_GETMSTATUS: {
+ struct mxser_mstatus __user *argm = argp;
+ struct mxser_mstatus tmp;
+ struct moxa_port *p;
+ unsigned int i, j;
+
+ mutex_lock(&moxa_openlock);
+ for (i = 0; i < MAX_BOARDS; i++) {
+ p = moxa_boards[i].ports;
+ for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) {
+ memset(&tmp, 0, sizeof(tmp));
+ if (!moxa_boards[i].ready)
+ goto copy;
+
+ status = MoxaPortLineStatus(p);
+ if (status & 1)
+ tmp.cts = 1;
+ if (status & 2)
+ tmp.dsr = 1;
+ if (status & 4)
+ tmp.dcd = 1;
+
+ if (!p->tty || !p->tty->termios)
+ tmp.cflag = p->cflag;
+ else
+ tmp.cflag = p->tty->termios->c_cflag;
+copy:
+ if (copy_to_user(argm, &tmp, sizeof(tmp))) {
+ mutex_unlock(&moxa_openlock);
+ return -EFAULT;
+ }
+ }
+ }
+ mutex_unlock(&moxa_openlock);
+ break;
+ }
+ case TIOCGSERIAL:
+ mutex_lock(&moxa_openlock);
+ ret = moxa_get_serial_info(ch, argp);
+ mutex_unlock(&moxa_openlock);
+ break;
+ case TIOCSSERIAL:
+ mutex_lock(&moxa_openlock);
+ ret = moxa_set_serial_info(ch, argp);
+ mutex_unlock(&moxa_openlock);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+ return ret;
+}
+
+static void moxa_break_ctl(struct tty_struct *tty, int state)
+{
+ struct moxa_port *port = tty->driver_data;
+
+ moxafunc(port->tableAddr, state ? FC_SendBreak : FC_StopBreak,
+ Magic_code);
+}
static const struct tty_operations moxa_ops = {
.open = moxa_open,
@@ -254,8 +393,6 @@
.write_room = moxa_write_room,
.flush_buffer = moxa_flush_buffer,
.chars_in_buffer = moxa_chars_in_buffer,
- .flush_chars = moxa_flush_chars,
- .put_char = moxa_put_char,
.ioctl = moxa_ioctl,
.throttle = moxa_throttle,
.unthrottle = moxa_unthrottle,
@@ -263,15 +400,509 @@
.stop = moxa_stop,
.start = moxa_start,
.hangup = moxa_hangup,
+ .break_ctl = moxa_break_ctl,
.tiocmget = moxa_tiocmget,
.tiocmset = moxa_tiocmset,
};
static struct tty_driver *moxaDriver;
-static struct moxa_port moxa_ports[MAX_PORTS];
static DEFINE_TIMER(moxaTimer, moxa_poll, 0, 0);
static DEFINE_SPINLOCK(moxa_lock);
+/*
+ * HW init
+ */
+
+static int moxa_check_fw_model(struct moxa_board_conf *brd, u8 model)
+{
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ if (model != 1)
+ goto err;
+ break;
+ case MOXA_BOARD_CP204J:
+ if (model != 3)
+ goto err;
+ break;
+ default:
+ if (model != 2)
+ goto err;
+ break;
+ }
+ return 0;
+err:
+ return -EINVAL;
+}
+
+static int moxa_check_fw(const void *ptr)
+{
+ const __le16 *lptr = ptr;
+
+ if (*lptr != cpu_to_le16(0x7980))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int moxa_load_bios(struct moxa_board_conf *brd, const u8 *buf,
+ size_t len)
+{
+ void __iomem *baseAddr = brd->basemem;
+ u16 tmp;
+
+ writeb(HW_reset, baseAddr + Control_reg); /* reset */
+ msleep(10);
+ memset_io(baseAddr, 0, 4096);
+ memcpy_toio(baseAddr, buf, len); /* download BIOS */
+ writeb(0, baseAddr + Control_reg); /* restart */
+
+ msleep(2000);
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ tmp = readw(baseAddr + C218_key);
+ if (tmp != C218_KeyCode)
+ goto err;
+ break;
+ case MOXA_BOARD_CP204J:
+ tmp = readw(baseAddr + C218_key);
+ if (tmp != CP204J_KeyCode)
+ goto err;
+ break;
+ default:
+ tmp = readw(baseAddr + C320_key);
+ if (tmp != C320_KeyCode)
+ goto err;
+ tmp = readw(baseAddr + C320_status);
+ if (tmp != STS_init) {
+ printk(KERN_ERR "MOXA: bios upload failed -- CPU/Basic "
+ "module not found\n");
+ return -EIO;
+ }
+ break;
+ }
+
+ return 0;
+err:
+ printk(KERN_ERR "MOXA: bios upload failed -- board not found\n");
+ return -EIO;
+}
+
+static int moxa_load_320b(struct moxa_board_conf *brd, const u8 *ptr,
+ size_t len)
+{
+ void __iomem *baseAddr = brd->basemem;
+
+ if (len < 7168) {
+ printk(KERN_ERR "MOXA: invalid 320 bios -- too short\n");
+ return -EINVAL;
+ }
+
+ writew(len - 7168 - 2, baseAddr + C320bapi_len);
+ writeb(1, baseAddr + Control_reg); /* Select Page 1 */
+ memcpy_toio(baseAddr + DynPage_addr, ptr, 7168);
+ writeb(2, baseAddr + Control_reg); /* Select Page 2 */
+ memcpy_toio(baseAddr + DynPage_addr, ptr + 7168, len - 7168);
+
+ return 0;
+}
+
+static int moxa_real_load_code(struct moxa_board_conf *brd, const void *ptr,
+ size_t len)
+{
+ void __iomem *baseAddr = brd->basemem;
+ const u16 *uptr = ptr;
+ size_t wlen, len2, j;
+ unsigned long key, loadbuf, loadlen, checksum, checksum_ok;
+ unsigned int i, retry;
+ u16 usum, keycode;
+
+ keycode = (brd->boardType == MOXA_BOARD_CP204J) ? CP204J_KeyCode :
+ C218_KeyCode;
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_CP204J:
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ key = C218_key;
+ loadbuf = C218_LoadBuf;
+ loadlen = C218DLoad_len;
+ checksum = C218check_sum;
+ checksum_ok = C218chksum_ok;
+ break;
+ default:
+ key = C320_key;
+ keycode = C320_KeyCode;
+ loadbuf = C320_LoadBuf;
+ loadlen = C320DLoad_len;
+ checksum = C320check_sum;
+ checksum_ok = C320chksum_ok;
+ break;
+ }
+
+ usum = 0;
+ wlen = len >> 1;
+ for (i = 0; i < wlen; i++)
+ usum += le16_to_cpu(uptr[i]);
+ retry = 0;
+ do {
+ wlen = len >> 1;
+ j = 0;
+ while (wlen) {
+ len2 = (wlen > 2048) ? 2048 : wlen;
+ wlen -= len2;
+ memcpy_toio(baseAddr + loadbuf, ptr + j, len2 << 1);
+ j += len2 << 1;
+
+ writew(len2, baseAddr + loadlen);
+ writew(0, baseAddr + key);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + key) == keycode)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + key) != keycode)
+ return -EIO;
+ }
+ writew(0, baseAddr + loadlen);
+ writew(usum, baseAddr + checksum);
+ writew(0, baseAddr + key);
+ for (i = 0; i < 100; i++) {
+ if (readw(baseAddr + key) == keycode)
+ break;
+ msleep(10);
+ }
+ retry++;
+ } while ((readb(baseAddr + checksum_ok) != 1) && (retry < 3));
+ if (readb(baseAddr + checksum_ok) != 1)
+ return -EIO;
+
+ writew(0, baseAddr + key);
+ for (i = 0; i < 600; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return -EIO;
+
+ if (MOXA_IS_320(brd)) {
+ if (brd->busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
+ writew(0x3800, baseAddr + TMS320_PORT1);
+ writew(0x3900, baseAddr + TMS320_PORT2);
+ writew(28499, baseAddr + TMS320_CLOCK);
+ } else {
+ writew(0x3200, baseAddr + TMS320_PORT1);
+ writew(0x3400, baseAddr + TMS320_PORT2);
+ writew(19999, baseAddr + TMS320_CLOCK);
+ }
+ }
+ writew(1, baseAddr + Disable_IRQ);
+ writew(0, baseAddr + Magic_no);
+ for (i = 0; i < 500; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return -EIO;
+
+ if (MOXA_IS_320(brd)) {
+ j = readw(baseAddr + Module_cnt);
+ if (j <= 0)
+ return -EIO;
+ brd->numPorts = j * 8;
+ writew(j, baseAddr + Module_no);
+ writew(0, baseAddr + Magic_no);
+ for (i = 0; i < 600; i++) {
+ if (readw(baseAddr + Magic_no) == Magic_code)
+ break;
+ msleep(10);
+ }
+ if (readw(baseAddr + Magic_no) != Magic_code)
+ return -EIO;
+ }
+ brd->intNdx = baseAddr + IRQindex;
+ brd->intPend = baseAddr + IRQpending;
+ brd->intTable = baseAddr + IRQtable;
+
+ return 0;
+}
+
+static int moxa_load_code(struct moxa_board_conf *brd, const void *ptr,
+ size_t len)
+{
+ void __iomem *ofsAddr, *baseAddr = brd->basemem;
+ struct moxa_port *port;
+ int retval, i;
+
+ if (len % 2) {
+ printk(KERN_ERR "MOXA: bios length is not even\n");
+ return -EINVAL;
+ }
+
+ retval = moxa_real_load_code(brd, ptr, len); /* may change numPorts */
+ if (retval)
+ return retval;
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ case MOXA_BOARD_CP204J:
+ port = brd->ports;
+ for (i = 0; i < brd->numPorts; i++, port++) {
+ port->board = brd;
+ port->DCDState = 0;
+ port->tableAddr = baseAddr + Extern_table +
+ Extern_size * i;
+ ofsAddr = port->tableAddr;
+ writew(C218rx_mask, ofsAddr + RX_mask);
+ writew(C218tx_mask, ofsAddr + TX_mask);
+ writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
+
+ writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
+
+ }
+ break;
+ default:
+ port = brd->ports;
+ for (i = 0; i < brd->numPorts; i++, port++) {
+ port->board = brd;
+ port->DCDState = 0;
+ port->tableAddr = baseAddr + Extern_table +
+ Extern_size * i;
+ ofsAddr = port->tableAddr;
+ switch (brd->numPorts) {
+ case 8:
+ writew(C320p8rx_mask, ofsAddr + RX_mask);
+ writew(C320p8tx_mask, ofsAddr + TX_mask);
+ writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
+
+ break;
+ case 16:
+ writew(C320p16rx_mask, ofsAddr + RX_mask);
+ writew(C320p16tx_mask, ofsAddr + TX_mask);
+ writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
+ break;
+
+ case 24:
+ writew(C320p24rx_mask, ofsAddr + RX_mask);
+ writew(C320p24tx_mask, ofsAddr + TX_mask);
+ writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
+ writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
+ writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+ break;
+ case 32:
+ writew(C320p32rx_mask, ofsAddr + RX_mask);
+ writew(C320p32tx_mask, ofsAddr + TX_mask);
+ writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
+ writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
+ writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
+ writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
+ writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
+ break;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+static int moxa_load_fw(struct moxa_board_conf *brd, const struct firmware *fw)
+{
+ void *ptr = fw->data;
+ char rsn[64];
+ u16 lens[5];
+ size_t len;
+ unsigned int a, lenp, lencnt;
+ int ret = -EINVAL;
+ struct {
+ __le32 magic; /* 0x34303430 */
+ u8 reserved1[2];
+ u8 type; /* UNIX = 3 */
+ u8 model; /* C218T=1, C320T=2, CP204=3 */
+ u8 reserved2[8];
+ __le16 len[5];
+ } *hdr = ptr;
+
+ BUILD_BUG_ON(ARRAY_SIZE(hdr->len) != ARRAY_SIZE(lens));
+
+ if (fw->size < MOXA_FW_HDRLEN) {
+ strcpy(rsn, "too short (even header won't fit)");
+ goto err;
+ }
+ if (hdr->magic != cpu_to_le32(0x30343034)) {
+ sprintf(rsn, "bad magic: %.8x", le32_to_cpu(hdr->magic));
+ goto err;
+ }
+ if (hdr->type != 3) {
+ sprintf(rsn, "not for linux, type is %u", hdr->type);
+ goto err;
+ }
+ if (moxa_check_fw_model(brd, hdr->model)) {
+ sprintf(rsn, "not for this card, model is %u", hdr->model);
+ goto err;
+ }
+
+ len = MOXA_FW_HDRLEN;
+ lencnt = hdr->model == 2 ? 5 : 3;
+ for (a = 0; a < ARRAY_SIZE(lens); a++) {
+ lens[a] = le16_to_cpu(hdr->len[a]);
+ if (lens[a] && len + lens[a] <= fw->size &&
+ moxa_check_fw(&fw->data[len]))
+ printk(KERN_WARNING "MOXA firmware: unexpected input "
+ "at offset %u, but going on\n", (u32)len);
+ if (!lens[a] && a < lencnt) {
+ sprintf(rsn, "too few entries in fw file");
+ goto err;
+ }
+ len += lens[a];
+ }
+
+ if (len != fw->size) {
+ sprintf(rsn, "bad length: %u (should be %u)", (u32)fw->size,
+ (u32)len);
+ goto err;
+ }
+
+ ptr += MOXA_FW_HDRLEN;
+ lenp = 0; /* bios */
+
+ strcpy(rsn, "read above");
+
+ ret = moxa_load_bios(brd, ptr, lens[lenp]);
+ if (ret)
+ goto err;
+
+ /* we skip the tty section (lens[1]), since we don't need it */
+ ptr += lens[lenp] + lens[lenp + 1];
+ lenp += 2; /* comm */
+
+ if (hdr->model == 2) {
+ ret = moxa_load_320b(brd, ptr, lens[lenp]);
+ if (ret)
+ goto err;
+ /* skip another tty */
+ ptr += lens[lenp] + lens[lenp + 1];
+ lenp += 2;
+ }
+
+ ret = moxa_load_code(brd, ptr, lens[lenp]);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ printk(KERN_ERR "firmware failed to load, reason: %s\n", rsn);
+ return ret;
+}
+
+static int moxa_init_board(struct moxa_board_conf *brd, struct device *dev)
+{
+ const struct firmware *fw;
+ const char *file;
+ struct moxa_port *p;
+ unsigned int i;
+ int ret;
+
+ brd->ports = kcalloc(MAX_PORTS_PER_BOARD, sizeof(*brd->ports),
+ GFP_KERNEL);
+ if (brd->ports == NULL) {
+ printk(KERN_ERR "cannot allocate memory for ports\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0, p = brd->ports; i < MAX_PORTS_PER_BOARD; i++, p++) {
+ p->type = PORT_16550A;
+ p->close_delay = 5 * HZ / 10;
+ p->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
+ init_waitqueue_head(&p->open_wait);
+ }
+
+ switch (brd->boardType) {
+ case MOXA_BOARD_C218_ISA:
+ case MOXA_BOARD_C218_PCI:
+ file = "c218tunx.cod";
+ break;
+ case MOXA_BOARD_CP204J:
+ file = "cp204unx.cod";
+ break;
+ default:
+ file = "c320tunx.cod";
+ break;
+ }
+
+ ret = request_firmware(&fw, file, dev);
+ if (ret) {
+ printk(KERN_ERR "MOXA: request_firmware failed. Make sure "
+ "you've placed '%s' file into your firmware "
+ "loader directory (e.g. /lib/firmware)\n",
+ file);
+ goto err_free;
+ }
+
+ ret = moxa_load_fw(brd, fw);
+
+ release_firmware(fw);
+
+ if (ret)
+ goto err_free;
+
+ spin_lock_bh(&moxa_lock);
+ brd->ready = 1;
+ if (!timer_pending(&moxaTimer))
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
+ spin_unlock_bh(&moxa_lock);
+
+ return 0;
+err_free:
+ kfree(brd->ports);
+err:
+ return ret;
+}
+
+static void moxa_board_deinit(struct moxa_board_conf *brd)
+{
+ unsigned int a, opened;
+
+ mutex_lock(&moxa_openlock);
+ spin_lock_bh(&moxa_lock);
+ brd->ready = 0;
+ spin_unlock_bh(&moxa_lock);
+
+ /* pci hot-un-plug support */
+ for (a = 0; a < brd->numPorts; a++)
+ if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
+ tty_hangup(brd->ports[a].tty);
+ while (1) {
+ opened = 0;
+ for (a = 0; a < brd->numPorts; a++)
+ if (brd->ports[a].asyncflags & ASYNC_INITIALIZED)
+ opened++;
+ mutex_unlock(&moxa_openlock);
+ if (!opened)
+ break;
+ msleep(50);
+ mutex_lock(&moxa_openlock);
+ }
+
+ iounmap(brd->basemem);
+ brd->basemem = NULL;
+ kfree(brd->ports);
+}
+
#ifdef CONFIG_PCI
static int __devinit moxa_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -299,10 +930,17 @@
}
board = &moxa_boards[i];
- board->basemem = pci_iomap(pdev, 2, 0x4000);
+
+ retval = pci_request_region(pdev, 2, "moxa-base");
+ if (retval) {
+ dev_err(&pdev->dev, "can't request pci region 2\n");
+ goto err;
+ }
+
+ board->basemem = ioremap_nocache(pci_resource_start(pdev, 2), 0x4000);
if (board->basemem == NULL) {
dev_err(&pdev->dev, "can't remap io space 2\n");
- goto err;
+ goto err_reg;
}
board->boardType = board_type;
@@ -321,9 +959,21 @@
}
board->busType = MOXA_BUS_TYPE_PCI;
+ retval = moxa_init_board(board, &pdev->dev);
+ if (retval)
+ goto err_base;
+
pci_set_drvdata(pdev, board);
- return (0);
+ dev_info(&pdev->dev, "board '%s' ready (%u ports, firmware loaded)\n",
+ moxa_brdname[board_type - 1], board->numPorts);
+
+ return 0;
+err_base:
+ iounmap(board->basemem);
+ board->basemem = NULL;
+err_reg:
+ pci_release_region(pdev, 2);
err:
return retval;
}
@@ -332,8 +982,9 @@
{
struct moxa_board_conf *brd = pci_get_drvdata(pdev);
- pci_iounmap(pdev, brd->basemem);
- brd->basemem = NULL;
+ moxa_board_deinit(brd);
+
+ pci_release_region(pdev, 2);
}
static struct pci_driver moxa_pci_driver = {
@@ -346,8 +997,8 @@
static int __init moxa_init(void)
{
- int i, numBoards, retval = 0;
- struct moxa_port *ch;
+ unsigned int isabrds = 0;
+ int retval = 0;
printk(KERN_INFO "MOXA Intellio family driver version %s\n",
MOXA_VERSION);
@@ -368,154 +1019,176 @@
moxaDriver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(moxaDriver, &moxa_ops);
- for (i = 0, ch = moxa_ports; i < MAX_PORTS; i++, ch++) {
- ch->type = PORT_16550A;
- ch->port = i;
- ch->close_delay = 5 * HZ / 10;
- ch->closing_wait = 30 * HZ;
- ch->cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;
- init_waitqueue_head(&ch->open_wait);
- init_completion(&ch->close_wait);
-
- setup_timer(&ch->emptyTimer, moxa_check_xmit_empty,
- (unsigned long)ch);
- }
-
- pr_debug("Moxa tty devices major number = %d\n", ttymajor);
-
if (tty_register_driver(moxaDriver)) {
- printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n");
+ printk(KERN_ERR "can't register MOXA Smartio tty driver!\n");
put_tty_driver(moxaDriver);
return -1;
}
- mod_timer(&moxaTimer, jiffies + HZ / 50);
-
- /* Find the boards defined in source code */
- numBoards = 0;
- for (i = 0; i < MAX_BOARDS; i++) {
- if ((moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA) ||
- (moxa_isa_boards[i].boardType == MOXA_BOARD_C320_ISA)) {
- moxa_boards[numBoards].boardType = moxa_isa_boards[i].boardType;
- if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
- moxa_boards[numBoards].numPorts = 8;
- else
- moxa_boards[numBoards].numPorts = moxa_isa_boards[i].numPorts;
- moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
- moxa_boards[numBoards].baseAddr = moxa_isa_boards[i].baseAddr;
- pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
- numBoards + 1,
- moxa_brdname[moxa_boards[numBoards].boardType-1],
- moxa_boards[numBoards].baseAddr);
- numBoards++;
- }
- }
- /* Find the boards defined form module args. */
+ /* Find the boards defined from module args. */
#ifdef MODULE
+ {
+ struct moxa_board_conf *brd = moxa_boards;
+ unsigned int i;
for (i = 0; i < MAX_BOARDS; i++) {
- if ((type[i] == MOXA_BOARD_C218_ISA) ||
- (type[i] == MOXA_BOARD_C320_ISA)) {
+ if (!baseaddr[i])
+ break;
+ if (type[i] == MOXA_BOARD_C218_ISA ||
+ type[i] == MOXA_BOARD_C320_ISA) {
pr_debug("Moxa board %2d: %s board(baseAddr=%lx)\n",
- numBoards + 1, moxa_brdname[type[i] - 1],
- (unsigned long)baseaddr[i]);
- if (numBoards >= MAX_BOARDS) {
- printk(KERN_WARNING "More than %d MOXA "
- "Intellio family boards found. Board "
- "is ignored.\n", MAX_BOARDS);
+ isabrds + 1, moxa_brdname[type[i] - 1],
+ baseaddr[i]);
+ brd->boardType = type[i];
+ brd->numPorts = type[i] == MOXA_BOARD_C218_ISA ? 8 :
+ numports[i];
+ brd->busType = MOXA_BUS_TYPE_ISA;
+ brd->basemem = ioremap_nocache(baseaddr[i], 0x4000);
+ if (!brd->basemem) {
+ printk(KERN_ERR "MOXA: can't remap %lx\n",
+ baseaddr[i]);
continue;
}
- moxa_boards[numBoards].boardType = type[i];
- if (moxa_isa_boards[i].boardType == MOXA_BOARD_C218_ISA)
- moxa_boards[numBoards].numPorts = 8;
- else
- moxa_boards[numBoards].numPorts = numports[i];
- moxa_boards[numBoards].busType = MOXA_BUS_TYPE_ISA;
- moxa_boards[numBoards].baseAddr = baseaddr[i];
- numBoards++;
+ if (moxa_init_board(brd, NULL)) {
+ iounmap(brd->basemem);
+ brd->basemem = NULL;
+ continue;
+ }
+
+ printk(KERN_INFO "MOXA isa board found at 0x%.8lu and "
+ "ready (%u ports, firmware loaded)\n",
+ baseaddr[i], brd->numPorts);
+
+ brd++;
+ isabrds++;
}
}
+ }
#endif
#ifdef CONFIG_PCI
retval = pci_register_driver(&moxa_pci_driver);
if (retval) {
- printk(KERN_ERR "Can't register moxa pci driver!\n");
- if (numBoards)
+ printk(KERN_ERR "Can't register MOXA pci driver!\n");
+ if (isabrds)
retval = 0;
}
#endif
- for (i = 0; i < numBoards; i++) {
- moxa_boards[i].basemem = ioremap(moxa_boards[i].baseAddr,
- 0x4000);
- }
-
return retval;
}
static void __exit moxa_exit(void)
{
- int i;
-
- del_timer_sync(&moxaTimer);
-
- for (i = 0; i < MAX_PORTS; i++)
- del_timer_sync(&moxa_ports[i].emptyTimer);
-
- if (tty_unregister_driver(moxaDriver))
- printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
- "serial driver\n");
- put_tty_driver(moxaDriver);
+ unsigned int i;
#ifdef CONFIG_PCI
pci_unregister_driver(&moxa_pci_driver);
#endif
- for (i = 0; i < MAX_BOARDS; i++)
- if (moxa_boards[i].basemem)
- iounmap(moxa_boards[i].basemem);
+ for (i = 0; i < MAX_BOARDS; i++) /* ISA boards */
+ if (moxa_boards[i].ready)
+ moxa_board_deinit(&moxa_boards[i]);
+
+ del_timer_sync(&moxaTimer);
+
+ if (tty_unregister_driver(moxaDriver))
+ printk(KERN_ERR "Couldn't unregister MOXA Intellio family "
+ "serial driver\n");
+ put_tty_driver(moxaDriver);
}
module_init(moxa_init);
module_exit(moxa_exit);
+static void moxa_close_port(struct moxa_port *ch)
+{
+ moxa_shut_down(ch);
+ MoxaPortFlushData(ch, 2);
+ ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
+ ch->tty->driver_data = NULL;
+ ch->tty = NULL;
+}
+
+static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
+ struct moxa_port *ch)
+{
+ DEFINE_WAIT(wait);
+ int retval = 0;
+ u8 dcd;
+
+ while (1) {
+ prepare_to_wait(&ch->open_wait, &wait, TASK_INTERRUPTIBLE);
+ if (tty_hung_up_p(filp)) {
+#ifdef SERIAL_DO_RESTART
+ retval = -ERESTARTSYS;
+#else
+ retval = -EAGAIN;
+#endif
+ break;
+ }
+ spin_lock_bh(&moxa_lock);
+ dcd = ch->DCDState;
+ spin_unlock_bh(&moxa_lock);
+ if (dcd)
+ break;
+
+ if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+ schedule();
+ }
+ finish_wait(&ch->open_wait, &wait);
+
+ return retval;
+}
+
static int moxa_open(struct tty_struct *tty, struct file *filp)
{
+ struct moxa_board_conf *brd;
struct moxa_port *ch;
int port;
int retval;
port = tty->index;
if (port == MAX_PORTS) {
- return (0);
+ return capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
}
- if (!MoxaPortIsValid(port)) {
- tty->driver_data = NULL;
- return (-ENODEV);
+ if (mutex_lock_interruptible(&moxa_openlock))
+ return -ERESTARTSYS;
+ brd = &moxa_boards[port / MAX_PORTS_PER_BOARD];
+ if (!brd->ready) {
+ mutex_unlock(&moxa_openlock);
+ return -ENODEV;
}
- ch = &moxa_ports[port];
+ ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
ch->count++;
tty->driver_data = ch;
ch->tty = tty;
if (!(ch->asyncflags & ASYNC_INITIALIZED)) {
ch->statusflags = 0;
moxa_set_tty_param(tty, tty->termios);
- MoxaPortLineCtrl(ch->port, 1, 1);
- MoxaPortEnable(ch->port);
+ MoxaPortLineCtrl(ch, 1, 1);
+ MoxaPortEnable(ch);
+ MoxaSetFifo(ch, ch->type == PORT_16550A);
ch->asyncflags |= ASYNC_INITIALIZED;
}
- retval = moxa_block_till_ready(tty, filp, ch);
+ mutex_unlock(&moxa_openlock);
- moxa_unthrottle(tty);
+ retval = 0;
+ if (!(filp->f_flags & O_NONBLOCK) && !C_CLOCAL(tty))
+ retval = moxa_block_till_ready(tty, filp, ch);
+ mutex_lock(&moxa_openlock);
+ if (retval) {
+ if (ch->count) /* 0 means already hung up... */
+ if (--ch->count == 0)
+ moxa_close_port(ch);
+ } else
+ ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
+ mutex_unlock(&moxa_openlock);
- if (ch->type == PORT_16550A) {
- MoxaSetFifo(ch->port, 1);
- } else {
- MoxaSetFifo(ch->port, 0);
- }
-
- return (retval);
+ return retval;
}
static void moxa_close(struct tty_struct *tty, struct file *filp)
@@ -524,23 +1197,14 @@
int port;
port = tty->index;
- if (port == MAX_PORTS) {
+ if (port == MAX_PORTS || tty_hung_up_p(filp))
return;
- }
- if (!MoxaPortIsValid(port)) {
- pr_debug("Invalid portno in moxa_close\n");
- tty->driver_data = NULL;
- return;
- }
- if (tty->driver_data == NULL) {
- return;
- }
- if (tty_hung_up_p(filp)) {
- return;
- }
- ch = (struct moxa_port *) tty->driver_data;
- if ((tty->count == 1) && (ch->count != 1)) {
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (ch == NULL)
+ goto unlock;
+ if (tty->count == 1 && ch->count != 1) {
printk(KERN_WARNING "moxa_close: bad serial port count; "
"tty->count is 1, ch->count is %d\n", ch->count);
ch->count = 1;
@@ -550,59 +1214,35 @@
"device=%s\n", tty->name);
ch->count = 0;
}
- if (ch->count) {
- return;
- }
- ch->asyncflags |= ASYNC_CLOSING;
+ if (ch->count)
+ goto unlock;
ch->cflag = tty->termios->c_cflag;
if (ch->asyncflags & ASYNC_INITIALIZED) {
moxa_setup_empty_event(tty);
tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */
- del_timer_sync(&moxa_ports[ch->port].emptyTimer);
}
- moxa_shut_down(ch);
- MoxaPortFlushData(port, 2);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
-
- tty->closing = 0;
- ch->event = 0;
- ch->tty = NULL;
- if (ch->blocked_open) {
- if (ch->close_delay) {
- msleep_interruptible(jiffies_to_msecs(ch->close_delay));
- }
- wake_up_interruptible(&ch->open_wait);
- }
- ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING);
- complete_all(&ch->close_wait);
+ moxa_close_port(ch);
+unlock:
+ mutex_unlock(&moxa_openlock);
}
static int moxa_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
- struct moxa_port *ch;
- int len, port;
- unsigned long flags;
+ struct moxa_port *ch = tty->driver_data;
+ int len;
- ch = (struct moxa_port *) tty->driver_data;
if (ch == NULL)
- return (0);
- port = ch->port;
+ return 0;
- spin_lock_irqsave(&moxa_lock, flags);
- len = MoxaPortWriteData(port, (unsigned char *) buf, count);
- spin_unlock_irqrestore(&moxa_lock, flags);
+ spin_lock_bh(&moxa_lock);
+ len = MoxaPortWriteData(ch, buf, count);
+ spin_unlock_bh(&moxa_lock);
- /*********************************************
- if ( !(ch->statusflags & LOWWAIT) &&
- ((len != count) || (MoxaPortTxFree(port) <= 100)) )
- ************************************************/
ch->statusflags |= LOWWAIT;
- return (len);
+ return len;
}
static int moxa_write_room(struct tty_struct *tty)
@@ -610,27 +1250,27 @@
struct moxa_port *ch;
if (tty->stopped)
- return (0);
- ch = (struct moxa_port *) tty->driver_data;
+ return 0;
+ ch = tty->driver_data;
if (ch == NULL)
- return (0);
- return (MoxaPortTxFree(ch->port));
+ return 0;
+ return MoxaPortTxFree(ch);
}
static void moxa_flush_buffer(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
- MoxaPortFlushData(ch->port, 1);
+ MoxaPortFlushData(ch, 1);
tty_wakeup(tty);
}
static int moxa_chars_in_buffer(struct tty_struct *tty)
{
+ struct moxa_port *ch = tty->driver_data;
int chars;
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
/*
* Sigh...I have to check if driver_data is NULL here, because
@@ -639,8 +1279,9 @@
* routine. And since the open() failed, we return 0 here. TDJ
*/
if (ch == NULL)
- return (0);
- chars = MoxaPortTxQueue(ch->port);
+ return 0;
+ lock_kernel();
+ chars = MoxaPortTxQueue(ch);
if (chars) {
/*
* Make it possible to wakeup anything waiting for output
@@ -649,73 +1290,54 @@
if (!(ch->statusflags & EMPTYWAIT))
moxa_setup_empty_event(tty);
}
- return (chars);
-}
-
-static void moxa_flush_chars(struct tty_struct *tty)
-{
- /*
- * Don't think I need this, because this is called to empty the TX
- * buffer for the 16450, 16550, etc.
- */
-}
-
-static void moxa_put_char(struct tty_struct *tty, unsigned char c)
-{
- struct moxa_port *ch;
- int port;
- unsigned long flags;
-
- ch = (struct moxa_port *) tty->driver_data;
- if (ch == NULL)
- return;
- port = ch->port;
- spin_lock_irqsave(&moxa_lock, flags);
- MoxaPortWriteData(port, &c, 1);
- spin_unlock_irqrestore(&moxa_lock, flags);
- /************************************************
- if ( !(ch->statusflags & LOWWAIT) && (MoxaPortTxFree(port) <= 100) )
- *************************************************/
- ch->statusflags |= LOWWAIT;
+ unlock_kernel();
+ return chars;
}
static int moxa_tiocmget(struct tty_struct *tty, struct file *file)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
- int port;
+ struct moxa_port *ch;
int flag = 0, dtr, rts;
- port = tty->index;
- if ((port != MAX_PORTS) && (!ch))
- return (-EINVAL);
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (!ch) {
+ mutex_unlock(&moxa_openlock);
+ return -EINVAL;
+ }
- MoxaPortGetLineOut(ch->port, &dtr, &rts);
+ MoxaPortGetLineOut(ch, &dtr, &rts);
if (dtr)
flag |= TIOCM_DTR;
if (rts)
flag |= TIOCM_RTS;
- dtr = MoxaPortLineStatus(ch->port);
+ dtr = MoxaPortLineStatus(ch);
if (dtr & 1)
flag |= TIOCM_CTS;
if (dtr & 2)
flag |= TIOCM_DSR;
if (dtr & 4)
flag |= TIOCM_CD;
+ mutex_unlock(&moxa_openlock);
return flag;
}
static int moxa_tiocmset(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch;
int port;
int dtr, rts;
port = tty->index;
- if ((port != MAX_PORTS) && (!ch))
- return (-EINVAL);
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (!ch) {
+ mutex_unlock(&moxa_openlock);
+ return -EINVAL;
+ }
- MoxaPortGetLineOut(ch->port, &dtr, &rts);
+ MoxaPortGetLineOut(ch, &dtr, &rts);
if (set & TIOCM_RTS)
rts = 1;
if (set & TIOCM_DTR)
@@ -724,105 +1346,51 @@
rts = 0;
if (clear & TIOCM_DTR)
dtr = 0;
- MoxaPortLineCtrl(ch->port, dtr, rts);
+ MoxaPortLineCtrl(ch, dtr, rts);
+ mutex_unlock(&moxa_openlock);
return 0;
}
-static int moxa_ioctl(struct tty_struct *tty, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
- register int port;
- void __user *argp = (void __user *)arg;
- int retval;
-
- port = tty->index;
- if ((port != MAX_PORTS) && (!ch))
- return (-EINVAL);
-
- switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
- retval = tty_check_change(tty);
- if (retval)
- return (retval);
- moxa_setup_empty_event(tty);
- tty_wait_until_sent(tty, 0);
- if (!arg)
- MoxaPortSendBreak(ch->port, 0);
- return (0);
- case TCSBRKP: /* support for POSIX tcsendbreak() */
- retval = tty_check_change(tty);
- if (retval)
- return (retval);
- moxa_setup_empty_event(tty);
- tty_wait_until_sent(tty, 0);
- MoxaPortSendBreak(ch->port, arg);
- return (0);
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
- case TIOCSSOFTCAR:
- if(get_user(retval, (unsigned long __user *) argp))
- return -EFAULT;
- arg = retval;
- tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- if (C_CLOCAL(tty))
- ch->asyncflags &= ~ASYNC_CHECK_CD;
- else
- ch->asyncflags |= ASYNC_CHECK_CD;
- return (0);
- case TIOCGSERIAL:
- return moxa_get_serial_info(ch, argp);
-
- case TIOCSSERIAL:
- return moxa_set_serial_info(ch, argp);
- default:
- retval = MoxaDriverIoctl(cmd, arg, port);
- }
- return (retval);
-}
-
static void moxa_throttle(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
ch->statusflags |= THROTTLE;
}
static void moxa_unthrottle(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
ch->statusflags &= ~THROTTLE;
}
static void moxa_set_termios(struct tty_struct *tty,
- struct ktermios *old_termios)
+ struct ktermios *old_termios)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
moxa_set_tty_param(tty, old_termios);
- if (!(old_termios->c_cflag & CLOCAL) &&
- (tty->termios->c_cflag & CLOCAL))
+ if (!(old_termios->c_cflag & CLOCAL) && C_CLOCAL(tty))
wake_up_interruptible(&ch->open_wait);
}
static void moxa_stop(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
- MoxaPortTxDisable(ch->port);
+ MoxaPortTxDisable(ch);
ch->statusflags |= TXSTOPPED;
}
static void moxa_start(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch = tty->driver_data;
if (ch == NULL)
return;
@@ -830,91 +1398,143 @@
if (!(ch->statusflags & TXSTOPPED))
return;
- MoxaPortTxEnable(ch->port);
+ MoxaPortTxEnable(ch);
ch->statusflags &= ~TXSTOPPED;
}
static void moxa_hangup(struct tty_struct *tty)
{
- struct moxa_port *ch = (struct moxa_port *) tty->driver_data;
+ struct moxa_port *ch;
- moxa_flush_buffer(tty);
- moxa_shut_down(ch);
- ch->event = 0;
+ mutex_lock(&moxa_openlock);
+ ch = tty->driver_data;
+ if (ch == NULL) {
+ mutex_unlock(&moxa_openlock);
+ return;
+ }
ch->count = 0;
- ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- ch->tty = NULL;
+ moxa_close_port(ch);
+ mutex_unlock(&moxa_openlock);
+
wake_up_interruptible(&ch->open_wait);
}
+static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd)
+{
+ dcd = !!dcd;
+
+ if (dcd != p->DCDState && p->tty && C_CLOCAL(p->tty)) {
+ if (!dcd)
+ tty_hangup(p->tty);
+ }
+ p->DCDState = dcd;
+}
+
+static int moxa_poll_port(struct moxa_port *p, unsigned int handle,
+ u16 __iomem *ip)
+{
+ struct tty_struct *tty = p->tty;
+ void __iomem *ofsAddr;
+ unsigned int inited = p->asyncflags & ASYNC_INITIALIZED;
+ u16 intr;
+
+ if (tty) {
+ if ((p->statusflags & EMPTYWAIT) &&
+ MoxaPortTxQueue(p) == 0) {
+ p->statusflags &= ~EMPTYWAIT;
+ tty_wakeup(tty);
+ }
+ if ((p->statusflags & LOWWAIT) && !tty->stopped &&
+ MoxaPortTxQueue(p) <= WAKEUP_CHARS) {
+ p->statusflags &= ~LOWWAIT;
+ tty_wakeup(tty);
+ }
+
+ if (inited && !(p->statusflags & THROTTLE) &&
+ MoxaPortRxQueue(p) > 0) { /* RX */
+ MoxaPortReadData(p);
+ tty_schedule_flip(tty);
+ }
+ } else {
+ p->statusflags &= ~EMPTYWAIT;
+ MoxaPortFlushData(p, 0); /* flush RX */
+ }
+
+ if (!handle) /* nothing else to do */
+ return 0;
+
+ intr = readw(ip); /* port irq status */
+ if (intr == 0)
+ return 0;
+
+ writew(0, ip); /* ACK port */
+ ofsAddr = p->tableAddr;
+ if (intr & IntrTx) /* disable tx intr */
+ writew(readw(ofsAddr + HostStat) & ~WakeupTx,
+ ofsAddr + HostStat);
+
+ if (!inited)
+ return 0;
+
+ if (tty && (intr & IntrBreak) && !I_IGNBRK(tty)) { /* BREAK */
+ tty_insert_flip_char(tty, 0, TTY_BREAK);
+ tty_schedule_flip(tty);
+ }
+
+ if (intr & IntrLine)
+ moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state);
+
+ return 0;
+}
+
static void moxa_poll(unsigned long ignored)
{
- register int card;
- struct moxa_port *ch;
- struct tty_struct *tp;
- int i, ports;
+ struct moxa_board_conf *brd;
+ u16 __iomem *ip;
+ unsigned int card, port, served = 0;
- del_timer(&moxaTimer);
-
- if (MoxaDriverPoll() < 0) {
- mod_timer(&moxaTimer, jiffies + HZ / 50);
- return;
- }
+ spin_lock(&moxa_lock);
for (card = 0; card < MAX_BOARDS; card++) {
- if ((ports = MoxaPortsOfCard(card)) <= 0)
+ brd = &moxa_boards[card];
+ if (!brd->ready)
continue;
- ch = &moxa_ports[card * MAX_PORTS_PER_BOARD];
- for (i = 0; i < ports; i++, ch++) {
- if ((ch->asyncflags & ASYNC_INITIALIZED) == 0)
- continue;
- if (!(ch->statusflags & THROTTLE) &&
- (MoxaPortRxQueue(ch->port) > 0))
- moxa_receive_data(ch);
- if ((tp = ch->tty) == 0)
- continue;
- if (ch->statusflags & LOWWAIT) {
- if (MoxaPortTxQueue(ch->port) <= WAKEUP_CHARS) {
- if (!tp->stopped) {
- ch->statusflags &= ~LOWWAIT;
- tty_wakeup(tp);
- }
+
+ served++;
+
+ ip = NULL;
+ if (readb(brd->intPend) == 0xff)
+ ip = brd->intTable + readb(brd->intNdx);
+
+ for (port = 0; port < brd->numPorts; port++)
+ moxa_poll_port(&brd->ports[port], !!ip, ip + port);
+
+ if (ip)
+ writeb(0, brd->intPend); /* ACK */
+
+ if (moxaLowWaterChk) {
+ struct moxa_port *p = brd->ports;
+ for (port = 0; port < brd->numPorts; port++, p++)
+ if (p->lowChkFlag) {
+ p->lowChkFlag = 0;
+ moxa_low_water_check(p->tableAddr);
}
- }
- if (!I_IGNBRK(tp) && (MoxaPortResetBrkCnt(ch->port) > 0)) {
- tty_insert_flip_char(tp, 0, TTY_BREAK);
- tty_schedule_flip(tp);
- }
- if (MoxaPortDCDChange(ch->port)) {
- if (ch->asyncflags & ASYNC_CHECK_CD) {
- if (MoxaPortDCDON(ch->port))
- wake_up_interruptible(&ch->open_wait);
- else {
- tty_hangup(tp);
- wake_up_interruptible(&ch->open_wait);
- ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE;
- }
- }
- }
}
}
+ moxaLowWaterChk = 0;
- mod_timer(&moxaTimer, jiffies + HZ / 50);
+ if (served)
+ mod_timer(&moxaTimer, jiffies + HZ / 50);
+ spin_unlock(&moxa_lock);
}
/******************************************************************************/
static void moxa_set_tty_param(struct tty_struct *tty, struct ktermios *old_termios)
{
- register struct ktermios *ts;
- struct moxa_port *ch;
+ register struct ktermios *ts = tty->termios;
+ struct moxa_port *ch = tty->driver_data;
int rts, cts, txflow, rxflow, xany, baud;
- ch = (struct moxa_port *) tty->driver_data;
- ts = tty->termios;
- if (ts->c_cflag & CLOCAL)
- ch->asyncflags &= ~ASYNC_CHECK_CD;
- else
- ch->asyncflags |= ASYNC_CHECK_CD;
rts = cts = txflow = rxflow = xany = 0;
if (ts->c_cflag & CRTSCTS)
rts = cts = 1;
@@ -927,776 +1547,60 @@
/* Clear the features we don't support */
ts->c_cflag &= ~CMSPAR;
- MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany);
- baud = MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty));
+ MoxaPortFlowCtrl(ch, rts, cts, txflow, rxflow, xany);
+ baud = MoxaPortSetTermio(ch, ts, tty_get_baud_rate(tty));
if (baud == -1)
baud = tty_termios_baud_rate(old_termios);
/* Not put the baud rate into the termios data */
tty_encode_baud_rate(tty, baud, baud);
}
-static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp,
- struct moxa_port *ch)
-{
- DECLARE_WAITQUEUE(wait,current);
- unsigned long flags;
- int retval;
- int do_clocal = C_CLOCAL(tty);
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (tty_hung_up_p(filp) || (ch->asyncflags & ASYNC_CLOSING)) {
- if (ch->asyncflags & ASYNC_CLOSING)
- wait_for_completion_interruptible(&ch->close_wait);
-#ifdef SERIAL_DO_RESTART
- if (ch->asyncflags & ASYNC_HUP_NOTIFY)
- return (-EAGAIN);
- else
- return (-ERESTARTSYS);
-#else
- return (-EAGAIN);
-#endif
- }
- /*
- * If non-blocking mode is set, then make the check up front
- * and then exit.
- */
- if (filp->f_flags & O_NONBLOCK) {
- ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
- return (0);
- }
- /*
- * Block waiting for the carrier detect and the line to become free
- */
- retval = 0;
- add_wait_queue(&ch->open_wait, &wait);
- pr_debug("block_til_ready before block: ttys%d, count = %d\n",
- ch->port, ch->count);
- spin_lock_irqsave(&moxa_lock, flags);
- if (!tty_hung_up_p(filp))
- ch->count--;
- ch->blocked_open++;
- spin_unlock_irqrestore(&moxa_lock, flags);
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(ch->asyncflags & ASYNC_INITIALIZED)) {
-#ifdef SERIAL_DO_RESTART
- if (ch->asyncflags & ASYNC_HUP_NOTIFY)
- retval = -EAGAIN;
- else
- retval = -ERESTARTSYS;
-#else
- retval = -EAGAIN;
-#endif
- break;
- }
- if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal ||
- MoxaPortDCDON(ch->port)))
- break;
-
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- schedule();
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&ch->open_wait, &wait);
-
- spin_lock_irqsave(&moxa_lock, flags);
- if (!tty_hung_up_p(filp))
- ch->count++;
- ch->blocked_open--;
- spin_unlock_irqrestore(&moxa_lock, flags);
- pr_debug("block_til_ready after blocking: ttys%d, count = %d\n",
- ch->port, ch->count);
- if (retval)
- return (retval);
- /* FIXME: review to see if we need to use set_bit on these */
- ch->asyncflags |= ASYNC_NORMAL_ACTIVE;
- return 0;
-}
-
static void moxa_setup_empty_event(struct tty_struct *tty)
{
struct moxa_port *ch = tty->driver_data;
- unsigned long flags;
- spin_lock_irqsave(&moxa_lock, flags);
+ spin_lock_bh(&moxa_lock);
ch->statusflags |= EMPTYWAIT;
- mod_timer(&moxa_ports[ch->port].emptyTimer, jiffies + HZ);
- spin_unlock_irqrestore(&moxa_lock, flags);
-}
-
-static void moxa_check_xmit_empty(unsigned long data)
-{
- struct moxa_port *ch;
-
- ch = (struct moxa_port *) data;
- if (ch->tty && (ch->statusflags & EMPTYWAIT)) {
- if (MoxaPortTxQueue(ch->port) == 0) {
- ch->statusflags &= ~EMPTYWAIT;
- tty_wakeup(ch->tty);
- return;
- }
- mod_timer(&moxa_ports[ch->port].emptyTimer,
- round_jiffies(jiffies + HZ));
- } else
- ch->statusflags &= ~EMPTYWAIT;
+ spin_unlock_bh(&moxa_lock);
}
static void moxa_shut_down(struct moxa_port *ch)
{
- struct tty_struct *tp;
+ struct tty_struct *tp = ch->tty;
if (!(ch->asyncflags & ASYNC_INITIALIZED))
return;
- tp = ch->tty;
-
- MoxaPortDisable(ch->port);
+ MoxaPortDisable(ch);
/*
* If we're a modem control device and HUPCL is on, drop RTS & DTR.
*/
- if (tp->termios->c_cflag & HUPCL)
- MoxaPortLineCtrl(ch->port, 0, 0);
+ if (C_HUPCL(tp))
+ MoxaPortLineCtrl(ch, 0, 0);
+ spin_lock_bh(&moxa_lock);
ch->asyncflags &= ~ASYNC_INITIALIZED;
+ spin_unlock_bh(&moxa_lock);
}
-static void moxa_receive_data(struct moxa_port *ch)
-{
- struct tty_struct *tp;
- struct ktermios *ts;
- unsigned long flags;
-
- ts = NULL;
- tp = ch->tty;
- if (tp)
- ts = tp->termios;
- /**************************************************
- if ( !tp || !ts || !(ts->c_cflag & CREAD) ) {
- *****************************************************/
- if (!tp || !ts) {
- MoxaPortFlushData(ch->port, 0);
- return;
- }
- spin_lock_irqsave(&moxa_lock, flags);
- MoxaPortReadData(ch->port, tp);
- spin_unlock_irqrestore(&moxa_lock, flags);
- tty_schedule_flip(tp);
-}
-
-#define Magic_code 0x404
-
-/*
- * System Configuration
- */
-/*
- * for C218 BIOS initialization
- */
-#define C218_ConfBase 0x800
-#define C218_status (C218_ConfBase + 0) /* BIOS running status */
-#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
-#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
-#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
-#define C218check_sum (C218_ConfBase + 8) /* BYTE */
-#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
-#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
-#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
-#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
-#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
-
-#define C218_LoadBuf 0x0F00
-#define C218_KeyCode 0x218
-#define CP204J_KeyCode 0x204
-
-/*
- * for C320 BIOS initialization
- */
-#define C320_ConfBase 0x800
-#define C320_LoadBuf 0x0f00
-#define STS_init 0x05 /* for C320_status */
-
-#define C320_status C320_ConfBase + 0 /* BIOS running status */
-#define C320_diag C320_ConfBase + 2 /* diagnostic status */
-#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
-#define C320DLoad_len C320_ConfBase + 6 /* WORD */
-#define C320check_sum C320_ConfBase + 8 /* WORD */
-#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
-#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
-#define C320UART_no C320_ConfBase + 0x0e /* WORD */
-
-#define C320_KeyCode 0x320
-
-#define FixPage_addr 0x0000 /* starting addr of static page */
-#define DynPage_addr 0x2000 /* starting addr of dynamic page */
-#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
-#define Control_reg 0x1ff0 /* select page and reset control */
-#define HW_reset 0x80
-
-/*
- * Function Codes
- */
-#define FC_CardReset 0x80
-#define FC_ChannelReset 1 /* C320 firmware not supported */
-#define FC_EnableCH 2
-#define FC_DisableCH 3
-#define FC_SetParam 4
-#define FC_SetMode 5
-#define FC_SetRate 6
-#define FC_LineControl 7
-#define FC_LineStatus 8
-#define FC_XmitControl 9
-#define FC_FlushQueue 10
-#define FC_SendBreak 11
-#define FC_StopBreak 12
-#define FC_LoopbackON 13
-#define FC_LoopbackOFF 14
-#define FC_ClrIrqTable 15
-#define FC_SendXon 16
-#define FC_SetTermIrq 17 /* C320 firmware not supported */
-#define FC_SetCntIrq 18 /* C320 firmware not supported */
-#define FC_SetBreakIrq 19
-#define FC_SetLineIrq 20
-#define FC_SetFlowCtl 21
-#define FC_GenIrq 22
-#define FC_InCD180 23
-#define FC_OutCD180 24
-#define FC_InUARTreg 23
-#define FC_OutUARTreg 24
-#define FC_SetXonXoff 25
-#define FC_OutCD180CCR 26
-#define FC_ExtIQueue 27
-#define FC_ExtOQueue 28
-#define FC_ClrLineIrq 29
-#define FC_HWFlowCtl 30
-#define FC_GetClockRate 35
-#define FC_SetBaud 36
-#define FC_SetDataMode 41
-#define FC_GetCCSR 43
-#define FC_GetDataError 45
-#define FC_RxControl 50
-#define FC_ImmSend 51
-#define FC_SetXonState 52
-#define FC_SetXoffState 53
-#define FC_SetRxFIFOTrig 54
-#define FC_SetTxFIFOCnt 55
-#define FC_UnixRate 56
-#define FC_UnixResetTimer 57
-
-#define RxFIFOTrig1 0
-#define RxFIFOTrig4 1
-#define RxFIFOTrig8 2
-#define RxFIFOTrig14 3
-
-/*
- * Dual-Ported RAM
- */
-#define DRAM_global 0
-#define INT_data (DRAM_global + 0)
-#define Config_base (DRAM_global + 0x108)
-
-#define IRQindex (INT_data + 0)
-#define IRQpending (INT_data + 4)
-#define IRQtable (INT_data + 8)
-
-/*
- * Interrupt Status
- */
-#define IntrRx 0x01 /* receiver data O.K. */
-#define IntrTx 0x02 /* transmit buffer empty */
-#define IntrFunc 0x04 /* function complete */
-#define IntrBreak 0x08 /* received break */
-#define IntrLine 0x10 /* line status change
- for transmitter */
-#define IntrIntr 0x20 /* received INTR code */
-#define IntrQuit 0x40 /* received QUIT code */
-#define IntrEOF 0x80 /* received EOF code */
-
-#define IntrRxTrigger 0x100 /* rx data count reach tigger value */
-#define IntrTxTrigger 0x200 /* tx data count below trigger value */
-
-#define Magic_no (Config_base + 0)
-#define Card_model_no (Config_base + 2)
-#define Total_ports (Config_base + 4)
-#define Module_cnt (Config_base + 8)
-#define Module_no (Config_base + 10)
-#define Timer_10ms (Config_base + 14)
-#define Disable_IRQ (Config_base + 20)
-#define TMS320_PORT1 (Config_base + 22)
-#define TMS320_PORT2 (Config_base + 24)
-#define TMS320_CLOCK (Config_base + 26)
-
-/*
- * DATA BUFFER in DRAM
- */
-#define Extern_table 0x400 /* Base address of the external table
- (24 words * 64) total 3K bytes
- (24 words * 128) total 6K bytes */
-#define Extern_size 0x60 /* 96 bytes */
-#define RXrptr 0x00 /* read pointer for RX buffer */
-#define RXwptr 0x02 /* write pointer for RX buffer */
-#define TXrptr 0x04 /* read pointer for TX buffer */
-#define TXwptr 0x06 /* write pointer for TX buffer */
-#define HostStat 0x08 /* IRQ flag and general flag */
-#define FlagStat 0x0A
-#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
- /* x x x x | | | | */
- /* | | | + CTS flow */
- /* | | +--- RTS flow */
- /* | +------ TX Xon/Xoff */
- /* +--------- RX Xon/Xoff */
-#define Break_cnt 0x0E /* received break count */
-#define CD180TXirq 0x10 /* if non-0: enable TX irq */
-#define RX_mask 0x12
-#define TX_mask 0x14
-#define Ofs_rxb 0x16
-#define Ofs_txb 0x18
-#define Page_rxb 0x1A
-#define Page_txb 0x1C
-#define EndPage_rxb 0x1E
-#define EndPage_txb 0x20
-#define Data_error 0x22
-#define RxTrigger 0x28
-#define TxTrigger 0x2a
-
-#define rRXwptr 0x34
-#define Low_water 0x36
-
-#define FuncCode 0x40
-#define FuncArg 0x42
-#define FuncArg1 0x44
-
-#define C218rx_size 0x2000 /* 8K bytes */
-#define C218tx_size 0x8000 /* 32K bytes */
-
-#define C218rx_mask (C218rx_size - 1)
-#define C218tx_mask (C218tx_size - 1)
-
-#define C320p8rx_size 0x2000
-#define C320p8tx_size 0x8000
-#define C320p8rx_mask (C320p8rx_size - 1)
-#define C320p8tx_mask (C320p8tx_size - 1)
-
-#define C320p16rx_size 0x2000
-#define C320p16tx_size 0x4000
-#define C320p16rx_mask (C320p16rx_size - 1)
-#define C320p16tx_mask (C320p16tx_size - 1)
-
-#define C320p24rx_size 0x2000
-#define C320p24tx_size 0x2000
-#define C320p24rx_mask (C320p24rx_size - 1)
-#define C320p24tx_mask (C320p24tx_size - 1)
-
-#define C320p32rx_size 0x1000
-#define C320p32tx_size 0x1000
-#define C320p32rx_mask (C320p32rx_size - 1)
-#define C320p32tx_mask (C320p32tx_size - 1)
-
-#define Page_size 0x2000
-#define Page_mask (Page_size - 1)
-#define C218rx_spage 3
-#define C218tx_spage 4
-#define C218rx_pageno 1
-#define C218tx_pageno 4
-#define C218buf_pageno 5
-
-#define C320p8rx_spage 3
-#define C320p8tx_spage 4
-#define C320p8rx_pgno 1
-#define C320p8tx_pgno 4
-#define C320p8buf_pgno 5
-
-#define C320p16rx_spage 3
-#define C320p16tx_spage 4
-#define C320p16rx_pgno 1
-#define C320p16tx_pgno 2
-#define C320p16buf_pgno 3
-
-#define C320p24rx_spage 3
-#define C320p24tx_spage 4
-#define C320p24rx_pgno 1
-#define C320p24tx_pgno 1
-#define C320p24buf_pgno 2
-
-#define C320p32rx_spage 3
-#define C320p32tx_ofs C320p32rx_size
-#define C320p32tx_spage 3
-#define C320p32buf_pgno 1
-
-/*
- * Host Status
- */
-#define WakeupRx 0x01
-#define WakeupTx 0x02
-#define WakeupBreak 0x08
-#define WakeupLine 0x10
-#define WakeupIntr 0x20
-#define WakeupQuit 0x40
-#define WakeupEOF 0x80 /* used in VTIME control */
-#define WakeupRxTrigger 0x100
-#define WakeupTxTrigger 0x200
-/*
- * Flag status
- */
-#define Rx_over 0x01
-#define Xoff_state 0x02
-#define Tx_flowOff 0x04
-#define Tx_enable 0x08
-#define CTS_state 0x10
-#define DSR_state 0x20
-#define DCD_state 0x80
-/*
- * FlowControl
- */
-#define CTS_FlowCtl 1
-#define RTS_FlowCtl 2
-#define Tx_FlowCtl 4
-#define Rx_FlowCtl 8
-#define IXM_IXANY 0x10
-
-#define LowWater 128
-
-#define DTR_ON 1
-#define RTS_ON 2
-#define CTS_ON 1
-#define DSR_ON 2
-#define DCD_ON 8
-
-/* mode definition */
-#define MX_CS8 0x03
-#define MX_CS7 0x02
-#define MX_CS6 0x01
-#define MX_CS5 0x00
-
-#define MX_STOP1 0x00
-#define MX_STOP15 0x04
-#define MX_STOP2 0x08
-
-#define MX_PARNONE 0x00
-#define MX_PAREVEN 0x40
-#define MX_PARODD 0xC0
-
-/*
- * Query
- */
-
-struct mon_str {
- int tick;
- int rxcnt[MAX_PORTS];
- int txcnt[MAX_PORTS];
-};
-
-#define DCD_changed 0x01
-#define DCD_oldstate 0x80
-
-static unsigned char moxaBuff[10240];
-static int moxaLowWaterChk;
-static int moxaCard;
-static struct mon_str moxaLog;
-static int moxaFuncTout = HZ / 2;
-
-static void moxafunc(void __iomem *, int, ushort);
-static void moxa_wait_finish(void __iomem *);
-static void moxa_low_water_check(void __iomem *);
-static int moxaloadbios(int, unsigned char __user *, int);
-static int moxafindcard(int);
-static int moxaload320b(int, unsigned char __user *, int);
-static int moxaloadcode(int, unsigned char __user *, int);
-static int moxaloadc218(int, void __iomem *, int);
-static int moxaloadc320(int, void __iomem *, int, int *);
-
/*****************************************************************************
* Driver level functions: *
- * 1. MoxaDriverInit(void); *
- * 2. MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port); *
- * 3. MoxaDriverPoll(void); *
*****************************************************************************/
-void MoxaDriverInit(void)
-{
- struct moxa_port *p;
- unsigned int i;
- moxaFuncTout = HZ / 2; /* 500 mini-seconds */
- moxaCard = 0;
- moxaLog.tick = 0;
- moxaLowWaterChk = 0;
- for (i = 0; i < MAX_PORTS; i++) {
- p = &moxa_ports[i];
- p->chkPort = 0;
- p->lowChkFlag = 0;
- p->lineCtrl = 0;
- moxaLog.rxcnt[i] = 0;
- moxaLog.txcnt[i] = 0;
- }
-}
-
-#define MOXA 0x400
-#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
-#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
-#define MOXA_INIT_DRIVER (MOXA + 6) /* moxaCard=0 */
-#define MOXA_LOAD_BIOS (MOXA + 9) /* download BIOS */
-#define MOXA_FIND_BOARD (MOXA + 10) /* Check if MOXA card exist? */
-#define MOXA_LOAD_C320B (MOXA + 11) /* download 320B firmware */
-#define MOXA_LOAD_CODE (MOXA + 12) /* download firmware */
-#define MOXA_GETDATACOUNT (MOXA + 23)
-#define MOXA_GET_IOQUEUE (MOXA + 27)
-#define MOXA_FLUSH_QUEUE (MOXA + 28)
-#define MOXA_GET_CONF (MOXA + 35) /* configuration */
-#define MOXA_GET_MAJOR (MOXA + 63)
-#define MOXA_GET_CUMAJOR (MOXA + 64)
-#define MOXA_GETMSTATUS (MOXA + 65)
-
-struct dl_str {
- char __user *buf;
- int len;
- int cardno;
-};
-
-static struct dl_str dltmp;
-
-void MoxaPortFlushData(int port, int mode)
+static void MoxaPortFlushData(struct moxa_port *port, int mode)
{
void __iomem *ofsAddr;
- if ((mode < 0) || (mode > 2))
+ if (mode < 0 || mode > 2)
return;
- ofsAddr = moxa_ports[port].tableAddr;
+ ofsAddr = port->tableAddr;
moxafunc(ofsAddr, FC_FlushQueue, mode);
if (mode != 1) {
- moxa_ports[port].lowChkFlag = 0;
+ port->lowChkFlag = 0;
moxa_low_water_check(ofsAddr);
}
}
-int MoxaDriverIoctl(unsigned int cmd, unsigned long arg, int port)
-{
- int i;
- int status;
- int MoxaPortTxQueue(int), MoxaPortRxQueue(int);
- void __user *argp = (void __user *)arg;
-
- if (port == MAX_PORTS) {
- if ((cmd != MOXA_GET_CONF) && (cmd != MOXA_INIT_DRIVER) &&
- (cmd != MOXA_LOAD_BIOS) && (cmd != MOXA_FIND_BOARD) && (cmd != MOXA_LOAD_C320B) &&
- (cmd != MOXA_LOAD_CODE) && (cmd != MOXA_GETDATACOUNT) &&
- (cmd != MOXA_GET_IOQUEUE) && (cmd != MOXA_GET_MAJOR) &&
- (cmd != MOXA_GET_CUMAJOR) && (cmd != MOXA_GETMSTATUS))
- return (-EINVAL);
- }
- switch (cmd) {
- case MOXA_GET_CONF:
- if(copy_to_user(argp, &moxa_boards, MAX_BOARDS *
- sizeof(struct moxa_board_conf)))
- return -EFAULT;
- return (0);
- case MOXA_INIT_DRIVER:
- if ((int) arg == 0x404)
- MoxaDriverInit();
- return (0);
- case MOXA_GETDATACOUNT:
- moxaLog.tick = jiffies;
- if(copy_to_user(argp, &moxaLog, sizeof(struct mon_str)))
- return -EFAULT;
- return (0);
- case MOXA_FLUSH_QUEUE:
- MoxaPortFlushData(port, arg);
- return (0);
- case MOXA_GET_IOQUEUE: {
- struct moxaq_str __user *argm = argp;
- struct moxaq_str tmp;
-
- for (i = 0; i < MAX_PORTS; i++, argm++) {
- memset(&tmp, 0, sizeof(tmp));
- if (moxa_ports[i].chkPort) {
- tmp.inq = MoxaPortRxQueue(i);
- tmp.outq = MoxaPortTxQueue(i);
- }
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- return (0);
- } case MOXA_GET_OQUEUE:
- i = MoxaPortTxQueue(port);
- return put_user(i, (unsigned long __user *)argp);
- case MOXA_GET_IQUEUE:
- i = MoxaPortRxQueue(port);
- return put_user(i, (unsigned long __user *)argp);
- case MOXA_GET_MAJOR:
- if(copy_to_user(argp, &ttymajor, sizeof(int)))
- return -EFAULT;
- return 0;
- case MOXA_GET_CUMAJOR:
- i = 0;
- if(copy_to_user(argp, &i, sizeof(int)))
- return -EFAULT;
- return 0;
- case MOXA_GETMSTATUS: {
- struct mxser_mstatus __user *argm = argp;
- struct mxser_mstatus tmp;
- struct moxa_port *p;
-
- for (i = 0; i < MAX_PORTS; i++, argm++) {
- p = &moxa_ports[i];
- memset(&tmp, 0, sizeof(tmp));
- if (!p->chkPort) {
- goto copy;
- } else {
- status = MoxaPortLineStatus(p->port);
- if (status & 1)
- tmp.cts = 1;
- if (status & 2)
- tmp.dsr = 1;
- if (status & 4)
- tmp.dcd = 1;
- }
-
- if (!p->tty || !p->tty->termios)
- tmp.cflag = p->cflag;
- else
- tmp.cflag = p->tty->termios->c_cflag;
-copy:
- if (copy_to_user(argm, &tmp, sizeof(tmp)))
- return -EFAULT;
- }
- return 0;
- } default:
- return (-ENOIOCTLCMD);
- case MOXA_LOAD_BIOS:
- case MOXA_FIND_BOARD:
- case MOXA_LOAD_C320B:
- case MOXA_LOAD_CODE:
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
- break;
- }
-
- if(copy_from_user(&dltmp, argp, sizeof(struct dl_str)))
- return -EFAULT;
- if(dltmp.cardno < 0 || dltmp.cardno >= MAX_BOARDS || dltmp.len < 0)
- return -EINVAL;
-
- switch(cmd)
- {
- case MOXA_LOAD_BIOS:
- i = moxaloadbios(dltmp.cardno, dltmp.buf, dltmp.len);
- return (i);
- case MOXA_FIND_BOARD:
- return moxafindcard(dltmp.cardno);
- case MOXA_LOAD_C320B:
- moxaload320b(dltmp.cardno, dltmp.buf, dltmp.len);
- default: /* to keep gcc happy */
- return (0);
- case MOXA_LOAD_CODE:
- i = moxaloadcode(dltmp.cardno, dltmp.buf, dltmp.len);
- if (i == -1)
- return (-EFAULT);
- return (i);
-
- }
-}
-
-int MoxaDriverPoll(void)
-{
- struct moxa_board_conf *brd;
- register ushort temp;
- register int card;
- void __iomem *ofsAddr;
- void __iomem *ip;
- int port, p, ports;
-
- if (moxaCard == 0)
- return (-1);
- for (card = 0; card < MAX_BOARDS; card++) {
- brd = &moxa_boards[card];
- if (brd->loadstat == 0)
- continue;
- if ((ports = brd->numPorts) == 0)
- continue;
- if (readb(brd->intPend) == 0xff) {
- ip = brd->intTable + readb(brd->intNdx);
- p = card * MAX_PORTS_PER_BOARD;
- ports <<= 1;
- for (port = 0; port < ports; port += 2, p++) {
- if ((temp = readw(ip + port)) != 0) {
- writew(0, ip + port);
- ofsAddr = moxa_ports[p].tableAddr;
- if (temp & IntrTx)
- writew(readw(ofsAddr + HostStat) & ~WakeupTx, ofsAddr + HostStat);
- if (temp & IntrBreak) {
- moxa_ports[p].breakCnt++;
- }
- if (temp & IntrLine) {
- if (readb(ofsAddr + FlagStat) & DCD_state) {
- if ((moxa_ports[p].DCDState & DCD_oldstate) == 0)
- moxa_ports[p].DCDState = (DCD_oldstate |
- DCD_changed);
- } else {
- if (moxa_ports[p].DCDState & DCD_oldstate)
- moxa_ports[p].DCDState = DCD_changed;
- }
- }
- }
- }
- writeb(0, brd->intPend);
- }
- if (moxaLowWaterChk) {
- p = card * MAX_PORTS_PER_BOARD;
- for (port = 0; port < ports; port++, p++) {
- if (moxa_ports[p].lowChkFlag) {
- moxa_ports[p].lowChkFlag = 0;
- ofsAddr = moxa_ports[p].tableAddr;
- moxa_low_water_check(ofsAddr);
- }
- }
- }
- }
- moxaLowWaterChk = 0;
- return (0);
-}
-
-/*****************************************************************************
- * Card level function: *
- * 1. MoxaPortsOfCard(int cardno); *
- *****************************************************************************/
-int MoxaPortsOfCard(int cardno)
-{
-
- if (moxa_boards[cardno].boardType == 0)
- return (0);
- return (moxa_boards[cardno].numPorts);
-}
-
-/*****************************************************************************
- * Port level functions: *
- * 1. MoxaPortIsValid(int port); *
- * 2. MoxaPortEnable(int port); *
- * 3. MoxaPortDisable(int port); *
- * 4. MoxaPortGetMaxBaud(int port); *
- * 6. MoxaPortSetBaud(int port, long baud); *
- * 8. MoxaPortSetTermio(int port, unsigned char *termio); *
- * 9. MoxaPortGetLineOut(int port, int *dtrState, int *rtsState); *
- * 10. MoxaPortLineCtrl(int port, int dtrState, int rtsState); *
- * 11. MoxaPortFlowCtrl(int port, int rts, int cts, int rx, int tx,int xany); *
- * 12. MoxaPortLineStatus(int port); *
- * 13. MoxaPortDCDChange(int port); *
- * 14. MoxaPortDCDON(int port); *
- * 15. MoxaPortFlushData(int port, int mode); *
- * 16. MoxaPortWriteData(int port, unsigned char * buffer, int length); *
- * 17. MoxaPortReadData(int port, struct tty_struct *tty); *
- * 20. MoxaPortTxQueue(int port); *
- * 21. MoxaPortTxFree(int port); *
- * 22. MoxaPortRxQueue(int port); *
- * 24. MoxaPortTxDisable(int port); *
- * 25. MoxaPortTxEnable(int port); *
- * 27. MoxaPortResetBrkCnt(int port); *
- * 30. MoxaPortSendBreak(int port, int ticks); *
- *****************************************************************************/
/*
* Moxa Port Number Description:
*
@@ -1733,33 +1637,6 @@
* -ENOIOCTLCMD
*
*
- * Function 3: Moxa driver polling process routine.
- * Syntax:
- * int MoxaDriverPoll(void);
- *
- * return: 0 ; polling O.K.
- * -1 : no any Moxa card.
- *
- *
- * Function 4: Get the ports of this card.
- * Syntax:
- * int MoxaPortsOfCard(int cardno);
- *
- * int cardno : card number (0 - 3)
- *
- * return: 0 : this card is invalid
- * 8/16/24/32
- *
- *
- * Function 5: Check this port is valid or invalid
- * Syntax:
- * int MoxaPortIsValid(int port);
- * int port : port number (0 - 127, ref port description)
- *
- * return: 0 : this port is invalid
- * 1 : this port is valid
- *
- *
* Function 6: Enable this port to start Tx/Rx data.
* Syntax:
* void MoxaPortEnable(int port);
@@ -1772,18 +1649,9 @@
* int port : port number (0 - 127)
*
*
- * Function 8: Get the maximun available baud rate of this port.
- * Syntax:
- * long MoxaPortGetMaxBaud(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : this port is invalid
- * 38400/57600/115200 bps
- *
- *
* Function 10: Setting baud rate of this port.
* Syntax:
- * long MoxaPortSetBaud(int port, long baud);
+ * speed_t MoxaPortSetBaud(int port, speed_t baud);
* int port : port number (0 - 127)
* long baud : baud rate (50 - 115200)
*
@@ -1850,25 +1718,6 @@
* Bit 2 - DCD state (0: off, 1: on)
*
*
- * Function 17: Check the DCD state has changed since the last read
- * of this function.
- * Syntax:
- * int MoxaPortDCDChange(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : no changed
- * 1 : DCD has changed
- *
- *
- * Function 18: Check ths current DCD state is ON or not.
- * Syntax:
- * int MoxaPortDCDON(int port);
- * int port : port number (0 - 127)
- *
- * return: 0 : DCD off
- * 1 : DCD on
- *
- *
* Function 19: Flush the Rx/Tx buffer data of this port.
* Syntax:
* void MoxaPortFlushData(int port, int mode);
@@ -1942,40 +1791,20 @@
* return: 0 - .. : BREAK signal count
*
*
- * Function 34: Send out a BREAK signal.
- * Syntax:
- * void MoxaPortSendBreak(int port, int ms100);
- * int port : port number (0 - 127)
- * int ms100 : break signal time interval.
- * unit: 100 mini-second. if ms100 == 0, it will
- * send out a about 250 ms BREAK signal.
- *
*/
-int MoxaPortIsValid(int port)
-{
- if (moxaCard == 0)
- return (0);
- if (moxa_ports[port].chkPort == 0)
- return (0);
- return (1);
-}
-
-void MoxaPortEnable(int port)
+static void MoxaPortEnable(struct moxa_port *port)
{
void __iomem *ofsAddr;
- int MoxaPortLineStatus(int);
- short lowwater = 512;
+ u16 lowwater = 512;
- ofsAddr = moxa_ports[port].tableAddr;
+ ofsAddr = port->tableAddr;
writew(lowwater, ofsAddr + Low_water);
- moxa_ports[port].breakCnt = 0;
- if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
- (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+ if (MOXA_IS_320(port->board))
moxafunc(ofsAddr, FC_SetBreakIrq, 0);
- } else {
- writew(readw(ofsAddr + HostStat) | WakeupBreak, ofsAddr + HostStat);
- }
+ else
+ writew(readw(ofsAddr + HostStat) | WakeupBreak,
+ ofsAddr + HostStat);
moxafunc(ofsAddr, FC_SetLineIrq, Magic_code);
moxafunc(ofsAddr, FC_FlushQueue, 2);
@@ -1984,9 +1813,9 @@
MoxaPortLineStatus(port);
}
-void MoxaPortDisable(int port)
+static void MoxaPortDisable(struct moxa_port *port)
{
- void __iomem *ofsAddr = moxa_ports[port].tableAddr;
+ void __iomem *ofsAddr = port->tableAddr;
moxafunc(ofsAddr, FC_SetFlowCtl, 0); /* disable flow control */
moxafunc(ofsAddr, FC_ClrLineIrq, Magic_code);
@@ -1994,49 +1823,32 @@
moxafunc(ofsAddr, FC_DisableCH, Magic_code);
}
-long MoxaPortGetMaxBaud(int port)
+static speed_t MoxaPortSetBaud(struct moxa_port *port, speed_t baud)
{
- if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
- (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI))
- return (460800L);
- else
- return (921600L);
-}
+ void __iomem *ofsAddr = port->tableAddr;
+ unsigned int clock, val;
+ speed_t max;
-
-long MoxaPortSetBaud(int port, long baud)
-{
- void __iomem *ofsAddr;
- long max, clock;
- unsigned int val;
-
- if ((baud < 50L) || ((max = MoxaPortGetMaxBaud(port)) == 0))
- return (0);
- ofsAddr = moxa_ports[port].tableAddr;
+ max = MOXA_IS_320(port->board) ? 460800 : 921600;
+ if (baud < 50)
+ return 0;
if (baud > max)
baud = max;
- if (max == 38400L)
- clock = 614400L; /* for 9.8304 Mhz : max. 38400 bps */
- else if (max == 57600L)
- clock = 691200L; /* for 11.0592 Mhz : max. 57600 bps */
- else
- clock = 921600L; /* for 14.7456 Mhz : max. 115200 bps */
+ clock = 921600;
val = clock / baud;
moxafunc(ofsAddr, FC_SetBaud, val);
baud = clock / val;
- moxa_ports[port].curBaud = baud;
- return (baud);
+ return baud;
}
-int MoxaPortSetTermio(int port, struct ktermios *termio, speed_t baud)
+static int MoxaPortSetTermio(struct moxa_port *port, struct ktermios *termio,
+ speed_t baud)
{
void __iomem *ofsAddr;
tcflag_t cflag;
tcflag_t mode = 0;
- if (moxa_ports[port].chkPort == 0 || termio == 0)
- return (-1);
- ofsAddr = moxa_ports[port].tableAddr;
+ ofsAddr = port->tableAddr;
cflag = termio->c_cflag; /* termio->c_cflag */
mode = termio->c_cflag & CSIZE;
@@ -2065,13 +1877,11 @@
} else
mode |= MX_PARNONE;
- moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
+ moxafunc(ofsAddr, FC_SetDataMode, (u16)mode);
- if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
- (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
- if (baud >= 921600L)
- return (-1);
- }
+ if (MOXA_IS_320(port->board) && baud >= 921600)
+ return -1;
+
baud = MoxaPortSetBaud(port, baud);
if (termio->c_iflag & (IXON | IXOFF | IXANY)) {
@@ -2081,51 +1891,37 @@
moxa_wait_finish(ofsAddr);
}
- return (baud);
+ return baud;
}
-int MoxaPortGetLineOut(int port, int *dtrState, int *rtsState)
+static int MoxaPortGetLineOut(struct moxa_port *port, int *dtrState,
+ int *rtsState)
{
+ if (dtrState)
+ *dtrState = !!(port->lineCtrl & DTR_ON);
+ if (rtsState)
+ *rtsState = !!(port->lineCtrl & RTS_ON);
- if (!MoxaPortIsValid(port))
- return (-1);
- if (dtrState) {
- if (moxa_ports[port].lineCtrl & DTR_ON)
- *dtrState = 1;
- else
- *dtrState = 0;
- }
- if (rtsState) {
- if (moxa_ports[port].lineCtrl & RTS_ON)
- *rtsState = 1;
- else
- *rtsState = 0;
- }
- return (0);
+ return 0;
}
-void MoxaPortLineCtrl(int port, int dtr, int rts)
+static void MoxaPortLineCtrl(struct moxa_port *port, int dtr, int rts)
{
- void __iomem *ofsAddr;
- int mode;
+ u8 mode = 0;
- ofsAddr = moxa_ports[port].tableAddr;
- mode = 0;
if (dtr)
mode |= DTR_ON;
if (rts)
mode |= RTS_ON;
- moxa_ports[port].lineCtrl = mode;
- moxafunc(ofsAddr, FC_LineControl, mode);
+ port->lineCtrl = mode;
+ moxafunc(port->tableAddr, FC_LineControl, mode);
}
-void MoxaPortFlowCtrl(int port, int rts, int cts, int txflow, int rxflow, int txany)
+static void MoxaPortFlowCtrl(struct moxa_port *port, int rts, int cts,
+ int txflow, int rxflow, int txany)
{
- void __iomem *ofsAddr;
- int mode;
+ int mode = 0;
- ofsAddr = moxa_ports[port].tableAddr;
- mode = 0;
if (rts)
mode |= RTS_FlowCtl;
if (cts)
@@ -2136,81 +1932,50 @@
mode |= Rx_FlowCtl;
if (txany)
mode |= IXM_IXANY;
- moxafunc(ofsAddr, FC_SetFlowCtl, mode);
+ moxafunc(port->tableAddr, FC_SetFlowCtl, mode);
}
-int MoxaPortLineStatus(int port)
+static int MoxaPortLineStatus(struct moxa_port *port)
{
void __iomem *ofsAddr;
int val;
- ofsAddr = moxa_ports[port].tableAddr;
- if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
- (moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
+ ofsAddr = port->tableAddr;
+ if (MOXA_IS_320(port->board)) {
moxafunc(ofsAddr, FC_LineStatus, 0);
val = readw(ofsAddr + FuncArg);
} else {
val = readw(ofsAddr + FlagStat) >> 4;
}
val &= 0x0B;
- if (val & 8) {
+ if (val & 8)
val |= 4;
- if ((moxa_ports[port].DCDState & DCD_oldstate) == 0)
- moxa_ports[port].DCDState = (DCD_oldstate | DCD_changed);
- } else {
- if (moxa_ports[port].DCDState & DCD_oldstate)
- moxa_ports[port].DCDState = DCD_changed;
- }
+ spin_lock_bh(&moxa_lock);
+ moxa_new_dcdstate(port, val & 8);
+ spin_unlock_bh(&moxa_lock);
val &= 7;
- return (val);
+ return val;
}
-int MoxaPortDCDChange(int port)
+static int MoxaPortWriteData(struct moxa_port *port,
+ const unsigned char *buffer, int len)
{
- int n;
-
- if (moxa_ports[port].chkPort == 0)
- return (0);
- n = moxa_ports[port].DCDState;
- moxa_ports[port].DCDState &= ~DCD_changed;
- n &= DCD_changed;
- return (n);
-}
-
-int MoxaPortDCDON(int port)
-{
- int n;
-
- if (moxa_ports[port].chkPort == 0)
- return (0);
- if (moxa_ports[port].DCDState & DCD_oldstate)
- n = 1;
- else
- n = 0;
- return (n);
-}
-
-int MoxaPortWriteData(int port, unsigned char * buffer, int len)
-{
- int c, total, i;
- ushort tail;
- int cnt;
- ushort head, tx_mask, spage, epage;
- ushort pageno, pageofs, bufhead;
void __iomem *baseAddr, *ofsAddr, *ofs;
+ unsigned int c, total;
+ u16 head, tail, tx_mask, spage, epage;
+ u16 pageno, pageofs, bufhead;
- ofsAddr = moxa_ports[port].tableAddr;
- baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
+ ofsAddr = port->tableAddr;
+ baseAddr = port->board->basemem;
tx_mask = readw(ofsAddr + TX_mask);
spage = readw(ofsAddr + Page_txb);
epage = readw(ofsAddr + EndPage_txb);
tail = readw(ofsAddr + TXwptr);
head = readw(ofsAddr + TXrptr);
- c = (head > tail) ? (head - tail - 1)
- : (head - tail + tx_mask);
+ c = (head > tail) ? (head - tail - 1) : (head - tail + tx_mask);
if (c > len)
c = len;
- moxaLog.txcnt[port] += c;
+ moxaLog.txcnt[port->tty->index] += c;
total = c;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_txb);
@@ -2222,249 +1987,179 @@
len = tx_mask + 1 - tail;
len = (c > len) ? len : c;
ofs = baseAddr + DynPage_addr + bufhead + tail;
- for (i = 0; i < len; i++)
- writeb(*buffer++, ofs + i);
+ memcpy_toio(ofs, buffer, len);
+ buffer += len;
tail = (tail + len) & tx_mask;
c -= len;
}
- writew(tail, ofsAddr + TXwptr);
} else {
- len = c;
pageno = spage + (tail >> 13);
pageofs = tail & Page_mask;
- do {
- cnt = Page_size - pageofs;
- if (cnt > c)
- cnt = c;
- c -= cnt;
+ while (c > 0) {
+ len = Page_size - pageofs;
+ if (len > c)
+ len = c;
writeb(pageno, baseAddr + Control_reg);
ofs = baseAddr + DynPage_addr + pageofs;
- for (i = 0; i < cnt; i++)
- writeb(*buffer++, ofs + i);
- if (c == 0) {
- writew((tail + len) & tx_mask, ofsAddr + TXwptr);
- break;
- }
+ memcpy_toio(ofs, buffer, len);
+ buffer += len;
if (++pageno == epage)
pageno = spage;
pageofs = 0;
- } while (1);
+ c -= len;
+ }
+ tail = (tail + total) & tx_mask;
}
+ writew(tail, ofsAddr + TXwptr);
writeb(1, ofsAddr + CD180TXirq); /* start to send */
- return (total);
+ return total;
}
-int MoxaPortReadData(int port, struct tty_struct *tty)
+static int MoxaPortReadData(struct moxa_port *port)
{
- register ushort head, pageofs;
- int i, count, cnt, len, total, remain;
- ushort tail, rx_mask, spage, epage;
- ushort pageno, bufhead;
+ struct tty_struct *tty = port->tty;
+ unsigned char *dst;
void __iomem *baseAddr, *ofsAddr, *ofs;
+ unsigned int count, len, total;
+ u16 tail, rx_mask, spage, epage;
+ u16 pageno, pageofs, bufhead, head;
- ofsAddr = moxa_ports[port].tableAddr;
- baseAddr = moxa_boards[port / MAX_PORTS_PER_BOARD].basemem;
+ ofsAddr = port->tableAddr;
+ baseAddr = port->board->basemem;
head = readw(ofsAddr + RXrptr);
tail = readw(ofsAddr + RXwptr);
rx_mask = readw(ofsAddr + RX_mask);
spage = readw(ofsAddr + Page_rxb);
epage = readw(ofsAddr + EndPage_rxb);
- count = (tail >= head) ? (tail - head)
- : (tail - head + rx_mask + 1);
+ count = (tail >= head) ? (tail - head) : (tail - head + rx_mask + 1);
if (count == 0)
return 0;
total = count;
- remain = count - total;
- moxaLog.rxcnt[port] += total;
- count = total;
+ moxaLog.rxcnt[tty->index] += total;
if (spage == epage) {
bufhead = readw(ofsAddr + Ofs_rxb);
writew(spage, baseAddr + Control_reg);
while (count > 0) {
- if (tail >= head)
- len = tail - head;
- else
- len = rx_mask + 1 - head;
- len = (count > len) ? len : count;
ofs = baseAddr + DynPage_addr + bufhead + head;
- for (i = 0; i < len; i++)
- tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
+ len = (tail >= head) ? (tail - head) :
+ (rx_mask + 1 - head);
+ len = tty_prepare_flip_string(tty, &dst,
+ min(len, count));
+ memcpy_fromio(dst, ofs, len);
head = (head + len) & rx_mask;
count -= len;
}
- writew(head, ofsAddr + RXrptr);
} else {
- len = count;
pageno = spage + (head >> 13);
pageofs = head & Page_mask;
- do {
- cnt = Page_size - pageofs;
- if (cnt > count)
- cnt = count;
- count -= cnt;
+ while (count > 0) {
writew(pageno, baseAddr + Control_reg);
ofs = baseAddr + DynPage_addr + pageofs;
- for (i = 0; i < cnt; i++)
- tty_insert_flip_char(tty, readb(ofs + i), TTY_NORMAL);
- if (count == 0) {
- writew((head + len) & rx_mask, ofsAddr + RXrptr);
- break;
- }
- if (++pageno == epage)
+ len = tty_prepare_flip_string(tty, &dst,
+ min(Page_size - pageofs, count));
+ memcpy_fromio(dst, ofs, len);
+
+ count -= len;
+ pageofs = (pageofs + len) & Page_mask;
+ if (pageofs == 0 && ++pageno == epage)
pageno = spage;
- pageofs = 0;
- } while (1);
+ }
+ head = (head + total) & rx_mask;
}
- if ((readb(ofsAddr + FlagStat) & Xoff_state) && (remain < LowWater)) {
+ writew(head, ofsAddr + RXrptr);
+ if (readb(ofsAddr + FlagStat) & Xoff_state) {
moxaLowWaterChk = 1;
- moxa_ports[port].lowChkFlag = 1;
+ port->lowChkFlag = 1;
}
- return (total);
+ return total;
}
-int MoxaPortTxQueue(int port)
+static int MoxaPortTxQueue(struct moxa_port *port)
{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
+ void __iomem *ofsAddr = port->tableAddr;
+ u16 rptr, wptr, mask;
- ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + TXrptr);
wptr = readw(ofsAddr + TXwptr);
mask = readw(ofsAddr + TX_mask);
- len = (wptr - rptr) & mask;
- return (len);
+ return (wptr - rptr) & mask;
}
-int MoxaPortTxFree(int port)
+static int MoxaPortTxFree(struct moxa_port *port)
{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
+ void __iomem *ofsAddr = port->tableAddr;
+ u16 rptr, wptr, mask;
- ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + TXrptr);
wptr = readw(ofsAddr + TXwptr);
mask = readw(ofsAddr + TX_mask);
- len = mask - ((wptr - rptr) & mask);
- return (len);
+ return mask - ((wptr - rptr) & mask);
}
-int MoxaPortRxQueue(int port)
+static int MoxaPortRxQueue(struct moxa_port *port)
{
- void __iomem *ofsAddr;
- ushort rptr, wptr, mask;
- int len;
+ void __iomem *ofsAddr = port->tableAddr;
+ u16 rptr, wptr, mask;
- ofsAddr = moxa_ports[port].tableAddr;
rptr = readw(ofsAddr + RXrptr);
wptr = readw(ofsAddr + RXwptr);
mask = readw(ofsAddr + RX_mask);
- len = (wptr - rptr) & mask;
- return (len);
+ return (wptr - rptr) & mask;
}
-
-void MoxaPortTxDisable(int port)
+static void MoxaPortTxDisable(struct moxa_port *port)
{
- void __iomem *ofsAddr;
-
- ofsAddr = moxa_ports[port].tableAddr;
- moxafunc(ofsAddr, FC_SetXoffState, Magic_code);
+ moxafunc(port->tableAddr, FC_SetXoffState, Magic_code);
}
-void MoxaPortTxEnable(int port)
+static void MoxaPortTxEnable(struct moxa_port *port)
{
- void __iomem *ofsAddr;
-
- ofsAddr = moxa_ports[port].tableAddr;
- moxafunc(ofsAddr, FC_SetXonState, Magic_code);
-}
-
-
-int MoxaPortResetBrkCnt(int port)
-{
- ushort cnt;
- cnt = moxa_ports[port].breakCnt;
- moxa_ports[port].breakCnt = 0;
- return (cnt);
-}
-
-
-void MoxaPortSendBreak(int port, int ms100)
-{
- void __iomem *ofsAddr;
-
- ofsAddr = moxa_ports[port].tableAddr;
- if (ms100) {
- moxafunc(ofsAddr, FC_SendBreak, Magic_code);
- msleep(ms100 * 10);
- } else {
- moxafunc(ofsAddr, FC_SendBreak, Magic_code);
- msleep(250);
- }
- moxafunc(ofsAddr, FC_StopBreak, Magic_code);
+ moxafunc(port->tableAddr, FC_SetXonState, Magic_code);
}
static int moxa_get_serial_info(struct moxa_port *info,
- struct serial_struct __user *retinfo)
+ struct serial_struct __user *retinfo)
{
- struct serial_struct tmp;
-
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->port;
- tmp.port = 0;
- tmp.irq = 0;
- tmp.flags = info->asyncflags;
- tmp.baud_base = 921600;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = 0;
- tmp.hub6 = 0;
- if(copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return (0);
+ struct serial_struct tmp = {
+ .type = info->type,
+ .line = info->tty->index,
+ .flags = info->asyncflags,
+ .baud_base = 921600,
+ .close_delay = info->close_delay
+ };
+ return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;
}
static int moxa_set_serial_info(struct moxa_port *info,
- struct serial_struct __user *new_info)
+ struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
- if(copy_from_user(&new_serial, new_info, sizeof(new_serial)))
+ if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;
- if ((new_serial.irq != 0) ||
- (new_serial.port != 0) ||
-// (new_serial.type != info->type) ||
- (new_serial.custom_divisor != 0) ||
- (new_serial.baud_base != 921600))
- return (-EPERM);
+ if (new_serial.irq != 0 || new_serial.port != 0 ||
+ new_serial.custom_divisor != 0 ||
+ new_serial.baud_base != 921600)
+ return -EPERM;
if (!capable(CAP_SYS_ADMIN)) {
if (((new_serial.flags & ~ASYNC_USR_MASK) !=
(info->asyncflags & ~ASYNC_USR_MASK)))
- return (-EPERM);
- } else {
+ return -EPERM;
+ } else
info->close_delay = new_serial.close_delay * HZ / 100;
- info->closing_wait = new_serial.closing_wait * HZ / 100;
- }
new_serial.flags = (new_serial.flags & ~ASYNC_FLAGS);
new_serial.flags |= (info->asyncflags & ASYNC_FLAGS);
- if (new_serial.type == PORT_16550A) {
- MoxaSetFifo(info->port, 1);
- } else {
- MoxaSetFifo(info->port, 0);
- }
+ MoxaSetFifo(info, new_serial.type == PORT_16550A);
info->type = new_serial.type;
- return (0);
+ return 0;
}
@@ -2472,374 +2167,10 @@
/*****************************************************************************
* Static local functions: *
*****************************************************************************/
-static void moxafunc(void __iomem *ofsAddr, int cmd, ushort arg)
+
+static void MoxaSetFifo(struct moxa_port *port, int enable)
{
-
- writew(arg, ofsAddr + FuncArg);
- writew(cmd, ofsAddr + FuncCode);
- moxa_wait_finish(ofsAddr);
-}
-
-static void moxa_wait_finish(void __iomem *ofsAddr)
-{
- unsigned long i, j;
-
- i = jiffies;
- while (readw(ofsAddr + FuncCode) != 0) {
- j = jiffies;
- if ((j - i) > moxaFuncTout) {
- return;
- }
- }
-}
-
-static void moxa_low_water_check(void __iomem *ofsAddr)
-{
- int len;
- ushort rptr, wptr, mask;
-
- if (readb(ofsAddr + FlagStat) & Xoff_state) {
- rptr = readw(ofsAddr + RXrptr);
- wptr = readw(ofsAddr + RXwptr);
- mask = readw(ofsAddr + RX_mask);
- len = (wptr - rptr) & mask;
- if (len <= Low_water)
- moxafunc(ofsAddr, FC_SendXon, 0);
- }
-}
-
-static int moxaloadbios(int cardno, unsigned char __user *tmp, int len)
-{
- void __iomem *baseAddr;
- int i;
-
- if(len < 0 || len > sizeof(moxaBuff))
- return -EINVAL;
- if(copy_from_user(moxaBuff, tmp, len))
- return -EFAULT;
- baseAddr = moxa_boards[cardno].basemem;
- writeb(HW_reset, baseAddr + Control_reg); /* reset */
- msleep(10);
- for (i = 0; i < 4096; i++)
- writeb(0, baseAddr + i); /* clear fix page */
- for (i = 0; i < len; i++)
- writeb(moxaBuff[i], baseAddr + i); /* download BIOS */
- writeb(0, baseAddr + Control_reg); /* restart */
- return (0);
-}
-
-static int moxafindcard(int cardno)
-{
- void __iomem *baseAddr;
- ushort tmp;
-
- baseAddr = moxa_boards[cardno].basemem;
- switch (moxa_boards[cardno].boardType) {
- case MOXA_BOARD_C218_ISA:
- case MOXA_BOARD_C218_PCI:
- if ((tmp = readw(baseAddr + C218_key)) != C218_KeyCode) {
- return (-1);
- }
- break;
- case MOXA_BOARD_CP204J:
- if ((tmp = readw(baseAddr + C218_key)) != CP204J_KeyCode) {
- return (-1);
- }
- break;
- default:
- if ((tmp = readw(baseAddr + C320_key)) != C320_KeyCode) {
- return (-1);
- }
- if ((tmp = readw(baseAddr + C320_status)) != STS_init) {
- return (-2);
- }
- }
- return (0);
-}
-
-static int moxaload320b(int cardno, unsigned char __user *tmp, int len)
-{
- void __iomem *baseAddr;
- int i;
-
- if(len < 0 || len > sizeof(moxaBuff))
- return -EINVAL;
- if(copy_from_user(moxaBuff, tmp, len))
- return -EFAULT;
- baseAddr = moxa_boards[cardno].basemem;
- writew(len - 7168 - 2, baseAddr + C320bapi_len);
- writeb(1, baseAddr + Control_reg); /* Select Page 1 */
- for (i = 0; i < 7168; i++)
- writeb(moxaBuff[i], baseAddr + DynPage_addr + i);
- writeb(2, baseAddr + Control_reg); /* Select Page 2 */
- for (i = 0; i < (len - 7168); i++)
- writeb(moxaBuff[i + 7168], baseAddr + DynPage_addr + i);
- return (0);
-}
-
-static int moxaloadcode(int cardno, unsigned char __user *tmp, int len)
-{
- void __iomem *baseAddr, *ofsAddr;
- int retval, port, i;
-
- if(len < 0 || len > sizeof(moxaBuff))
- return -EINVAL;
- if(copy_from_user(moxaBuff, tmp, len))
- return -EFAULT;
- baseAddr = moxa_boards[cardno].basemem;
- switch (moxa_boards[cardno].boardType) {
- case MOXA_BOARD_C218_ISA:
- case MOXA_BOARD_C218_PCI:
- case MOXA_BOARD_CP204J:
- retval = moxaloadc218(cardno, baseAddr, len);
- if (retval)
- return (retval);
- port = cardno * MAX_PORTS_PER_BOARD;
- for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
- struct moxa_port *p = &moxa_ports[port];
-
- p->chkPort = 1;
- p->curBaud = 9600L;
- p->DCDState = 0;
- p->tableAddr = baseAddr + Extern_table + Extern_size * i;
- ofsAddr = p->tableAddr;
- writew(C218rx_mask, ofsAddr + RX_mask);
- writew(C218tx_mask, ofsAddr + TX_mask);
- writew(C218rx_spage + i * C218buf_pageno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C218rx_pageno, ofsAddr + EndPage_rxb);
-
- writew(C218tx_spage + i * C218buf_pageno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C218tx_pageno, ofsAddr + EndPage_txb);
-
- }
- break;
- default:
- retval = moxaloadc320(cardno, baseAddr, len,
- &moxa_boards[cardno].numPorts);
- if (retval)
- return (retval);
- port = cardno * MAX_PORTS_PER_BOARD;
- for (i = 0; i < moxa_boards[cardno].numPorts; i++, port++) {
- struct moxa_port *p = &moxa_ports[port];
-
- p->chkPort = 1;
- p->curBaud = 9600L;
- p->DCDState = 0;
- p->tableAddr = baseAddr + Extern_table + Extern_size * i;
- ofsAddr = p->tableAddr;
- if (moxa_boards[cardno].numPorts == 8) {
- writew(C320p8rx_mask, ofsAddr + RX_mask);
- writew(C320p8tx_mask, ofsAddr + TX_mask);
- writew(C320p8rx_spage + i * C320p8buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p8rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p8tx_spage + i * C320p8buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C320p8tx_pgno, ofsAddr + EndPage_txb);
-
- } else if (moxa_boards[cardno].numPorts == 16) {
- writew(C320p16rx_mask, ofsAddr + RX_mask);
- writew(C320p16tx_mask, ofsAddr + TX_mask);
- writew(C320p16rx_spage + i * C320p16buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p16rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p16tx_spage + i * C320p16buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb) + C320p16tx_pgno, ofsAddr + EndPage_txb);
-
- } else if (moxa_boards[cardno].numPorts == 24) {
- writew(C320p24rx_mask, ofsAddr + RX_mask);
- writew(C320p24tx_mask, ofsAddr + TX_mask);
- writew(C320p24rx_spage + i * C320p24buf_pgno, ofsAddr + Page_rxb);
- writew(readw(ofsAddr + Page_rxb) + C320p24rx_pgno, ofsAddr + EndPage_rxb);
- writew(C320p24tx_spage + i * C320p24buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
- } else if (moxa_boards[cardno].numPorts == 32) {
- writew(C320p32rx_mask, ofsAddr + RX_mask);
- writew(C320p32tx_mask, ofsAddr + TX_mask);
- writew(C320p32tx_ofs, ofsAddr + Ofs_txb);
- writew(C320p32rx_spage + i * C320p32buf_pgno, ofsAddr + Page_rxb);
- writew(readb(ofsAddr + Page_rxb), ofsAddr + EndPage_rxb);
- writew(C320p32tx_spage + i * C320p32buf_pgno, ofsAddr + Page_txb);
- writew(readw(ofsAddr + Page_txb), ofsAddr + EndPage_txb);
- }
- }
- break;
- }
- moxa_boards[cardno].loadstat = 1;
- return (0);
-}
-
-static int moxaloadc218(int cardno, void __iomem *baseAddr, int len)
-{
- char retry;
- int i, j, len1, len2;
- ushort usum, *ptr, keycode;
-
- if (moxa_boards[cardno].boardType == MOXA_BOARD_CP204J)
- keycode = CP204J_KeyCode;
- else
- keycode = C218_KeyCode;
- usum = 0;
- len1 = len >> 1;
- ptr = (ushort *) moxaBuff;
- for (i = 0; i < len1; i++)
- usum += le16_to_cpu(*(ptr + i));
- retry = 0;
- do {
- len1 = len >> 1;
- j = 0;
- while (len1) {
- len2 = (len1 > 2048) ? 2048 : len1;
- len1 -= len2;
- for (i = 0; i < len2 << 1; i++)
- writeb(moxaBuff[i + j], baseAddr + C218_LoadBuf + i);
- j += i;
-
- writew(len2, baseAddr + C218DLoad_len);
- writew(0, baseAddr + C218_key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + C218_key) == keycode)
- break;
- msleep(10);
- }
- if (readw(baseAddr + C218_key) != keycode) {
- return (-1);
- }
- }
- writew(0, baseAddr + C218DLoad_len);
- writew(usum, baseAddr + C218check_sum);
- writew(0, baseAddr + C218_key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + C218_key) == keycode)
- break;
- msleep(10);
- }
- retry++;
- } while ((readb(baseAddr + C218chksum_ok) != 1) && (retry < 3));
- if (readb(baseAddr + C218chksum_ok) != 1) {
- return (-1);
- }
- writew(0, baseAddr + C218_key);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code) {
- return (-1);
- }
- writew(1, baseAddr + Disable_IRQ);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 100; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code) {
- return (-1);
- }
- moxaCard = 1;
- moxa_boards[cardno].intNdx = baseAddr + IRQindex;
- moxa_boards[cardno].intPend = baseAddr + IRQpending;
- moxa_boards[cardno].intTable = baseAddr + IRQtable;
- return (0);
-}
-
-static int moxaloadc320(int cardno, void __iomem *baseAddr, int len, int *numPorts)
-{
- ushort usum;
- int i, j, wlen, len2, retry;
- ushort *uptr;
-
- usum = 0;
- wlen = len >> 1;
- uptr = (ushort *) moxaBuff;
- for (i = 0; i < wlen; i++)
- usum += le16_to_cpu(uptr[i]);
- retry = 0;
- j = 0;
- do {
- while (wlen) {
- if (wlen > 2048)
- len2 = 2048;
- else
- len2 = wlen;
- wlen -= len2;
- len2 <<= 1;
- for (i = 0; i < len2; i++)
- writeb(moxaBuff[j + i], baseAddr + C320_LoadBuf + i);
- len2 >>= 1;
- j += i;
- writew(len2, baseAddr + C320DLoad_len);
- writew(0, baseAddr + C320_key);
- for (i = 0; i < 10; i++) {
- if (readw(baseAddr + C320_key) == C320_KeyCode)
- break;
- msleep(10);
- }
- if (readw(baseAddr + C320_key) != C320_KeyCode)
- return (-1);
- }
- writew(0, baseAddr + C320DLoad_len);
- writew(usum, baseAddr + C320check_sum);
- writew(0, baseAddr + C320_key);
- for (i = 0; i < 10; i++) {
- if (readw(baseAddr + C320_key) == C320_KeyCode)
- break;
- msleep(10);
- }
- retry++;
- } while ((readb(baseAddr + C320chksum_ok) != 1) && (retry < 3));
- if (readb(baseAddr + C320chksum_ok) != 1)
- return (-1);
- writew(0, baseAddr + C320_key);
- for (i = 0; i < 600; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return (-100);
-
- if (moxa_boards[cardno].busType == MOXA_BUS_TYPE_PCI) { /* ASIC board */
- writew(0x3800, baseAddr + TMS320_PORT1);
- writew(0x3900, baseAddr + TMS320_PORT2);
- writew(28499, baseAddr + TMS320_CLOCK);
- } else {
- writew(0x3200, baseAddr + TMS320_PORT1);
- writew(0x3400, baseAddr + TMS320_PORT2);
- writew(19999, baseAddr + TMS320_CLOCK);
- }
- writew(1, baseAddr + Disable_IRQ);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 500; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return (-102);
-
- j = readw(baseAddr + Module_cnt);
- if (j <= 0)
- return (-101);
- *numPorts = j * 8;
- writew(j, baseAddr + Module_no);
- writew(0, baseAddr + Magic_no);
- for (i = 0; i < 600; i++) {
- if (readw(baseAddr + Magic_no) == Magic_code)
- break;
- msleep(10);
- }
- if (readw(baseAddr + Magic_no) != Magic_code)
- return (-102);
- moxaCard = 1;
- moxa_boards[cardno].intNdx = baseAddr + IRQindex;
- moxa_boards[cardno].intPend = baseAddr + IRQpending;
- moxa_boards[cardno].intTable = baseAddr + IRQtable;
- return (0);
-}
-
-static void MoxaSetFifo(int port, int enable)
-{
- void __iomem *ofsAddr = moxa_ports[port].tableAddr;
+ void __iomem *ofsAddr = port->tableAddr;
if (!enable) {
moxafunc(ofsAddr, FC_SetRxFIFOTrig, 0);
diff --git a/drivers/char/moxa.h b/drivers/char/moxa.h
new file mode 100644
index 0000000..87d16ce
--- /dev/null
+++ b/drivers/char/moxa.h
@@ -0,0 +1,304 @@
+#ifndef MOXA_H_FILE
+#define MOXA_H_FILE
+
+#define MOXA 0x400
+#define MOXA_GET_IQUEUE (MOXA + 1) /* get input buffered count */
+#define MOXA_GET_OQUEUE (MOXA + 2) /* get output buffered count */
+#define MOXA_GETDATACOUNT (MOXA + 23)
+#define MOXA_GET_IOQUEUE (MOXA + 27)
+#define MOXA_FLUSH_QUEUE (MOXA + 28)
+#define MOXA_GETMSTATUS (MOXA + 65)
+
+/*
+ * System Configuration
+ */
+
+#define Magic_code 0x404
+
+/*
+ * for C218 BIOS initialization
+ */
+#define C218_ConfBase 0x800
+#define C218_status (C218_ConfBase + 0) /* BIOS running status */
+#define C218_diag (C218_ConfBase + 2) /* diagnostic status */
+#define C218_key (C218_ConfBase + 4) /* WORD (0x218 for C218) */
+#define C218DLoad_len (C218_ConfBase + 6) /* WORD */
+#define C218check_sum (C218_ConfBase + 8) /* BYTE */
+#define C218chksum_ok (C218_ConfBase + 0x0a) /* BYTE (1:ok) */
+#define C218_TestRx (C218_ConfBase + 0x10) /* 8 bytes for 8 ports */
+#define C218_TestTx (C218_ConfBase + 0x18) /* 8 bytes for 8 ports */
+#define C218_RXerr (C218_ConfBase + 0x20) /* 8 bytes for 8 ports */
+#define C218_ErrFlag (C218_ConfBase + 0x28) /* 8 bytes for 8 ports */
+
+#define C218_LoadBuf 0x0F00
+#define C218_KeyCode 0x218
+#define CP204J_KeyCode 0x204
+
+/*
+ * for C320 BIOS initialization
+ */
+#define C320_ConfBase 0x800
+#define C320_LoadBuf 0x0f00
+#define STS_init 0x05 /* for C320_status */
+
+#define C320_status C320_ConfBase + 0 /* BIOS running status */
+#define C320_diag C320_ConfBase + 2 /* diagnostic status */
+#define C320_key C320_ConfBase + 4 /* WORD (0320H for C320) */
+#define C320DLoad_len C320_ConfBase + 6 /* WORD */
+#define C320check_sum C320_ConfBase + 8 /* WORD */
+#define C320chksum_ok C320_ConfBase + 0x0a /* WORD (1:ok) */
+#define C320bapi_len C320_ConfBase + 0x0c /* WORD */
+#define C320UART_no C320_ConfBase + 0x0e /* WORD */
+
+#define C320_KeyCode 0x320
+
+#define FixPage_addr 0x0000 /* starting addr of static page */
+#define DynPage_addr 0x2000 /* starting addr of dynamic page */
+#define C218_start 0x3000 /* starting addr of C218 BIOS prg */
+#define Control_reg 0x1ff0 /* select page and reset control */
+#define HW_reset 0x80
+
+/*
+ * Function Codes
+ */
+#define FC_CardReset 0x80
+#define FC_ChannelReset 1 /* C320 firmware not supported */
+#define FC_EnableCH 2
+#define FC_DisableCH 3
+#define FC_SetParam 4
+#define FC_SetMode 5
+#define FC_SetRate 6
+#define FC_LineControl 7
+#define FC_LineStatus 8
+#define FC_XmitControl 9
+#define FC_FlushQueue 10
+#define FC_SendBreak 11
+#define FC_StopBreak 12
+#define FC_LoopbackON 13
+#define FC_LoopbackOFF 14
+#define FC_ClrIrqTable 15
+#define FC_SendXon 16
+#define FC_SetTermIrq 17 /* C320 firmware not supported */
+#define FC_SetCntIrq 18 /* C320 firmware not supported */
+#define FC_SetBreakIrq 19
+#define FC_SetLineIrq 20
+#define FC_SetFlowCtl 21
+#define FC_GenIrq 22
+#define FC_InCD180 23
+#define FC_OutCD180 24
+#define FC_InUARTreg 23
+#define FC_OutUARTreg 24
+#define FC_SetXonXoff 25
+#define FC_OutCD180CCR 26
+#define FC_ExtIQueue 27
+#define FC_ExtOQueue 28
+#define FC_ClrLineIrq 29
+#define FC_HWFlowCtl 30
+#define FC_GetClockRate 35
+#define FC_SetBaud 36
+#define FC_SetDataMode 41
+#define FC_GetCCSR 43
+#define FC_GetDataError 45
+#define FC_RxControl 50
+#define FC_ImmSend 51
+#define FC_SetXonState 52
+#define FC_SetXoffState 53
+#define FC_SetRxFIFOTrig 54
+#define FC_SetTxFIFOCnt 55
+#define FC_UnixRate 56
+#define FC_UnixResetTimer 57
+
+#define RxFIFOTrig1 0
+#define RxFIFOTrig4 1
+#define RxFIFOTrig8 2
+#define RxFIFOTrig14 3
+
+/*
+ * Dual-Ported RAM
+ */
+#define DRAM_global 0
+#define INT_data (DRAM_global + 0)
+#define Config_base (DRAM_global + 0x108)
+
+#define IRQindex (INT_data + 0)
+#define IRQpending (INT_data + 4)
+#define IRQtable (INT_data + 8)
+
+/*
+ * Interrupt Status
+ */
+#define IntrRx 0x01 /* receiver data O.K. */
+#define IntrTx 0x02 /* transmit buffer empty */
+#define IntrFunc 0x04 /* function complete */
+#define IntrBreak 0x08 /* received break */
+#define IntrLine 0x10 /* line status change
+ for transmitter */
+#define IntrIntr 0x20 /* received INTR code */
+#define IntrQuit 0x40 /* received QUIT code */
+#define IntrEOF 0x80 /* received EOF code */
+
+#define IntrRxTrigger 0x100 /* rx data count reach tigger value */
+#define IntrTxTrigger 0x200 /* tx data count below trigger value */
+
+#define Magic_no (Config_base + 0)
+#define Card_model_no (Config_base + 2)
+#define Total_ports (Config_base + 4)
+#define Module_cnt (Config_base + 8)
+#define Module_no (Config_base + 10)
+#define Timer_10ms (Config_base + 14)
+#define Disable_IRQ (Config_base + 20)
+#define TMS320_PORT1 (Config_base + 22)
+#define TMS320_PORT2 (Config_base + 24)
+#define TMS320_CLOCK (Config_base + 26)
+
+/*
+ * DATA BUFFER in DRAM
+ */
+#define Extern_table 0x400 /* Base address of the external table
+ (24 words * 64) total 3K bytes
+ (24 words * 128) total 6K bytes */
+#define Extern_size 0x60 /* 96 bytes */
+#define RXrptr 0x00 /* read pointer for RX buffer */
+#define RXwptr 0x02 /* write pointer for RX buffer */
+#define TXrptr 0x04 /* read pointer for TX buffer */
+#define TXwptr 0x06 /* write pointer for TX buffer */
+#define HostStat 0x08 /* IRQ flag and general flag */
+#define FlagStat 0x0A
+#define FlowControl 0x0C /* B7 B6 B5 B4 B3 B2 B1 B0 */
+ /* x x x x | | | | */
+ /* | | | + CTS flow */
+ /* | | +--- RTS flow */
+ /* | +------ TX Xon/Xoff */
+ /* +--------- RX Xon/Xoff */
+#define Break_cnt 0x0E /* received break count */
+#define CD180TXirq 0x10 /* if non-0: enable TX irq */
+#define RX_mask 0x12
+#define TX_mask 0x14
+#define Ofs_rxb 0x16
+#define Ofs_txb 0x18
+#define Page_rxb 0x1A
+#define Page_txb 0x1C
+#define EndPage_rxb 0x1E
+#define EndPage_txb 0x20
+#define Data_error 0x22
+#define RxTrigger 0x28
+#define TxTrigger 0x2a
+
+#define rRXwptr 0x34
+#define Low_water 0x36
+
+#define FuncCode 0x40
+#define FuncArg 0x42
+#define FuncArg1 0x44
+
+#define C218rx_size 0x2000 /* 8K bytes */
+#define C218tx_size 0x8000 /* 32K bytes */
+
+#define C218rx_mask (C218rx_size - 1)
+#define C218tx_mask (C218tx_size - 1)
+
+#define C320p8rx_size 0x2000
+#define C320p8tx_size 0x8000
+#define C320p8rx_mask (C320p8rx_size - 1)
+#define C320p8tx_mask (C320p8tx_size - 1)
+
+#define C320p16rx_size 0x2000
+#define C320p16tx_size 0x4000
+#define C320p16rx_mask (C320p16rx_size - 1)
+#define C320p16tx_mask (C320p16tx_size - 1)
+
+#define C320p24rx_size 0x2000
+#define C320p24tx_size 0x2000
+#define C320p24rx_mask (C320p24rx_size - 1)
+#define C320p24tx_mask (C320p24tx_size - 1)
+
+#define C320p32rx_size 0x1000
+#define C320p32tx_size 0x1000
+#define C320p32rx_mask (C320p32rx_size - 1)
+#define C320p32tx_mask (C320p32tx_size - 1)
+
+#define Page_size 0x2000U
+#define Page_mask (Page_size - 1)
+#define C218rx_spage 3
+#define C218tx_spage 4
+#define C218rx_pageno 1
+#define C218tx_pageno 4
+#define C218buf_pageno 5
+
+#define C320p8rx_spage 3
+#define C320p8tx_spage 4
+#define C320p8rx_pgno 1
+#define C320p8tx_pgno 4
+#define C320p8buf_pgno 5
+
+#define C320p16rx_spage 3
+#define C320p16tx_spage 4
+#define C320p16rx_pgno 1
+#define C320p16tx_pgno 2
+#define C320p16buf_pgno 3
+
+#define C320p24rx_spage 3
+#define C320p24tx_spage 4
+#define C320p24rx_pgno 1
+#define C320p24tx_pgno 1
+#define C320p24buf_pgno 2
+
+#define C320p32rx_spage 3
+#define C320p32tx_ofs C320p32rx_size
+#define C320p32tx_spage 3
+#define C320p32buf_pgno 1
+
+/*
+ * Host Status
+ */
+#define WakeupRx 0x01
+#define WakeupTx 0x02
+#define WakeupBreak 0x08
+#define WakeupLine 0x10
+#define WakeupIntr 0x20
+#define WakeupQuit 0x40
+#define WakeupEOF 0x80 /* used in VTIME control */
+#define WakeupRxTrigger 0x100
+#define WakeupTxTrigger 0x200
+/*
+ * Flag status
+ */
+#define Rx_over 0x01
+#define Xoff_state 0x02
+#define Tx_flowOff 0x04
+#define Tx_enable 0x08
+#define CTS_state 0x10
+#define DSR_state 0x20
+#define DCD_state 0x80
+/*
+ * FlowControl
+ */
+#define CTS_FlowCtl 1
+#define RTS_FlowCtl 2
+#define Tx_FlowCtl 4
+#define Rx_FlowCtl 8
+#define IXM_IXANY 0x10
+
+#define LowWater 128
+
+#define DTR_ON 1
+#define RTS_ON 2
+#define CTS_ON 1
+#define DSR_ON 2
+#define DCD_ON 8
+
+/* mode definition */
+#define MX_CS8 0x03
+#define MX_CS7 0x02
+#define MX_CS6 0x01
+#define MX_CS5 0x00
+
+#define MX_STOP1 0x00
+#define MX_STOP15 0x04
+#define MX_STOP2 0x08
+
+#define MX_PARNONE 0x00
+#define MX_PAREVEN 0x40
+#define MX_PARODD 0xC0
+
+#endif
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
index ff146c2..fe2a95b 100644
--- a/drivers/char/mspec.c
+++ b/drivers/char/mspec.c
@@ -180,7 +180,7 @@
my_page = vdata->maddr[index];
vdata->maddr[index] = 0;
if (!mspec_zero_block(my_page, PAGE_SIZE))
- uncached_free_page(my_page);
+ uncached_free_page(my_page, 1);
else
printk(KERN_WARNING "mspec_close(): "
"failed to zero page %ld\n", my_page);
@@ -209,7 +209,7 @@
index = (address - vdata->vm_start) >> PAGE_SHIFT;
maddr = (volatile unsigned long) vdata->maddr[index];
if (maddr == 0) {
- maddr = uncached_alloc_page(numa_node_id());
+ maddr = uncached_alloc_page(numa_node_id(), 1);
if (maddr == 0)
return NOPFN_OOM;
@@ -218,7 +218,7 @@
vdata->count++;
vdata->maddr[index] = maddr;
} else {
- uncached_free_page(maddr);
+ uncached_free_page(maddr, 1);
maddr = vdata->maddr[index];
}
spin_unlock(&vdata->lock);
@@ -367,7 +367,7 @@
int nasid;
unsigned long phys;
- scratch_page[nid] = uncached_alloc_page(nid);
+ scratch_page[nid] = uncached_alloc_page(nid, 1);
if (scratch_page[nid] == 0)
goto free_scratch_pages;
phys = __pa(scratch_page[nid]);
@@ -414,7 +414,7 @@
free_scratch_pages:
for_each_node(nid) {
if (scratch_page[nid] != 0)
- uncached_free_page(scratch_page[nid]);
+ uncached_free_page(scratch_page[nid], 1);
}
return ret;
}
@@ -431,7 +431,7 @@
for_each_node(nid) {
if (scratch_page[nid] != 0)
- uncached_free_page(scratch_page[nid]);
+ uncached_free_page(scratch_page[nid], 1);
}
}
}
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 68c2e92..4b81a85 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -307,6 +307,200 @@
static struct mxser_mon_ext mon_data_ext;
static int mxser_set_baud_method[MXSER_PORTS + 1];
+static void mxser_enable_must_enchance_mode(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr |= MOXA_MUST_EFR_EFRB_ENABLE;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_disable_must_enchance_mode(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_EFRB_ENABLE;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_set_must_xon1_value(unsigned long baseio, u8 value)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK0;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(value, baseio + MOXA_MUST_XON1_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_set_must_xoff1_value(unsigned long baseio, u8 value)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK0;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(value, baseio + MOXA_MUST_XOFF1_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_set_must_fifo_value(struct mxser_port *info)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(info->ioaddr + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, info->ioaddr + UART_LCR);
+
+ efr = inb(info->ioaddr + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK1;
+
+ outb(efr, info->ioaddr + MOXA_MUST_EFR_REGISTER);
+ outb((u8)info->rx_high_water, info->ioaddr + MOXA_MUST_RBRTH_REGISTER);
+ outb((u8)info->rx_trigger, info->ioaddr + MOXA_MUST_RBRTI_REGISTER);
+ outb((u8)info->rx_low_water, info->ioaddr + MOXA_MUST_RBRTL_REGISTER);
+ outb(oldlcr, info->ioaddr + UART_LCR);
+}
+
+static void mxser_set_must_enum_value(unsigned long baseio, u8 value)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK2;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(value, baseio + MOXA_MUST_ENUM_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_get_must_hardware_id(unsigned long baseio, u8 *pId)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_BANK_MASK;
+ efr |= MOXA_MUST_EFR_BANK2;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ *pId = inb(baseio + MOXA_MUST_HWID_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_MASK;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_enable_must_tx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_TX_MASK;
+ efr |= MOXA_MUST_EFR_SF_TX1;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_disable_must_tx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_TX_MASK;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_enable_must_rx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_RX_MASK;
+ efr |= MOXA_MUST_EFR_SF_RX1;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
+static void mxser_disable_must_rx_software_flow_control(unsigned long baseio)
+{
+ u8 oldlcr;
+ u8 efr;
+
+ oldlcr = inb(baseio + UART_LCR);
+ outb(MOXA_MUST_ENTER_ENCHANCE, baseio + UART_LCR);
+
+ efr = inb(baseio + MOXA_MUST_EFR_REGISTER);
+ efr &= ~MOXA_MUST_EFR_SF_RX_MASK;
+
+ outb(efr, baseio + MOXA_MUST_EFR_REGISTER);
+ outb(oldlcr, baseio + UART_LCR);
+}
+
#ifdef CONFIG_PCI
static int __devinit CheckIsMoxaMust(unsigned long io)
{
@@ -314,16 +508,16 @@
int i;
outb(0, io + UART_LCR);
- DISABLE_MOXA_MUST_ENCHANCE_MODE(io);
+ mxser_disable_must_enchance_mode(io);
oldmcr = inb(io + UART_MCR);
outb(0, io + UART_MCR);
- SET_MOXA_MUST_XON1_VALUE(io, 0x11);
+ mxser_set_must_xon1_value(io, 0x11);
if ((hwid = inb(io + UART_MCR)) != 0) {
outb(oldmcr, io + UART_MCR);
return MOXA_OTHER_UART;
}
- GET_MOXA_MUST_HARDWARE_ID(io, &hwid);
+ mxser_get_must_hardware_id(io, &hwid);
for (i = 1; i < UART_INFO_NUM; i++) { /* 0 = OTHER_UART */
if (hwid == Gpci_uart_info[i].type)
return (int)hwid;
@@ -494,10 +688,10 @@
} else
quot /= newspd;
- SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, quot);
+ mxser_set_must_enum_value(info->ioaddr, quot);
} else
#endif
- SET_MOXA_MUST_ENUM_VALUE(info->ioaddr, 0);
+ mxser_set_must_enum_value(info->ioaddr, 0);
return 0;
}
@@ -553,14 +747,14 @@
if (info->board->chip_flag) {
fcr = UART_FCR_ENABLE_FIFO;
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
+ mxser_set_must_fifo_value(info);
} else
fcr = 0;
} else {
fcr = UART_FCR_ENABLE_FIFO;
if (info->board->chip_flag) {
fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
+ mxser_set_must_fifo_value(info);
} else {
switch (info->rx_trigger) {
case 1:
@@ -657,17 +851,21 @@
}
}
if (info->board->chip_flag) {
- SET_MOXA_MUST_XON1_VALUE(info->ioaddr, START_CHAR(info->tty));
- SET_MOXA_MUST_XOFF1_VALUE(info->ioaddr, STOP_CHAR(info->tty));
+ mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->tty));
+ mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->tty));
if (I_IXON(info->tty)) {
- ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_enable_must_rx_software_flow_control(
+ info->ioaddr);
} else {
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_disable_must_rx_software_flow_control(
+ info->ioaddr);
}
if (I_IXOFF(info->tty)) {
- ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_enable_must_tx_software_flow_control(
+ info->ioaddr);
} else {
- DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_disable_must_tx_software_flow_control(
+ info->ioaddr);
}
}
@@ -927,6 +1125,27 @@
return 0;
}
+static void mxser_flush_buffer(struct tty_struct *tty)
+{
+ struct mxser_port *info = tty->driver_data;
+ char fcr;
+ unsigned long flags;
+
+
+ spin_lock_irqsave(&info->slock, flags);
+ info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+ fcr = inb(info->ioaddr + UART_FCR);
+ outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
+ info->ioaddr + UART_FCR);
+ outb(fcr, info->ioaddr + UART_FCR);
+
+ spin_unlock_irqrestore(&info->slock, flags);
+
+ tty_wakeup(tty);
+}
+
+
/*
* This routine is called when the serial port gets closed. First, we
* wait for the last remaining data to be sent. Then, we unlink its
@@ -1013,9 +1232,7 @@
}
mxser_shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
-
+ mxser_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -1072,16 +1289,16 @@
return total;
}
-static void mxser_put_char(struct tty_struct *tty, unsigned char ch)
+static int mxser_put_char(struct tty_struct *tty, unsigned char ch)
{
struct mxser_port *info = tty->driver_data;
unsigned long flags;
if (!info->xmit_buf)
- return;
+ return 0;
if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
- return;
+ return 0;
spin_lock_irqsave(&info->slock, flags);
info->xmit_buf[info->xmit_head++] = ch;
@@ -1099,6 +1316,7 @@
spin_unlock_irqrestore(&info->slock, flags);
}
}
+ return 1;
}
@@ -1142,26 +1360,6 @@
return info->xmit_cnt;
}
-static void mxser_flush_buffer(struct tty_struct *tty)
-{
- struct mxser_port *info = tty->driver_data;
- char fcr;
- unsigned long flags;
-
-
- spin_lock_irqsave(&info->slock, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- fcr = inb(info->ioaddr + UART_FCR);
- outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT),
- info->ioaddr + UART_FCR);
- outb(fcr, info->ioaddr + UART_FCR);
-
- spin_unlock_irqrestore(&info->slock, flags);
-
- tty_wakeup(tty);
-}
-
/*
* ------------------------------------------------------------
* friends of mxser_ioctl()
@@ -1460,6 +1658,7 @@
struct mxser_port *port;
int result, status;
unsigned int i, j;
+ int ret = 0;
switch (cmd) {
case MOXA_GET_MAJOR:
@@ -1467,18 +1666,21 @@
case MOXA_CHKPORTENABLE:
result = 0;
-
+ lock_kernel();
for (i = 0; i < MXSER_BOARDS; i++)
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++)
if (mxser_boards[i].ports[j].ioaddr)
result |= (1 << i);
-
+ unlock_kernel();
return put_user(result, (unsigned long __user *)argp);
case MOXA_GETDATACOUNT:
+ lock_kernel();
if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ unlock_kernel();
+ return ret;
case MOXA_GETMSTATUS:
+ lock_kernel();
for (i = 0; i < MXSER_BOARDS; i++)
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
port = &mxser_boards[i].ports[j];
@@ -1515,6 +1717,7 @@
else
GMStatus[i].cts = 0;
}
+ unlock_kernel();
if (copy_to_user(argp, GMStatus,
sizeof(struct mxser_mstatus) * MXSER_PORTS))
return -EFAULT;
@@ -1524,7 +1727,8 @@
unsigned long opmode;
unsigned cflag, iflag;
- for (i = 0; i < MXSER_BOARDS; i++)
+ lock_kernel();
+ for (i = 0; i < MXSER_BOARDS; i++) {
for (j = 0; j < MXSER_PORTS_PER_BOARD; j++) {
port = &mxser_boards[i].ports[j];
if (!port->ioaddr)
@@ -1589,13 +1793,14 @@
mon_data_ext.iftype[i] = opmode;
}
- if (copy_to_user(argp, &mon_data_ext,
- sizeof(mon_data_ext)))
- return -EFAULT;
-
- return 0;
-
- } default:
+ }
+ unlock_kernel();
+ if (copy_to_user(argp, &mon_data_ext,
+ sizeof(mon_data_ext)))
+ return -EFAULT;
+ return 0;
+ }
+ default:
return -ENOIOCTLCMD;
}
return 0;
@@ -1651,16 +1856,20 @@
opmode != RS422_MODE &&
opmode != RS485_4WIRE_MODE)
return -EFAULT;
+ lock_kernel();
mask = ModeMask[p];
shiftbit = p * 2;
val = inb(info->opmode_ioaddr);
val &= mask;
val |= (opmode << shiftbit);
outb(val, info->opmode_ioaddr);
+ unlock_kernel();
} else {
+ lock_kernel();
shiftbit = p * 2;
opmode = inb(info->opmode_ioaddr) >> shiftbit;
opmode &= OP_MODE_MASK;
+ unlock_kernel();
if (put_user(opmode, (int __user *)argp))
return -EFAULT;
}
@@ -1687,19 +1896,18 @@
tty_wait_until_sent(tty, 0);
mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
return 0;
- case TIOCGSOFTCAR:
- return put_user(!!C_CLOCAL(tty), (unsigned long __user *)argp);
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *)argp))
- return -EFAULT;
- tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0));
- return 0;
case TIOCGSERIAL:
- return mxser_get_serial_info(info, argp);
+ lock_kernel();
+ retval = mxser_get_serial_info(info, argp);
+ unlock_kernel();
+ return retval;
case TIOCSSERIAL:
- return mxser_set_serial_info(info, argp);
+ lock_kernel();
+ retval = mxser_set_serial_info(info, argp);
+ unlock_kernel();
+ return retval;
case TIOCSERGETLSR: /* Get line status register */
- return mxser_get_lsr_info(info, argp);
+ return mxser_get_lsr_info(info, argp);
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
@@ -1746,24 +1954,27 @@
case MOXA_HighSpeedOn:
return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
case MOXA_SDS_RSTICOUNTER:
+ lock_kernel();
info->mon_data.rxcnt = 0;
info->mon_data.txcnt = 0;
+ unlock_kernel();
return 0;
case MOXA_ASPP_OQUEUE:{
int len, lsr;
+ lock_kernel();
len = mxser_chars_in_buffer(tty);
-
lsr = inb(info->ioaddr + UART_LSR) & UART_LSR_TEMT;
-
len += (lsr ? 0 : 1);
+ unlock_kernel();
return put_user(len, (int __user *)argp);
}
case MOXA_ASPP_MON: {
int mcr, status;
+ lock_kernel();
status = mxser_get_msr(info->ioaddr, 1, tty->index);
mxser_check_modem_status(info, status);
@@ -1782,7 +1993,7 @@
info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD;
else
info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD;
-
+ unlock_kernel();
if (copy_to_user(argp, &info->mon_data,
sizeof(struct mxser_mon)))
return -EFAULT;
@@ -1925,7 +2136,8 @@
if (info->board->chip_flag) {
spin_lock_irqsave(&info->slock, flags);
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->ioaddr);
+ mxser_disable_must_rx_software_flow_control(
+ info->ioaddr);
spin_unlock_irqrestore(&info->slock, flags);
}
@@ -1979,6 +2191,7 @@
timeout, char_time);
printk("jiff=%lu...", jiffies);
#endif
+ lock_kernel();
while (!((lsr = inb(info->ioaddr + UART_LSR)) & UART_LSR_TEMT)) {
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
@@ -1990,6 +2203,7 @@
break;
}
set_current_state(TASK_RUNNING);
+ unlock_kernel();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
@@ -2342,7 +2556,7 @@
/* Enhance mode enabled here */
if (brd->chip_flag != MOXA_OTHER_UART)
- ENABLE_MOXA_MUST_ENCHANCE_MODE(info->ioaddr);
+ mxser_enable_must_enchance_mode(info->ioaddr);
info->flags = ASYNC_SHARE_IRQ;
info->type = brd->uart_type;
diff --git a/drivers/char/mxser.h b/drivers/char/mxser.h
index 8441711..41878a6 100644
--- a/drivers/char/mxser.h
+++ b/drivers/char/mxser.h
@@ -147,141 +147,4 @@
/* Rx software flow control mask */
#define MOXA_MUST_EFR_SF_RX_MASK 0x03
-#define ENABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr |= MOXA_MUST_EFR_EFRB_ENABLE; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define DISABLE_MOXA_MUST_ENCHANCE_MODE(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_EFRB_ENABLE; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_XON1_VALUE(baseio, Value) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_XON1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_XOFF1_VALUE(baseio, Value) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK0; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_XOFF1_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_FIFO_VALUE(info) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((info)->ioaddr+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (info)->ioaddr+UART_LCR);\
- __efr = inb((info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK1; \
- outb(__efr, (info)->ioaddr+MOXA_MUST_EFR_REGISTER); \
- outb((u8)((info)->rx_high_water), (info)->ioaddr+ \
- MOXA_MUST_RBRTH_REGISTER); \
- outb((u8)((info)->rx_trigger), (info)->ioaddr+ \
- MOXA_MUST_RBRTI_REGISTER); \
- outb((u8)((info)->rx_low_water), (info)->ioaddr+ \
- MOXA_MUST_RBRTL_REGISTER); \
- outb(__oldlcr, (info)->ioaddr+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_ENUM_VALUE(baseio, Value) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK2; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb((u8)(Value), (baseio)+MOXA_MUST_ENUM_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define GET_MOXA_MUST_HARDWARE_ID(baseio, pId) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_BANK_MASK; \
- __efr |= MOXA_MUST_EFR_BANK2; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- *pId = inb((baseio)+MOXA_MUST_HWID_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
- __efr |= MOXA_MUST_EFR_SF_TX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_TX_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
- __efr |= MOXA_MUST_EFR_SF_RX1; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
-#define DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(baseio) do { \
- u8 __oldlcr, __efr; \
- __oldlcr = inb((baseio)+UART_LCR); \
- outb(MOXA_MUST_ENTER_ENCHANCE, (baseio)+UART_LCR); \
- __efr = inb((baseio)+MOXA_MUST_EFR_REGISTER); \
- __efr &= ~MOXA_MUST_EFR_SF_RX_MASK; \
- outb(__efr, (baseio)+MOXA_MUST_EFR_REGISTER); \
- outb(__oldlcr, (baseio)+UART_LCR); \
-} while (0)
-
#endif
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 06803ed..a35bfd7 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -342,12 +342,10 @@
#endif
/* Flush any pending characters in the driver and discipline. */
-
if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer (tty);
+ tty->ldisc.flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer (tty);
+ tty_driver_flush_buffer(tty);
if (debuglevel >= DEBUG_LEVEL_INFO)
printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
@@ -399,7 +397,7 @@
/* Send the next block of data to device */
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- actual = tty->driver->write(tty, tbuf->buf, tbuf->count);
+ actual = tty->ops->write(tty, tbuf->buf, tbuf->count);
/* rollback was possible and has been done */
if (actual == -ERESTARTSYS) {
@@ -578,26 +576,36 @@
return -EFAULT;
}
+ lock_kernel();
+
for (;;) {
- if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
+ if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
+ unlock_kernel();
return -EIO;
+ }
n_hdlc = tty2n_hdlc (tty);
if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
- tty != n_hdlc->tty)
+ tty != n_hdlc->tty) {
+ unlock_kernel();
return 0;
+ }
rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
if (rbuf)
break;
/* no data */
- if (file->f_flags & O_NONBLOCK)
+ if (file->f_flags & O_NONBLOCK) {
+ unlock_kernel();
return -EAGAIN;
+ }
interruptible_sleep_on (&tty->read_wait);
- if (signal_pending(current))
+ if (signal_pending(current)) {
+ unlock_kernel();
return -EINTR;
+ }
}
if (rbuf->count > nr)
@@ -618,7 +626,7 @@
kfree(rbuf);
else
n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
-
+ unlock_kernel();
return ret;
} /* end of n_hdlc_tty_read() */
@@ -661,6 +669,8 @@
count = maxframe;
}
+ lock_kernel();
+
add_wait_queue(&tty->write_wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
@@ -695,7 +705,7 @@
n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
n_hdlc_send_frames(n_hdlc,tty);
}
-
+ unlock_kernel();
return error;
} /* end of n_hdlc_tty_write() */
@@ -740,8 +750,7 @@
case TIOCOUTQ:
/* get the pending tx byte count in the driver */
- count = tty->driver->chars_in_buffer ?
- tty->driver->chars_in_buffer(tty) : 0;
+ count = tty_chars_in_buffer(tty);
/* add size of next output frame in queue */
spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
if (n_hdlc->tx_buf_list.head)
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index 6b918b8..9021690 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -376,8 +376,9 @@
if (tty == NULL)
return;
- if (tty->driver->put_char) {
- tty->driver->put_char(tty, ch);
+ /* FIXME: put_char should not be called from an IRQ */
+ if (tty->ops->put_char) {
+ tty->ops->put_char(tty, ch);
}
pInfo->bcc ^= ch;
}
@@ -386,12 +387,9 @@
{
struct tty_struct *tty = pInfo->tty;
- if (tty == NULL)
+ if (tty == NULL || tty->ops->flush_chars == NULL)
return;
-
- if (tty->driver->flush_chars) {
- tty->driver->flush_chars(tty);
- }
+ tty->ops->flush_chars(tty);
}
static void trigger_transmit(struct r3964_info *pInfo)
@@ -449,12 +447,11 @@
struct r3964_block_header *pBlock = pInfo->tx_first;
int room = 0;
- if ((tty == NULL) || (pBlock == NULL)) {
+ if (tty == NULL || pBlock == NULL) {
return;
}
- if (tty->driver->write_room)
- room = tty->driver->write_room(tty);
+ room = tty_write_room(tty);
TRACE_PS("transmit_block %p, room %d, length %d",
pBlock, room, pBlock->length);
@@ -1075,12 +1072,15 @@
TRACE_L("read()");
+ lock_kernel();
+
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
pMsg = remove_msg(pInfo, pClient);
if (pMsg == NULL) {
/* no messages available. */
if (file->f_flags & O_NONBLOCK) {
+ unlock_kernel();
return -EAGAIN;
}
/* block until there is a message: */
@@ -1090,8 +1090,10 @@
/* If we still haven't got a message, we must have been signalled */
- if (!pMsg)
+ if (!pMsg) {
+ unlock_kernel();
return -EINTR;
+ }
/* deliver msg to client process: */
theMsg.msg_id = pMsg->msg_id;
@@ -1102,12 +1104,15 @@
kfree(pMsg);
TRACE_M("r3964_read - msg kfree %p", pMsg);
- if (copy_to_user(buf, &theMsg, count))
+ if (copy_to_user(buf, &theMsg, count)) {
+ unlock_kernel();
return -EFAULT;
+ }
TRACE_PS("read - return %d", count);
return count;
}
+ unlock_kernel();
return -EPERM;
}
@@ -1156,6 +1161,8 @@
pHeader->locks = 0;
pHeader->owner = NULL;
+ lock_kernel();
+
pClient = findClient(pInfo, task_pid(current));
if (pClient) {
pHeader->owner = pClient;
@@ -1173,6 +1180,8 @@
add_tx_queue(pInfo, pHeader);
trigger_transmit(pInfo);
+ unlock_kernel();
+
return 0;
}
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 0c09409..19105ec 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -147,10 +147,8 @@
static void check_unthrottle(struct tty_struct *tty)
{
- if (tty->count &&
- test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ if (tty->count)
+ tty_unthrottle(tty);
}
/**
@@ -183,22 +181,24 @@
* at hangup) or when the N_TTY line discipline internally has to
* clean the pending queue (for example some signals).
*
- * FIXME: tty->ctrl_status is not spinlocked and relies on
- * lock_kernel() still.
+ * Locking: ctrl_lock
*/
static void n_tty_flush_buffer(struct tty_struct *tty)
{
+ unsigned long flags;
/* clear everything and unthrottle the driver */
reset_buffer_flags(tty);
if (!tty->link)
return;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->link->packet) {
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
wake_up_interruptible(&tty->link->read_wait);
}
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
/**
@@ -264,17 +264,18 @@
* relevant in the world today. If you ever need them, add them here.
*
* Called from both the receive and transmit sides and can be called
- * re-entrantly. Relies on lock_kernel() still.
+ * re-entrantly. Relies on lock_kernel() for tty->column state.
*/
static int opost(unsigned char c, struct tty_struct *tty)
{
int space, spaces;
- space = tty->driver->write_room(tty);
+ space = tty_write_room(tty);
if (!space)
return -1;
+ lock_kernel();
if (O_OPOST(tty)) {
switch (c) {
case '\n':
@@ -283,7 +284,7 @@
if (O_ONLCR(tty)) {
if (space < 2)
return -1;
- tty->driver->put_char(tty, '\r');
+ tty_put_char(tty, '\r');
tty->column = 0;
}
tty->canon_column = tty->column;
@@ -305,7 +306,7 @@
if (space < spaces)
return -1;
tty->column += spaces;
- tty->driver->write(tty, " ", spaces);
+ tty->ops->write(tty, " ", spaces);
return 0;
}
tty->column += spaces;
@@ -322,7 +323,8 @@
break;
}
}
- tty->driver->put_char(tty, c);
+ tty_put_char(tty, c);
+ unlock_kernel();
return 0;
}
@@ -337,7 +339,8 @@
* the simple cases normally found and helps to generate blocks of
* symbols for the console driver and thus improve performance.
*
- * Called from write_chan under the tty layer write lock.
+ * Called from write_chan under the tty layer write lock. Relies
+ * on lock_kernel for the tty->column state.
*/
static ssize_t opost_block(struct tty_struct *tty,
@@ -347,12 +350,13 @@
int i;
const unsigned char *cp;
- space = tty->driver->write_room(tty);
+ space = tty_write_room(tty);
if (!space)
return 0;
if (nr > space)
nr = space;
+ lock_kernel();
for (i = 0, cp = buf; i < nr; i++, cp++) {
switch (*cp) {
case '\n':
@@ -384,27 +388,15 @@
}
}
break_out:
- if (tty->driver->flush_chars)
- tty->driver->flush_chars(tty);
- i = tty->driver->write(tty, buf, i);
+ if (tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
+ i = tty->ops->write(tty, buf, i);
+ unlock_kernel();
return i;
}
/**
- * put_char - write character to driver
- * @c: character (or part of unicode symbol)
- * @tty: terminal device
- *
- * Queue a byte to the driver layer for output
- */
-
-static inline void put_char(unsigned char c, struct tty_struct *tty)
-{
- tty->driver->put_char(tty, c);
-}
-
-/**
* echo_char - echo characters
* @c: unicode byte to echo
* @tty: terminal device
@@ -416,8 +408,8 @@
static void echo_char(unsigned char c, struct tty_struct *tty)
{
if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') {
- put_char('^', tty);
- put_char(c ^ 0100, tty);
+ tty_put_char(tty, '^');
+ tty_put_char(tty, c ^ 0100);
tty->column += 2;
} else
opost(c, tty);
@@ -426,7 +418,7 @@
static inline void finish_erasing(struct tty_struct *tty)
{
if (tty->erasing) {
- put_char('/', tty);
+ tty_put_char(tty, '/');
tty->column++;
tty->erasing = 0;
}
@@ -510,7 +502,7 @@
if (L_ECHO(tty)) {
if (L_ECHOPRT(tty)) {
if (!tty->erasing) {
- put_char('\\', tty);
+ tty_put_char(tty, '\\');
tty->column++;
tty->erasing = 1;
}
@@ -518,7 +510,7 @@
echo_char(c, tty);
while (--cnt > 0) {
head = (head+1) & (N_TTY_BUF_SIZE-1);
- put_char(tty->read_buf[head], tty);
+ tty_put_char(tty, tty->read_buf[head]);
}
} else if (kill_type == ERASE && !L_ECHOE(tty)) {
echo_char(ERASE_CHAR(tty), tty);
@@ -546,22 +538,22 @@
/* Now backup to that column. */
while (tty->column > col) {
/* Can't use opost here. */
- put_char('\b', tty);
+ tty_put_char(tty, '\b');
if (tty->column > 0)
tty->column--;
}
} else {
if (iscntrl(c) && L_ECHOCTL(tty)) {
- put_char('\b', tty);
- put_char(' ', tty);
- put_char('\b', tty);
+ tty_put_char(tty, '\b');
+ tty_put_char(tty, ' ');
+ tty_put_char(tty, '\b');
if (tty->column > 0)
tty->column--;
}
if (!iscntrl(c) || L_ECHOCTL(tty)) {
- put_char('\b', tty);
- put_char(' ', tty);
- put_char('\b', tty);
+ tty_put_char(tty, '\b');
+ tty_put_char(tty, ' ');
+ tty_put_char(tty, '\b');
if (tty->column > 0)
tty->column--;
}
@@ -592,8 +584,7 @@
kill_pgrp(tty->pgrp, sig, 1);
if (flush || !L_NOFLSH(tty)) {
n_tty_flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
}
}
@@ -701,7 +692,7 @@
if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) ||
- c == INTR_CHAR(tty) || c == QUIT_CHAR(tty)))
+ c == INTR_CHAR(tty) || c == QUIT_CHAR(tty) || c == SUSP_CHAR(tty)))
start_tty(tty);
if (tty->closing) {
@@ -725,7 +716,7 @@
tty->lnext = 0;
if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
- put_char('\a', tty); /* beep if no space */
+ tty_put_char(tty, '\a'); /* beep if no space */
return;
}
/* Record the column of first canon char. */
@@ -739,13 +730,6 @@
return;
}
- if (c == '\r') {
- if (I_IGNCR(tty))
- return;
- if (I_ICRNL(tty))
- c = '\n';
- } else if (c == '\n' && I_INLCR(tty))
- c = '\r';
if (I_IXON(tty)) {
if (c == START_CHAR(tty)) {
start_tty(tty);
@@ -756,6 +740,7 @@
return;
}
}
+
if (L_ISIG(tty)) {
int signal;
signal = SIGINT;
@@ -775,8 +760,7 @@
*/
if (!L_NOFLSH(tty)) {
n_tty_flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
}
if (L_ECHO(tty))
echo_char(c, tty);
@@ -785,6 +769,15 @@
return;
}
}
+
+ if (c == '\r') {
+ if (I_IGNCR(tty))
+ return;
+ if (I_ICRNL(tty))
+ c = '\n';
+ } else if (c == '\n' && I_INLCR(tty))
+ c = '\r';
+
if (tty->icanon) {
if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
(c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
@@ -796,8 +789,8 @@
if (L_ECHO(tty)) {
finish_erasing(tty);
if (L_ECHOCTL(tty)) {
- put_char('^', tty);
- put_char('\b', tty);
+ tty_put_char(tty, '^');
+ tty_put_char(tty, '\b');
}
}
return;
@@ -818,7 +811,7 @@
if (c == '\n') {
if (L_ECHO(tty) || L_ECHONL(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
- put_char('\a', tty);
+ tty_put_char(tty, '\a');
opost('\n', tty);
}
goto handle_newline;
@@ -836,7 +829,7 @@
*/
if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
- put_char('\a', tty);
+ tty_put_char(tty, '\a');
/* Record the column of first canon char. */
if (tty->canon_head == tty->read_head)
tty->canon_column = tty->column;
@@ -866,7 +859,7 @@
finish_erasing(tty);
if (L_ECHO(tty)) {
if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
- put_char('\a', tty); /* beep if no space */
+ tty_put_char(tty, '\a'); /* beep if no space */
return;
}
if (c == '\n')
@@ -970,8 +963,8 @@
break;
}
}
- if (tty->driver->flush_chars)
- tty->driver->flush_chars(tty);
+ if (tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
}
n_tty_set_room(tty);
@@ -987,12 +980,8 @@
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
- if (tty->receive_room < TTY_THRESHOLD_THROTTLE) {
- /* check TTY_THROTTLED first so it indicates our state */
- if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
- tty->driver->throttle)
- tty->driver->throttle(tty);
- }
+ if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
+ tty_throttle(tty);
}
int is_ignored(int sig)
@@ -1076,6 +1065,9 @@
tty->real_raw = 0;
}
n_tty_set_room(tty);
+ /* The termios change make the tty ready for I/O */
+ wake_up_interruptible(&tty->write_wait);
+ wake_up_interruptible(&tty->read_wait);
}
/**
@@ -1194,6 +1186,11 @@
* Perform job control management checks on this file/tty descriptor
* and if appropriate send any needed signals and return a negative
* error code if action should be taken.
+ *
+ * FIXME:
+ * Locking: None - redirected write test is safe, testing
+ * current->signal should possibly lock current->sighand
+ * pgrp locking ?
*/
static int job_control(struct tty_struct *tty, struct file *file)
@@ -1246,6 +1243,7 @@
ssize_t size;
long timeout;
unsigned long flags;
+ int packet;
do_it_again:
@@ -1289,16 +1287,19 @@
if (mutex_lock_interruptible(&tty->atomic_read_lock))
return -ERESTARTSYS;
}
+ packet = tty->packet;
add_wait_queue(&tty->read_wait, &wait);
while (nr) {
/* First test for status change. */
- if (tty->packet && tty->link->ctrl_status) {
+ if (packet && tty->link->ctrl_status) {
unsigned char cs;
if (b != buf)
break;
+ spin_lock_irqsave(&tty->link->ctrl_lock, flags);
cs = tty->link->ctrl_status;
tty->link->ctrl_status = 0;
+ spin_unlock_irqrestore(&tty->link->ctrl_lock, flags);
if (tty_put_user(tty, cs, b++)) {
retval = -EFAULT;
b--;
@@ -1333,6 +1334,7 @@
retval = -ERESTARTSYS;
break;
}
+ /* FIXME: does n_tty_set_room need locking ? */
n_tty_set_room(tty);
timeout = schedule_timeout(timeout);
continue;
@@ -1340,7 +1342,7 @@
__set_current_state(TASK_RUNNING);
/* Deal with packet mode. */
- if (tty->packet && b == buf) {
+ if (packet && b == buf) {
if (tty_put_user(tty, TIOCPKT_DATA, b++)) {
retval = -EFAULT;
b--;
@@ -1388,6 +1390,8 @@
break;
} else {
int uncopied;
+ /* The copy function takes the read lock and handles
+ locking internally for this case */
uncopied = copy_from_read_buf(tty, &b, &nr);
uncopied += copy_from_read_buf(tty, &b, &nr);
if (uncopied) {
@@ -1429,7 +1433,6 @@
goto do_it_again;
n_tty_set_room(tty);
-
return retval;
}
@@ -1492,11 +1495,11 @@
break;
b++; nr--;
}
- if (tty->driver->flush_chars)
- tty->driver->flush_chars(tty);
+ if (tty->ops->flush_chars)
+ tty->ops->flush_chars(tty);
} else {
while (nr > 0) {
- c = tty->driver->write(tty, b, nr);
+ c = tty->ops->write(tty, b, nr);
if (c < 0) {
retval = c;
goto break_out;
@@ -1533,11 +1536,6 @@
*
* This code must be sure never to sleep through a hangup.
* Called without the kernel lock held - fine
- *
- * FIXME: if someone changes the VMIN or discipline settings for the
- * terminal while another process is in poll() the poll does not
- * recompute the new limits. Possibly set_termios should issue
- * a read wakeup to fix this bug.
*/
static unsigned int normal_poll(struct tty_struct *tty, struct file *file,
@@ -1561,9 +1559,9 @@
else
tty->minimum_to_wake = 1;
}
- if (!tty_is_writelocked(tty) &&
- tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS &&
- tty->driver->write_room(tty) > 0)
+ if (tty->ops->write && !tty_is_writelocked(tty) &&
+ tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
+ tty_write_room(tty) > 0)
mask |= POLLOUT | POLLWRNORM;
return mask;
}
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index 6a6843a..66a0f93 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -73,7 +73,7 @@
char tmp[P_BUF_SIZE]; \
snprintf(tmp, sizeof(tmp), ##args); \
printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \
- __FUNCTION__, tmp); \
+ __func__, tmp); \
} while (0)
#define DBG1(args...) D_(0x01, ##args)
@@ -1407,7 +1407,7 @@
/* Find out what card type it is */
nozomi_get_card_type(dc);
- dc->base_addr = ioremap(start, dc->card_type);
+ dc->base_addr = ioremap_nocache(start, dc->card_type);
if (!dc->base_addr) {
dev_err(&pdev->dev, "Unable to map card MMIO\n");
ret = -ENODEV;
@@ -1724,6 +1724,8 @@
const struct ctrl_dl *ctrl_dl = &port->ctrl_dl;
const struct ctrl_ul *ctrl_ul = &port->ctrl_ul;
+ /* Note: these could change under us but it is not clear this
+ matters if so */
return (ctrl_ul->RTS ? TIOCM_RTS : 0) |
(ctrl_ul->DTR ? TIOCM_DTR : 0) |
(ctrl_dl->DCD ? TIOCM_CAR : 0) |
@@ -1849,16 +1851,6 @@
spin_unlock_irqrestore(&dc->spin_mutex, flags);
}
-/* just to discard single character writes */
-static void ntty_put_char(struct tty_struct *tty, unsigned char c)
-{
- /*
- * card does not react correct when we write single chars
- * to the card, so we discard them
- */
- DBG2("PUT CHAR Function: %c", c);
-}
-
/* Returns number of chars in buffer, called by tty layer */
static s32 ntty_chars_in_buffer(struct tty_struct *tty)
{
@@ -1892,7 +1884,6 @@
.unthrottle = ntty_unthrottle,
.throttle = ntty_throttle,
.chars_in_buffer = ntty_chars_in_buffer,
- .put_char = ntty_put_char,
.tiocmget = ntty_tiocmget,
.tiocmset = ntty_tiocmset,
};
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index 454d732..4a933d4 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -53,7 +53,7 @@
#define DEBUGP(n, rdr, x, args...) do { \
if (pc_debug >= (n)) \
dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
- __FUNCTION__ , ## args); \
+ __func__ , ## args); \
} while (0)
#else
#define DEBUGP(n, rdr, x, args...)
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c
index 5f291bf..035084c 100644
--- a/drivers/char/pcmcia/cm4040_cs.c
+++ b/drivers/char/pcmcia/cm4040_cs.c
@@ -47,7 +47,7 @@
#define DEBUGP(n, rdr, x, args...) do { \
if (pc_debug >= (n)) \
dev_printk(KERN_DEBUG, reader_to_dev(rdr), "%s:" x, \
- __FUNCTION__ , ##args); \
+ __func__ , ##args); \
} while (0)
#else
#define DEBUGP(n, rdr, x, args...)
diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c
index 1f978ff..fa9d3c9 100644
--- a/drivers/char/pcmcia/ipwireless/hardware.c
+++ b/drivers/char/pcmcia/ipwireless/hardware.c
@@ -354,32 +354,6 @@
unsigned int channel_idx;
};
-#ifdef IPWIRELESS_STATE_DEBUG
-int ipwireless_dump_hardware_state(char *p, size_t limit,
- struct ipw_hardware *hw)
-{
- return snprintf(p, limit,
- "debug: initializing=%d\n"
- "debug: tx_ready=%d\n"
- "debug: tx_queued=%d\n"
- "debug: rx_ready=%d\n"
- "debug: rx_bytes_queued=%d\n"
- "debug: blocking_rx=%d\n"
- "debug: removed=%d\n"
- "debug: hardware.shutting_down=%d\n"
- "debug: to_setup=%d\n",
- hw->initializing,
- hw->tx_ready,
- hw->tx_queued,
- hw->rx_ready,
- hw->rx_bytes_queued,
- hw->blocking_rx,
- hw->removed,
- hw->shutting_down,
- hw->to_setup);
-}
-#endif
-
static char *data_type(const unsigned char *buf, unsigned length)
{
struct nl_packet_header *hdr = (struct nl_packet_header *) buf;
diff --git a/drivers/char/pcmcia/ipwireless/hardware.h b/drivers/char/pcmcia/ipwireless/hardware.h
index c83190f..19ce5eb 100644
--- a/drivers/char/pcmcia/ipwireless/hardware.h
+++ b/drivers/char/pcmcia/ipwireless/hardware.h
@@ -58,7 +58,5 @@
void *reboot_cb_data);
void ipwireless_init_hardware_v2_v3(struct ipw_hardware *hw);
void ipwireless_sleep(unsigned int tenths);
-int ipwireless_dump_hardware_state(char *p, size_t limit,
- struct ipw_hardware *hw);
#endif
diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c
index d793e68b..fe914d3 100644
--- a/drivers/char/pcmcia/ipwireless/network.c
+++ b/drivers/char/pcmcia/ipwireless/network.c
@@ -63,21 +63,6 @@
struct work_struct work_go_offline;
};
-
-#ifdef IPWIRELESS_STATE_DEBUG
-int ipwireless_dump_network_state(char *p, size_t limit,
- struct ipw_network *network)
-{
- return snprintf(p, limit,
- "debug: ppp_blocked=%d\n"
- "debug: outgoing_packets_queued=%d\n"
- "debug: network.shutting_down=%d\n",
- network->ppp_blocked,
- network->outgoing_packets_queued,
- network->shutting_down);
-}
-#endif
-
static void notify_packet_sent(void *callback_data, unsigned int packet_length)
{
struct ipw_network *network = callback_data;
diff --git a/drivers/char/pcmcia/ipwireless/network.h b/drivers/char/pcmcia/ipwireless/network.h
index b0e1e95..ccacd26 100644
--- a/drivers/char/pcmcia/ipwireless/network.h
+++ b/drivers/char/pcmcia/ipwireless/network.h
@@ -49,7 +49,4 @@
int ipwireless_ppp_channel_index(struct ipw_network *net);
int ipwireless_ppp_unit_number(struct ipw_network *net);
-int ipwireless_dump_network_state(char *p, size_t limit,
- struct ipw_network *net);
-
#endif
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 5833564..1dd0e99 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -503,20 +503,9 @@
* The wrappers maintain line discipline references
* while calling into the line discipline.
*
- * ldisc_flush_buffer - flush line discipline receive buffers
* ldisc_receive_buf - pass receive data to line discipline
*/
-static void ldisc_flush_buffer(struct tty_struct *tty)
-{
- struct tty_ldisc *ld = tty_ldisc_ref(tty);
- if (ld) {
- if (ld->flush_buffer)
- ld->flush_buffer(tty);
- tty_ldisc_deref(ld);
- }
-}
-
static void ldisc_receive_buf(struct tty_struct *tty,
const __u8 *data, char *flags, int count)
{
@@ -1556,7 +1545,7 @@
/* Add a character to the transmit buffer
*/
-static void mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
+static int mgslpc_put_char(struct tty_struct *tty, unsigned char ch)
{
MGSLPC_INFO *info = (MGSLPC_INFO *)tty->driver_data;
unsigned long flags;
@@ -1567,10 +1556,10 @@
}
if (mgslpc_paranoia_check(info, tty->name, "mgslpc_put_char"))
- return;
+ return 0;
if (!info->tx_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock,flags);
@@ -1583,6 +1572,7 @@
}
spin_unlock_irqrestore(&info->lock,flags);
+ return 1;
}
/* Enable transmitter so remaining characters in the
@@ -2467,10 +2457,9 @@
if (info->flags & ASYNC_INITIALIZED)
mgslpc_wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ mgslpc_flush_buffer(tty);
- ldisc_flush_buffer(tty);
+ tty_ldisc_flush(tty);
shutdown(info);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 706ff347..0a05c03 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -181,6 +181,7 @@
static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
+ unsigned long flags;
if (!to)
return;
@@ -189,8 +190,10 @@
to->ldisc.flush_buffer(to);
if (to->packet) {
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
wake_up_interruptible(&to->read_wait);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
}
@@ -251,6 +254,18 @@
static int legacy_count = CONFIG_LEGACY_PTY_COUNT;
module_param(legacy_count, int, 0);
+static const struct tty_operations pty_ops_bsd = {
+ .open = pty_open,
+ .close = pty_close,
+ .write = pty_write,
+ .write_room = pty_write_room,
+ .flush_buffer = pty_flush_buffer,
+ .chars_in_buffer = pty_chars_in_buffer,
+ .unthrottle = pty_unthrottle,
+ .set_termios = pty_set_termios,
+ .ioctl = pty_bsd_ioctl,
+};
+
static void __init legacy_pty_init(void)
{
if (legacy_count <= 0)
@@ -281,7 +296,6 @@
pty_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
pty_driver->other = pty_slave_driver;
tty_set_operations(pty_driver, &pty_ops);
- pty_driver->ioctl = pty_bsd_ioctl;
pty_slave_driver->owner = THIS_MODULE;
pty_slave_driver->driver_name = "pty_slave";
@@ -374,6 +388,19 @@
return -ENOIOCTLCMD;
}
+static const struct tty_operations pty_unix98_ops = {
+ .open = pty_open,
+ .close = pty_close,
+ .write = pty_write,
+ .write_room = pty_write_room,
+ .flush_buffer = pty_flush_buffer,
+ .chars_in_buffer = pty_chars_in_buffer,
+ .unthrottle = pty_unthrottle,
+ .set_termios = pty_set_termios,
+ .ioctl = pty_unix98_ioctl
+};
+
+
static void __init unix98_pty_init(void)
{
ptm_driver = alloc_tty_driver(NR_UNIX98_PTY_MAX);
@@ -400,8 +427,7 @@
ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM;
ptm_driver->other = pts_driver;
- tty_set_operations(ptm_driver, &pty_ops);
- ptm_driver->ioctl = pty_unix98_ioctl;
+ tty_set_operations(ptm_driver, &pty_unix98_ops);
pts_driver->owner = THIS_MODULE;
pts_driver->driver_name = "pty_slave";
diff --git a/drivers/char/random.c b/drivers/char/random.c
index f43c89f..0cf98bd 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -272,7 +272,7 @@
static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28;
-static DEFINE_PER_CPU(int, trickle_count) = 0;
+static DEFINE_PER_CPU(int, trickle_count);
/*
* A pool of size .poolwords is stirred with a primitive polynomial
@@ -370,17 +370,19 @@
*/
static DECLARE_WAIT_QUEUE_HEAD(random_read_wait);
static DECLARE_WAIT_QUEUE_HEAD(random_write_wait);
+static struct fasync_struct *fasync;
#if 0
-static int debug = 0;
+static int debug;
module_param(debug, bool, 0644);
-#define DEBUG_ENT(fmt, arg...) do { if (debug) \
- printk(KERN_DEBUG "random %04d %04d %04d: " \
- fmt,\
- input_pool.entropy_count,\
- blocking_pool.entropy_count,\
- nonblocking_pool.entropy_count,\
- ## arg); } while (0)
+#define DEBUG_ENT(fmt, arg...) do { \
+ if (debug) \
+ printk(KERN_DEBUG "random %04d %04d %04d: " \
+ fmt,\
+ input_pool.entropy_count,\
+ blocking_pool.entropy_count,\
+ nonblocking_pool.entropy_count,\
+ ## arg); } while (0)
#else
#define DEBUG_ENT(fmt, arg...) do {} while (0)
#endif
@@ -394,7 +396,7 @@
struct entropy_store;
struct entropy_store {
- /* mostly-read data: */
+ /* read-only data: */
struct poolinfo *poolinfo;
__u32 *pool;
const char *name;
@@ -402,7 +404,7 @@
struct entropy_store *pull;
/* read-write data: */
- spinlock_t lock ____cacheline_aligned_in_smp;
+ spinlock_t lock;
unsigned add_ptr;
int entropy_count;
int input_rotate;
@@ -438,25 +440,26 @@
};
/*
- * This function adds a byte into the entropy "pool". It does not
+ * This function adds bytes into the entropy "pool". It does not
* update the entropy estimate. The caller should call
- * credit_entropy_store if this is appropriate.
+ * credit_entropy_bits if this is appropriate.
*
* The pool is stirred with a primitive polynomial of the appropriate
* degree, and then twisted. We twist by three bits at a time because
* it's cheap to do so and helps slightly in the expected case where
* the entropy is concentrated in the low-order bits.
*/
-static void __add_entropy_words(struct entropy_store *r, const __u32 *in,
- int nwords, __u32 out[16])
+static void mix_pool_bytes_extract(struct entropy_store *r, const void *in,
+ int nbytes, __u8 out[64])
{
static __u32 const twist_table[8] = {
0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
- unsigned long i, add_ptr, tap1, tap2, tap3, tap4, tap5;
- int new_rotate, input_rotate;
+ unsigned long i, j, tap1, tap2, tap3, tap4, tap5;
+ int input_rotate;
int wordmask = r->poolinfo->poolwords - 1;
- __u32 w, next_w;
+ const char *bytes = in;
+ __u32 w;
unsigned long flags;
/* Taps are constant, so we can load them without holding r->lock. */
@@ -465,78 +468,76 @@
tap3 = r->poolinfo->tap3;
tap4 = r->poolinfo->tap4;
tap5 = r->poolinfo->tap5;
- next_w = *in++;
spin_lock_irqsave(&r->lock, flags);
- prefetch_range(r->pool, wordmask);
input_rotate = r->input_rotate;
- add_ptr = r->add_ptr;
+ i = r->add_ptr;
- while (nwords--) {
- w = rol32(next_w, input_rotate);
- if (nwords > 0)
- next_w = *in++;
- i = add_ptr = (add_ptr - 1) & wordmask;
+ /* mix one byte at a time to simplify size handling and churn faster */
+ while (nbytes--) {
+ w = rol32(*bytes++, input_rotate & 31);
+ i = (i - 1) & wordmask;
+
+ /* XOR in the various taps */
+ w ^= r->pool[i];
+ w ^= r->pool[(i + tap1) & wordmask];
+ w ^= r->pool[(i + tap2) & wordmask];
+ w ^= r->pool[(i + tap3) & wordmask];
+ w ^= r->pool[(i + tap4) & wordmask];
+ w ^= r->pool[(i + tap5) & wordmask];
+
+ /* Mix the result back in with a twist */
+ r->pool[i] = (w >> 3) ^ twist_table[w & 7];
+
/*
* Normally, we add 7 bits of rotation to the pool.
* At the beginning of the pool, add an extra 7 bits
* rotation, so that successive passes spread the
* input bits across the pool evenly.
*/
- new_rotate = input_rotate + 14;
- if (i)
- new_rotate = input_rotate + 7;
- input_rotate = new_rotate & 31;
-
- /* XOR in the various taps */
- w ^= r->pool[(i + tap1) & wordmask];
- w ^= r->pool[(i + tap2) & wordmask];
- w ^= r->pool[(i + tap3) & wordmask];
- w ^= r->pool[(i + tap4) & wordmask];
- w ^= r->pool[(i + tap5) & wordmask];
- w ^= r->pool[i];
- r->pool[i] = (w >> 3) ^ twist_table[w & 7];
+ input_rotate += i ? 7 : 14;
}
r->input_rotate = input_rotate;
- r->add_ptr = add_ptr;
+ r->add_ptr = i;
- if (out) {
- for (i = 0; i < 16; i++) {
- out[i] = r->pool[add_ptr];
- add_ptr = (add_ptr - 1) & wordmask;
- }
- }
+ if (out)
+ for (j = 0; j < 16; j++)
+ ((__u32 *)out)[j] = r->pool[(i - j) & wordmask];
spin_unlock_irqrestore(&r->lock, flags);
}
-static inline void add_entropy_words(struct entropy_store *r, const __u32 *in,
- int nwords)
+static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes)
{
- __add_entropy_words(r, in, nwords, NULL);
+ mix_pool_bytes_extract(r, in, bytes, NULL);
}
/*
* Credit (or debit) the entropy store with n bits of entropy
*/
-static void credit_entropy_store(struct entropy_store *r, int nbits)
+static void credit_entropy_bits(struct entropy_store *r, int nbits)
{
unsigned long flags;
+ if (!nbits)
+ return;
+
spin_lock_irqsave(&r->lock, flags);
- if (r->entropy_count + nbits < 0) {
- DEBUG_ENT("negative entropy/overflow (%d+%d)\n",
- r->entropy_count, nbits);
+ DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name);
+ r->entropy_count += nbits;
+ if (r->entropy_count < 0) {
+ DEBUG_ENT("negative entropy/overflow\n");
r->entropy_count = 0;
- } else if (r->entropy_count + nbits > r->poolinfo->POOLBITS) {
+ } else if (r->entropy_count > r->poolinfo->POOLBITS)
r->entropy_count = r->poolinfo->POOLBITS;
- } else {
- r->entropy_count += nbits;
- if (nbits)
- DEBUG_ENT("added %d entropy credits to %s\n",
- nbits, r->name);
+
+ /* should we wake readers? */
+ if (r == &input_pool &&
+ r->entropy_count >= random_read_wakeup_thresh) {
+ wake_up_interruptible(&random_read_wait);
+ kill_fasync(&fasync, SIGIO, POLL_IN);
}
spin_unlock_irqrestore(&r->lock, flags);
@@ -551,7 +552,7 @@
/* There is one of these per entropy source */
struct timer_rand_state {
cycles_t last_time;
- long last_delta,last_delta2;
+ long last_delta, last_delta2;
unsigned dont_count_entropy:1;
};
@@ -586,7 +587,7 @@
sample.jiffies = jiffies;
sample.cycles = get_cycles();
sample.num = num;
- add_entropy_words(&input_pool, (u32 *)&sample, sizeof(sample)/4);
+ mix_pool_bytes(&input_pool, &sample, sizeof(sample));
/*
* Calculate number of bits of randomness we probably added.
@@ -620,13 +621,9 @@
* Round down by 1 bit on general principles,
* and limit entropy entimate to 12 bits.
*/
- credit_entropy_store(&input_pool,
- min_t(int, fls(delta>>1), 11));
+ credit_entropy_bits(&input_pool,
+ min_t(int, fls(delta>>1), 11));
}
-
- if(input_pool.entropy_count >= random_read_wakeup_thresh)
- wake_up_interruptible(&random_read_wait);
-
out:
preempt_enable();
}
@@ -677,7 +674,7 @@
*
*********************************************************************/
-static ssize_t extract_entropy(struct entropy_store *r, void * buf,
+static ssize_t extract_entropy(struct entropy_store *r, void *buf,
size_t nbytes, int min, int rsvd);
/*
@@ -704,10 +701,10 @@
"(%d of %d requested)\n",
r->name, bytes * 8, nbytes * 8, r->entropy_count);
- bytes=extract_entropy(r->pull, tmp, bytes,
- random_read_wakeup_thresh / 8, rsvd);
- add_entropy_words(r, tmp, (bytes + 3) / 4);
- credit_entropy_store(r, bytes*8);
+ bytes = extract_entropy(r->pull, tmp, bytes,
+ random_read_wakeup_thresh / 8, rsvd);
+ mix_pool_bytes(r, tmp, bytes);
+ credit_entropy_bits(r, bytes*8);
}
}
@@ -744,13 +741,15 @@
if (r->limit && nbytes + reserved >= r->entropy_count / 8)
nbytes = r->entropy_count/8 - reserved;
- if(r->entropy_count / 8 >= nbytes + reserved)
+ if (r->entropy_count / 8 >= nbytes + reserved)
r->entropy_count -= nbytes*8;
else
r->entropy_count = reserved;
- if (r->entropy_count < random_write_wakeup_thresh)
+ if (r->entropy_count < random_write_wakeup_thresh) {
wake_up_interruptible(&random_write_wait);
+ kill_fasync(&fasync, SIGIO, POLL_OUT);
+ }
}
DEBUG_ENT("debiting %d entropy credits from %s%s\n",
@@ -764,45 +763,46 @@
static void extract_buf(struct entropy_store *r, __u8 *out)
{
int i;
- __u32 data[16], buf[5 + SHA_WORKSPACE_WORDS];
+ __u32 hash[5], workspace[SHA_WORKSPACE_WORDS];
+ __u8 extract[64];
- sha_init(buf);
- /*
- * As we hash the pool, we mix intermediate values of
- * the hash back into the pool. This eliminates
- * backtracking attacks (where the attacker knows
- * the state of the pool plus the current outputs, and
- * attempts to find previous ouputs), unless the hash
- * function can be inverted.
- */
- for (i = 0; i < r->poolinfo->poolwords; i += 16) {
- /* hash blocks of 16 words = 512 bits */
- sha_transform(buf, (__u8 *)(r->pool + i), buf + 5);
- /* feed back portion of the resulting hash */
- add_entropy_words(r, &buf[i % 5], 1);
- }
+ /* Generate a hash across the pool, 16 words (512 bits) at a time */
+ sha_init(hash);
+ for (i = 0; i < r->poolinfo->poolwords; i += 16)
+ sha_transform(hash, (__u8 *)(r->pool + i), workspace);
/*
- * To avoid duplicates, we atomically extract a
- * portion of the pool while mixing, and hash one
- * final time.
+ * We mix the hash back into the pool to prevent backtracking
+ * attacks (where the attacker knows the state of the pool
+ * plus the current outputs, and attempts to find previous
+ * ouputs), unless the hash function can be inverted. By
+ * mixing at least a SHA1 worth of hash data back, we make
+ * brute-forcing the feedback as hard as brute-forcing the
+ * hash.
*/
- __add_entropy_words(r, &buf[i % 5], 1, data);
- sha_transform(buf, (__u8 *)data, buf + 5);
+ mix_pool_bytes_extract(r, hash, sizeof(hash), extract);
/*
- * In case the hash function has some recognizable
- * output pattern, we fold it in half.
+ * To avoid duplicates, we atomically extract a portion of the
+ * pool while mixing, and hash one final time.
*/
+ sha_transform(hash, extract, workspace);
+ memset(extract, 0, sizeof(extract));
+ memset(workspace, 0, sizeof(workspace));
- buf[0] ^= buf[3];
- buf[1] ^= buf[4];
- buf[2] ^= rol32(buf[2], 16);
- memcpy(out, buf, EXTRACT_SIZE);
- memset(buf, 0, sizeof(buf));
+ /*
+ * In case the hash function has some recognizable output
+ * pattern, we fold it in half. Thus, we always feed back
+ * twice as much data as we output.
+ */
+ hash[0] ^= hash[3];
+ hash[1] ^= hash[4];
+ hash[2] ^= rol32(hash[2], 16);
+ memcpy(out, hash, EXTRACT_SIZE);
+ memset(hash, 0, sizeof(hash));
}
-static ssize_t extract_entropy(struct entropy_store *r, void * buf,
+static ssize_t extract_entropy(struct entropy_store *r, void *buf,
size_t nbytes, int min, int reserved)
{
ssize_t ret = 0, i;
@@ -872,7 +872,6 @@
{
extract_entropy(&nonblocking_pool, buf, nbytes, 0, 0);
}
-
EXPORT_SYMBOL(get_random_bytes);
/*
@@ -894,12 +893,11 @@
spin_unlock_irqrestore(&r->lock, flags);
now = ktime_get_real();
- add_entropy_words(r, (__u32 *)&now, sizeof(now)/4);
- add_entropy_words(r, (__u32 *)utsname(),
- sizeof(*(utsname()))/4);
+ mix_pool_bytes(r, &now, sizeof(now));
+ mix_pool_bytes(r, utsname(), sizeof(*(utsname())));
}
-static int __init rand_initialize(void)
+static int rand_initialize(void)
{
init_std_data(&input_pool);
init_std_data(&blocking_pool);
@@ -940,7 +938,7 @@
#endif
static ssize_t
-random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
+random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
ssize_t n, retval = 0, count = 0;
@@ -1002,8 +1000,7 @@
}
static ssize_t
-urandom_read(struct file * file, char __user * buf,
- size_t nbytes, loff_t *ppos)
+urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
return extract_entropy_user(&nonblocking_pool, buf, nbytes);
}
@@ -1038,16 +1035,15 @@
count -= bytes;
p += bytes;
- add_entropy_words(r, buf, (bytes + 3) / 4);
+ mix_pool_bytes(r, buf, bytes);
cond_resched();
}
return 0;
}
-static ssize_t
-random_write(struct file * file, const char __user * buffer,
- size_t count, loff_t *ppos)
+static ssize_t random_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
size_t ret;
struct inode *inode = file->f_path.dentry->d_inode;
@@ -1064,9 +1060,7 @@
return (ssize_t)count;
}
-static int
-random_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
+static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
{
int size, ent_count;
int __user *p = (int __user *)arg;
@@ -1074,8 +1068,8 @@
switch (cmd) {
case RNDGETENTCNT:
- ent_count = input_pool.entropy_count;
- if (put_user(ent_count, p))
+ /* inherently racy, no point locking */
+ if (put_user(input_pool.entropy_count, p))
return -EFAULT;
return 0;
case RNDADDTOENTCNT:
@@ -1083,13 +1077,7 @@
return -EPERM;
if (get_user(ent_count, p))
return -EFAULT;
- credit_entropy_store(&input_pool, ent_count);
- /*
- * Wake up waiting processes if we have enough
- * entropy.
- */
- if (input_pool.entropy_count >= random_read_wakeup_thresh)
- wake_up_interruptible(&random_read_wait);
+ credit_entropy_bits(&input_pool, ent_count);
return 0;
case RNDADDENTROPY:
if (!capable(CAP_SYS_ADMIN))
@@ -1104,39 +1092,45 @@
size);
if (retval < 0)
return retval;
- credit_entropy_store(&input_pool, ent_count);
- /*
- * Wake up waiting processes if we have enough
- * entropy.
- */
- if (input_pool.entropy_count >= random_read_wakeup_thresh)
- wake_up_interruptible(&random_read_wait);
+ credit_entropy_bits(&input_pool, ent_count);
return 0;
case RNDZAPENTCNT:
case RNDCLEARPOOL:
/* Clear the entropy pool counters. */
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- init_std_data(&input_pool);
- init_std_data(&blocking_pool);
- init_std_data(&nonblocking_pool);
+ rand_initialize();
return 0;
default:
return -EINVAL;
}
}
+static int random_fasync(int fd, struct file *filp, int on)
+{
+ return fasync_helper(fd, filp, on, &fasync);
+}
+
+static int random_release(struct inode *inode, struct file *filp)
+{
+ return fasync_helper(-1, filp, 0, &fasync);
+}
+
const struct file_operations random_fops = {
.read = random_read,
.write = random_write,
.poll = random_poll,
- .ioctl = random_ioctl,
+ .unlocked_ioctl = random_ioctl,
+ .fasync = random_fasync,
+ .release = random_release,
};
const struct file_operations urandom_fops = {
.read = urandom_read,
.write = random_write,
- .ioctl = random_ioctl,
+ .unlocked_ioctl = random_ioctl,
+ .fasync = random_fasync,
+ .release = random_release,
};
/***************************************************************
@@ -1157,7 +1151,6 @@
/* Set the UUID variant to DCE */
uuid_out[8] = (uuid_out[8] & 0x3F) | 0x80;
}
-
EXPORT_SYMBOL(generate_random_uuid);
/********************************************************************
@@ -1339,7 +1332,7 @@
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static __u32 twothirdsMD4Transform (__u32 const buf[4], __u32 const in[12])
+static __u32 twothirdsMD4Transform(__u32 const buf[4], __u32 const in[12])
{
__u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3];
@@ -1487,8 +1480,8 @@
*/
memcpy(hash, saddr, 16);
- hash[4]=((__force u16)sport << 16) + (__force u16)dport;
- memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);
+ hash[4] = ((__force u16)sport << 16) + (__force u16)dport;
+ memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7);
seq = twothirdsMD4Transform((const __u32 *)daddr, hash) & HASH_MASK;
seq += keyptr->count;
@@ -1538,10 +1531,10 @@
* Note that the words are placed into the starting vector, which is
* then mixed with a partial MD4 over random data.
*/
- hash[0]=(__force u32)saddr;
- hash[1]=(__force u32)daddr;
- hash[2]=((__force u16)sport << 16) + (__force u16)dport;
- hash[3]=keyptr->secret[11];
+ hash[0] = (__force u32)saddr;
+ hash[1] = (__force u32)daddr;
+ hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
+ hash[3] = keyptr->secret[11];
seq = half_md4_transform(hash, keyptr->secret) & HASH_MASK;
seq += keyptr->count;
@@ -1556,10 +1549,7 @@
* Choosing a clock of 64 ns period is OK. (period of 274 s)
*/
seq += ktime_to_ns(ktime_get_real()) >> 6;
-#if 0
- printk("init_seq(%lx, %lx, %d, %d) = %d\n",
- saddr, daddr, sport, dport, seq);
-#endif
+
return seq;
}
@@ -1582,14 +1572,15 @@
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, __be16 dport)
+u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
+ __be16 dport)
{
struct keydata *keyptr = get_keyptr();
u32 hash[12];
memcpy(hash, saddr, 16);
hash[4] = (__force u32)dport;
- memcpy(&hash[5],keyptr->secret,sizeof(__u32) * 7);
+ memcpy(&hash[5], keyptr->secret, sizeof(__u32) * 7);
return twothirdsMD4Transform((const __u32 *)daddr, hash);
}
@@ -1617,13 +1608,9 @@
seq += ktime_to_ns(ktime_get_real());
seq &= (1ull << 48) - 1;
-#if 0
- printk("dccp init_seq(%lx, %lx, %d, %d) = %d\n",
- saddr, daddr, sport, dport, seq);
-#endif
+
return seq;
}
-
EXPORT_SYMBOL(secure_dccp_sequence_number);
#endif
diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h
index f4f837f..a03a538 100644
--- a/drivers/char/rio/cirrus.h
+++ b/drivers/char/rio/cirrus.h
@@ -43,83 +43,83 @@
/* Bit fields for particular registers shared with driver */
/* COR1 - driver and RTA */
-#define COR1_ODD 0x80 /* Odd parity */
-#define COR1_EVEN 0x00 /* Even parity */
-#define COR1_NOP 0x00 /* No parity */
-#define COR1_FORCE 0x20 /* Force parity */
-#define COR1_NORMAL 0x40 /* With parity */
-#define COR1_1STOP 0x00 /* 1 stop bit */
-#define COR1_15STOP 0x04 /* 1.5 stop bits */
-#define COR1_2STOP 0x08 /* 2 stop bits */
-#define COR1_5BITS 0x00 /* 5 data bits */
-#define COR1_6BITS 0x01 /* 6 data bits */
-#define COR1_7BITS 0x02 /* 7 data bits */
-#define COR1_8BITS 0x03 /* 8 data bits */
+#define RIOC_COR1_ODD 0x80 /* Odd parity */
+#define RIOC_COR1_EVEN 0x00 /* Even parity */
+#define RIOC_COR1_NOP 0x00 /* No parity */
+#define RIOC_COR1_FORCE 0x20 /* Force parity */
+#define RIOC_COR1_NORMAL 0x40 /* With parity */
+#define RIOC_COR1_1STOP 0x00 /* 1 stop bit */
+#define RIOC_COR1_15STOP 0x04 /* 1.5 stop bits */
+#define RIOC_COR1_2STOP 0x08 /* 2 stop bits */
+#define RIOC_COR1_5BITS 0x00 /* 5 data bits */
+#define RIOC_COR1_6BITS 0x01 /* 6 data bits */
+#define RIOC_COR1_7BITS 0x02 /* 7 data bits */
+#define RIOC_COR1_8BITS 0x03 /* 8 data bits */
-#define COR1_HOST 0xef /* Safe host bits */
+#define RIOC_COR1_HOST 0xef /* Safe host bits */
/* RTA only */
-#define COR1_CINPCK 0x00 /* Check parity of received characters */
-#define COR1_CNINPCK 0x10 /* Don't check parity */
+#define RIOC_COR1_CINPCK 0x00 /* Check parity of received characters */
+#define RIOC_COR1_CNINPCK 0x10 /* Don't check parity */
/* COR2 bits for both RTA and driver use */
-#define COR2_IXANY 0x80 /* IXANY - any character is XON */
-#define COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */
-#define COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */
+#define RIOC_COR2_IXANY 0x80 /* IXANY - any character is XON */
+#define RIOC_COR2_IXON 0x40 /* IXON - enable tx soft flowcontrol */
+#define RIOC_COR2_RTSFLOW 0x02 /* Enable tx hardware flow control */
/* Additional driver bits */
-#define COR2_HUPCL 0x20 /* Hang up on close */
-#define COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */
-#define COR2_IXOFF 0x01 /* Enable rx software flow control */
-#define COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */
+#define RIOC_COR2_HUPCL 0x20 /* Hang up on close */
+#define RIOC_COR2_CTSFLOW 0x04 /* Enable rx hardware flow control */
+#define RIOC_COR2_IXOFF 0x01 /* Enable rx software flow control */
+#define RIOC_COR2_DTRFLOW 0x08 /* Enable tx hardware flow control */
/* RTA use only */
-#define COR2_ETC 0x20 /* Embedded transmit options */
-#define COR2_LOCAL 0x10 /* Local loopback mode */
-#define COR2_REMOTE 0x08 /* Remote loopback mode */
-#define COR2_HOST 0xc2 /* Safe host bits */
+#define RIOC_COR2_ETC 0x20 /* Embedded transmit options */
+#define RIOC_COR2_LOCAL 0x10 /* Local loopback mode */
+#define RIOC_COR2_REMOTE 0x08 /* Remote loopback mode */
+#define RIOC_COR2_HOST 0xc2 /* Safe host bits */
/* COR3 - RTA use only */
-#define COR3_SCDRNG 0x80 /* Enable special char detect for range */
-#define COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */
-#define COR3_FCT 0x20 /* Flow control transparency */
-#define COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */
-#define COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */
-#define COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */
-#define COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */
-#define COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */
+#define RIOC_COR3_SCDRNG 0x80 /* Enable special char detect for range */
+#define RIOC_COR3_SCD34 0x40 /* Special character detect for SCHR's 3 + 4 */
+#define RIOC_COR3_FCT 0x20 /* Flow control transparency */
+#define RIOC_COR3_SCD12 0x10 /* Special character detect for SCHR's 1 + 2 */
+#define RIOC_COR3_FIFO12 0x0c /* 12 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO10 0x0a /* 10 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO8 0x08 /* 8 chars for receive FIFO threshold */
+#define RIOC_COR3_FIFO6 0x06 /* 6 chars for receive FIFO threshold */
-#define COR3_THRESHOLD COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */
+#define RIOC_COR3_THRESHOLD RIOC_COR3_FIFO8 /* MUST BE LESS THAN MCOR_THRESHOLD */
-#define COR3_DEFAULT (COR3_FCT | COR3_THRESHOLD)
+#define RIOC_COR3_DEFAULT (RIOC_COR3_FCT | RIOC_COR3_THRESHOLD)
/* Default bits for COR3 */
/* COR4 driver and RTA use */
-#define COR4_IGNCR 0x80 /* Throw away CR's on input */
-#define COR4_ICRNL 0x40 /* Map CR -> NL on input */
-#define COR4_INLCR 0x20 /* Map NL -> CR on input */
-#define COR4_IGNBRK 0x10 /* Ignore Break */
-#define COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */
-#define COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */
+#define RIOC_COR4_IGNCR 0x80 /* Throw away CR's on input */
+#define RIOC_COR4_ICRNL 0x40 /* Map CR -> NL on input */
+#define RIOC_COR4_INLCR 0x20 /* Map NL -> CR on input */
+#define RIOC_COR4_IGNBRK 0x10 /* Ignore Break */
+#define RIOC_COR4_NBRKINT 0x08 /* No interrupt on break (-BRKINT) */
+#define RIOC_COR4_RAISEMOD 0x01 /* Raise modem output lines on non-zero baud */
/* COR4 driver only */
-#define COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */
-#define COR4_PARMRK 0x02 /* PARMRK */
+#define RIOC_COR4_IGNPAR 0x04 /* IGNPAR (ignore characters with errors) */
+#define RIOC_COR4_PARMRK 0x02 /* PARMRK */
-#define COR4_HOST 0xf8 /* Safe host bits */
+#define RIOC_COR4_HOST 0xf8 /* Safe host bits */
/* COR4 RTA only */
-#define COR4_CIGNPAR 0x02 /* Thrown away bad characters */
-#define COR4_CPARMRK 0x04 /* PARMRK characters */
-#define COR4_CNPARMRK 0x03 /* Don't PARMRK */
+#define RIOC_COR4_CIGNPAR 0x02 /* Thrown away bad characters */
+#define RIOC_COR4_CPARMRK 0x04 /* PARMRK characters */
+#define RIOC_COR4_CNPARMRK 0x03 /* Don't PARMRK */
/* COR5 driver and RTA use */
-#define COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */
-#define COR5_LNE 0x40 /* Enable LNEXT processing */
-#define COR5_CMOE 0x20 /* Match good and errored characters */
-#define COR5_ONLCR 0x02 /* NL -> CR NL on output */
-#define COR5_OCRNL 0x01 /* CR -> NL on output */
+#define RIOC_COR5_ISTRIP 0x80 /* Strip input chars to 7 bits */
+#define RIOC_COR5_LNE 0x40 /* Enable LNEXT processing */
+#define RIOC_COR5_CMOE 0x20 /* Match good and errored characters */
+#define RIOC_COR5_ONLCR 0x02 /* NL -> CR NL on output */
+#define RIOC_COR5_OCRNL 0x01 /* CR -> NL on output */
/*
** Spare bits - these are not used in the CIRRUS registers, so we use
@@ -128,86 +128,86 @@
/*
** tstop and tbusy indication
*/
-#define COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */
-#define COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */
+#define RIOC_COR5_TSTATE_ON 0x08 /* Turn on monitoring of tbusy and tstop */
+#define RIOC_COR5_TSTATE_OFF 0x04 /* Turn off monitoring of tbusy and tstop */
/*
** TAB3
*/
-#define COR5_TAB3 0x10 /* TAB3 mode */
+#define RIOC_COR5_TAB3 0x10 /* TAB3 mode */
-#define COR5_HOST 0xc3 /* Safe host bits */
+#define RIOC_COR5_HOST 0xc3 /* Safe host bits */
/* CCSR */
-#define CCSR_TXFLOFF 0x04 /* Tx is xoffed */
+#define RIOC_CCSR_TXFLOFF 0x04 /* Tx is xoffed */
/* MSVR1 */
/* NB. DTR / CD swapped from Cirrus spec as the pins are also reversed on the
RTA. This is because otherwise DCD would get lost on the 1 parallel / 3
serial option.
*/
-#define MSVR1_CD 0x80 /* CD (DSR on Cirrus) */
-#define MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */
-#define MSVR1_RI 0x20 /* RI */
-#define MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */
-#define MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */
+#define RIOC_MSVR1_CD 0x80 /* CD (DSR on Cirrus) */
+#define RIOC_MSVR1_RTS 0x40 /* RTS (CTS on Cirrus) */
+#define RIOC_MSVR1_RI 0x20 /* RI */
+#define RIOC_MSVR1_DTR 0x10 /* DTR (CD on Cirrus) */
+#define RIOC_MSVR1_CTS 0x01 /* CTS output pin (RTS on Cirrus) */
/* Next two used to indicate state of tbusy and tstop to driver */
-#define MSVR1_TSTOP 0x08 /* Set if port flow controlled */
-#define MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */
+#define RIOC_MSVR1_TSTOP 0x08 /* Set if port flow controlled */
+#define RIOC_MSVR1_TEMPTY 0x04 /* Set if port tx buffer empty */
-#define MSVR1_HOST 0xf3 /* The bits the host wants */
+#define RIOC_MSVR1_HOST 0xf3 /* The bits the host wants */
/* Defines for the subscripts of a CONFIG packet */
-#define CONFIG_COR1 1 /* Option register 1 */
-#define CONFIG_COR2 2 /* Option register 2 */
-#define CONFIG_COR4 3 /* Option register 4 */
-#define CONFIG_COR5 4 /* Option register 5 */
-#define CONFIG_TXXON 5 /* Tx XON character */
-#define CONFIG_TXXOFF 6 /* Tx XOFF character */
-#define CONFIG_RXXON 7 /* Rx XON character */
-#define CONFIG_RXXOFF 8 /* Rx XOFF character */
-#define CONFIG_LNEXT 9 /* LNEXT character */
-#define CONFIG_TXBAUD 10 /* Tx baud rate */
-#define CONFIG_RXBAUD 11 /* Rx baud rate */
+#define RIOC_CONFIG_COR1 1 /* Option register 1 */
+#define RIOC_CONFIG_COR2 2 /* Option register 2 */
+#define RIOC_CONFIG_COR4 3 /* Option register 4 */
+#define RIOC_CONFIG_COR5 4 /* Option register 5 */
+#define RIOC_CONFIG_TXXON 5 /* Tx XON character */
+#define RIOC_CONFIG_TXXOFF 6 /* Tx XOFF character */
+#define RIOC_CONFIG_RXXON 7 /* Rx XON character */
+#define RIOC_CONFIG_RXXOFF 8 /* Rx XOFF character */
+#define RIOC_CONFIG_LNEXT 9 /* LNEXT character */
+#define RIOC_CONFIG_TXBAUD 10 /* Tx baud rate */
+#define RIOC_CONFIG_RXBAUD 11 /* Rx baud rate */
-#define PRE_EMPTIVE 0x80 /* Pre-emptive bit in command field */
+#define RIOC_PRE_EMPTIVE 0x80 /* Pre-emptive bit in command field */
/* Packet types going from Host to remote - with the exception of OPEN, MOPEN,
CONFIG, SBREAK and MEMDUMP the remaining bytes of the data array will not
be used
*/
-#define OPEN 0x00 /* Open a port */
-#define CONFIG 0x01 /* Configure a port */
-#define MOPEN 0x02 /* Modem open (block for DCD) */
-#define CLOSE 0x03 /* Close a port */
-#define WFLUSH (0x04 | PRE_EMPTIVE) /* Write flush */
-#define RFLUSH (0x05 | PRE_EMPTIVE) /* Read flush */
-#define RESUME (0x06 | PRE_EMPTIVE) /* Resume if xoffed */
-#define SBREAK 0x07 /* Start break */
-#define EBREAK 0x08 /* End break */
-#define SUSPEND (0x09 | PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */
-#define FCLOSE (0x0a | PRE_EMPTIVE) /* Force close */
-#define XPRINT 0x0b /* Xprint packet */
-#define MBIS (0x0c | PRE_EMPTIVE) /* Set modem lines */
-#define MBIC (0x0d | PRE_EMPTIVE) /* Clear modem lines */
-#define MSET (0x0e | PRE_EMPTIVE) /* Set modem lines */
-#define PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */
-#define MGET (0x10 | PRE_EMPTIVE) /* Force update of modem status */
-#define MEMDUMP (0x11 | PRE_EMPTIVE) /* Send back mem from addr supplied */
-#define READ_REGISTER (0x12 | PRE_EMPTIVE) /* Read CD1400 register (debug) */
+#define RIOC_OPEN 0x00 /* Open a port */
+#define RIOC_CONFIG 0x01 /* Configure a port */
+#define RIOC_MOPEN 0x02 /* Modem open (block for DCD) */
+#define RIOC_CLOSE 0x03 /* Close a port */
+#define RIOC_WFLUSH (0x04 | RIOC_PRE_EMPTIVE) /* Write flush */
+#define RIOC_RFLUSH (0x05 | RIOC_PRE_EMPTIVE) /* Read flush */
+#define RIOC_RESUME (0x06 | RIOC_PRE_EMPTIVE) /* Resume if xoffed */
+#define RIOC_SBREAK 0x07 /* Start break */
+#define RIOC_EBREAK 0x08 /* End break */
+#define RIOC_SUSPEND (0x09 | RIOC_PRE_EMPTIVE) /* Susp op (behave as tho xoffed) */
+#define RIOC_FCLOSE (0x0a | RIOC_PRE_EMPTIVE) /* Force close */
+#define RIOC_XPRINT 0x0b /* Xprint packet */
+#define RIOC_MBIS (0x0c | RIOC_PRE_EMPTIVE) /* Set modem lines */
+#define RIOC_MBIC (0x0d | RIOC_PRE_EMPTIVE) /* Clear modem lines */
+#define RIOC_MSET (0x0e | RIOC_PRE_EMPTIVE) /* Set modem lines */
+#define RIOC_PCLOSE 0x0f /* Pseudo close - Leaves rx/tx enabled */
+#define RIOC_MGET (0x10 | RIOC_PRE_EMPTIVE) /* Force update of modem status */
+#define RIOC_MEMDUMP (0x11 | RIOC_PRE_EMPTIVE) /* Send back mem from addr supplied */
+#define RIOC_READ_REGISTER (0x12 | RIOC_PRE_EMPTIVE) /* Read CD1400 register (debug) */
/* "Command" packets going from remote to host COMPLETE and MODEM_STATUS
use data[4] / data[3] to indicate current state and modem status respectively
*/
-#define COMPLETE (0x20 | PRE_EMPTIVE)
+#define RIOC_COMPLETE (0x20 | RIOC_PRE_EMPTIVE)
/* Command complete */
-#define BREAK_RECEIVED (0x21 | PRE_EMPTIVE)
+#define RIOC_BREAK_RECEIVED (0x21 | RIOC_PRE_EMPTIVE)
/* Break received */
-#define MODEM_STATUS (0x22 | PRE_EMPTIVE)
+#define RIOC_MODEM_STATUS (0x22 | RIOC_PRE_EMPTIVE)
/* Change in modem status */
/* "Command" packet that could go either way - handshake wake-up */
-#define HANDSHAKE (0x23 | PRE_EMPTIVE)
+#define RIOC_HANDSHAKE (0x23 | RIOC_PRE_EMPTIVE)
/* Wake-up to HOST / RTA */
#endif
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 0ce9667..412777c 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -344,7 +344,7 @@
static int rio_set_real_termios(void *ptr)
{
- return RIOParam((struct Port *) ptr, CONFIG, 1, 1);
+ return RIOParam((struct Port *) ptr, RIOC_CONFIG, 1, 1);
}
@@ -487,7 +487,7 @@
int rv;
func_enter();
- rv = (PortP->ModemState & MSVR1_CD) != 0;
+ rv = (PortP->ModemState & RIOC_MSVR1_CD) != 0;
rio_dprintk(RIO_DEBUG_INIT, "Getting CD status: %d\n", rv);
@@ -607,7 +607,8 @@
rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
rc = -EIO;
} else {
- if (RIOShortCommand(p, PortP, SBREAK, 2, 250) == RIO_FAIL) {
+ if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2, 250) ==
+ RIO_FAIL) {
rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
rc = -EIO;
}
@@ -622,7 +623,8 @@
l = arg ? arg * 100 : 250;
if (l > 255)
l = 255;
- if (RIOShortCommand(p, PortP, SBREAK, 2, arg ? arg * 100 : 250) == RIO_FAIL) {
+ if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2,
+ arg ? arg * 100 : 250) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
rc = -EIO;
}
diff --git a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h
index dc3f005..7f26cd7 100644
--- a/drivers/char/rio/rio_linux.h
+++ b/drivers/char/rio/rio_linux.h
@@ -186,9 +186,9 @@
#ifdef DEBUG
#define rio_dprintk(f, str...) do { if (rio_debug & f) printk (str);} while (0)
-#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __FUNCTION__)
-#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __FUNCTION__)
-#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__FUNCTION__, port->line)
+#define func_enter() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s\n", __func__)
+#define func_exit() rio_dprintk (RIO_DEBUG_FLOW, "rio: exit %s\n", __func__)
+#define func_enter2() rio_dprintk (RIO_DEBUG_FLOW, "rio: enter %s (port %d)\n",__func__, port->line)
#else
#define rio_dprintk(f, str...) /* nothing */
#define func_enter()
diff --git a/drivers/char/rio/riocmd.c b/drivers/char/rio/riocmd.c
index bf36959..7b96e08 100644
--- a/drivers/char/rio/riocmd.c
+++ b/drivers/char/rio/riocmd.c
@@ -417,7 +417,7 @@
PortP = p->RIOPortp[SysPort];
rio_spin_lock_irqsave(&PortP->portSem, flags);
switch (readb(&PktCmdP->Command)) {
- case BREAK_RECEIVED:
+ case RIOC_BREAK_RECEIVED:
rio_dprintk(RIO_DEBUG_CMD, "Received a break!\n");
/* If the current line disc. is not multi-threading and
the current processor is not the default, reset rup_intr
@@ -428,16 +428,16 @@
gs_got_break(&PortP->gs);
break;
- case COMPLETE:
+ case RIOC_COMPLETE:
rio_dprintk(RIO_DEBUG_CMD, "Command complete on phb %d host %Zd\n", readb(&PktCmdP->PhbNum), HostP - p->RIOHosts);
subCommand = 1;
switch (readb(&PktCmdP->SubCommand)) {
- case MEMDUMP:
+ case RIOC_MEMDUMP:
rio_dprintk(RIO_DEBUG_CMD, "Memory dump cmd (0x%x) from addr 0x%x\n", readb(&PktCmdP->SubCommand), readw(&PktCmdP->SubAddr));
break;
- case READ_REGISTER:
+ case RIOC_READ_REGISTER:
rio_dprintk(RIO_DEBUG_CMD, "Read register (0x%x)\n", readw(&PktCmdP->SubAddr));
- p->CdRegister = (readb(&PktCmdP->ModemStatus) & MSVR1_HOST);
+ p->CdRegister = (readb(&PktCmdP->ModemStatus) & RIOC_MSVR1_HOST);
break;
default:
subCommand = 0;
@@ -456,14 +456,15 @@
rio_dprintk(RIO_DEBUG_CMD, "No change\n");
/* FALLTHROUGH */
- case MODEM_STATUS:
+ case RIOC_MODEM_STATUS:
/*
** Knock out the tbusy and tstop bits, as these are not relevant
** to the check for modem status change (they're just there because
** it's a convenient place to put them!).
*/
ReportedModemStatus = readb(&PktCmdP->ModemStatus);
- if ((PortP->ModemState & MSVR1_HOST) == (ReportedModemStatus & MSVR1_HOST)) {
+ if ((PortP->ModemState & RIOC_MSVR1_HOST) ==
+ (ReportedModemStatus & RIOC_MSVR1_HOST)) {
rio_dprintk(RIO_DEBUG_CMD, "Modem status unchanged 0x%x\n", PortP->ModemState);
/*
** Update ModemState just in case tbusy or tstop states have
@@ -497,7 +498,7 @@
/*
** Is there a carrier?
*/
- if (PortP->ModemState & MSVR1_CD) {
+ if (PortP->ModemState & RIOC_MSVR1_CD) {
/*
** Has carrier just appeared?
*/
@@ -691,7 +692,7 @@
*/
rio_spin_unlock_irqrestore(&UnixRupP->RupLock, flags);
FreeMe = RIOCommandRup(p, Rup, HostP, PacketP);
- if (readb(&PacketP->data[5]) == MEMDUMP) {
+ if (readb(&PacketP->data[5]) == RIOC_MEMDUMP) {
rio_dprintk(RIO_DEBUG_CMD, "Memdump from 0x%x complete\n", readw(&(PacketP->data[6])));
rio_memcpy_fromio(p->RIOMemDump, &(PacketP->data[8]), 32);
}
diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
index d8eb2bc..d65ceb9 100644
--- a/drivers/char/rio/rioctrl.c
+++ b/drivers/char/rio/rioctrl.c
@@ -422,7 +422,8 @@
}
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RESUME) == RIO_FAIL) {
+ if (RIOPreemptiveCmd(p, (p->RIOPortp[port]), RIOC_RESUME) ==
+ RIO_FAIL) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_RESUME failed\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
return -EBUSY;
@@ -636,7 +637,8 @@
return -ENXIO;
}
PortP = (p->RIOPortp[PortTty.port]);
- RIOParam(PortP, CONFIG, PortP->State & RIO_MODEM, OK_TO_SLEEP);
+ RIOParam(PortP, RIOC_CONFIG, PortP->State & RIO_MODEM,
+ OK_TO_SLEEP);
return retval;
case RIO_SET_PORT_PARAMS:
@@ -1247,7 +1249,7 @@
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (RIOPreemptiveCmd(p, PortP, MEMDUMP) == RIO_FAIL) {
+ if (RIOPreemptiveCmd(p, PortP, RIOC_MEMDUMP) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_MEM_DUMP failed\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
return -EBUSY;
@@ -1313,7 +1315,8 @@
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (RIOPreemptiveCmd(p, PortP, READ_REGISTER) == RIO_FAIL) {
+ if (RIOPreemptiveCmd(p, PortP, RIOC_READ_REGISTER) ==
+ RIO_FAIL) {
rio_dprintk(RIO_DEBUG_CTRL, "RIO_READ_REGISTER failed\n");
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
return -EBUSY;
@@ -1434,50 +1437,50 @@
PktCmdP->PhbNum = port;
switch (Cmd) {
- case MEMDUMP:
+ case RIOC_MEMDUMP:
rio_dprintk(RIO_DEBUG_CTRL, "Queue MEMDUMP command blk %p "
"(addr 0x%x)\n", CmdBlkP, (int) SubCmd.Addr);
- PktCmdP->SubCommand = MEMDUMP;
+ PktCmdP->SubCommand = RIOC_MEMDUMP;
PktCmdP->SubAddr = SubCmd.Addr;
break;
- case FCLOSE:
+ case RIOC_FCLOSE:
rio_dprintk(RIO_DEBUG_CTRL, "Queue FCLOSE command blk %p\n",
CmdBlkP);
break;
- case READ_REGISTER:
+ case RIOC_READ_REGISTER:
rio_dprintk(RIO_DEBUG_CTRL, "Queue READ_REGISTER (0x%x) "
"command blk %p\n", (int) SubCmd.Addr, CmdBlkP);
- PktCmdP->SubCommand = READ_REGISTER;
+ PktCmdP->SubCommand = RIOC_READ_REGISTER;
PktCmdP->SubAddr = SubCmd.Addr;
break;
- case RESUME:
+ case RIOC_RESUME:
rio_dprintk(RIO_DEBUG_CTRL, "Queue RESUME command blk %p\n",
CmdBlkP);
break;
- case RFLUSH:
+ case RIOC_RFLUSH:
rio_dprintk(RIO_DEBUG_CTRL, "Queue RFLUSH command blk %p\n",
CmdBlkP);
CmdBlkP->PostFuncP = RIORFlushEnable;
break;
- case SUSPEND:
+ case RIOC_SUSPEND:
rio_dprintk(RIO_DEBUG_CTRL, "Queue SUSPEND command blk %p\n",
CmdBlkP);
break;
- case MGET:
+ case RIOC_MGET:
rio_dprintk(RIO_DEBUG_CTRL, "Queue MGET command blk %p\n",
CmdBlkP);
break;
- case MSET:
- case MBIC:
- case MBIS:
+ case RIOC_MSET:
+ case RIOC_MBIC:
+ case RIOC_MBIS:
CmdBlkP->Packet.data[4] = (char) PortP->ModemLines;
rio_dprintk(RIO_DEBUG_CTRL, "Queue MSET/MBIC/MBIS command "
"blk %p\n", CmdBlkP);
break;
- case WFLUSH:
+ case RIOC_WFLUSH:
/*
** If we have queued up the maximum number of Write flushes
** allowed then we should not bother sending any more to the
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
index 4734e26..ea21686 100644
--- a/drivers/char/rio/riointr.c
+++ b/drivers/char/rio/riointr.c
@@ -401,9 +401,8 @@
PortP->InUse = NOT_INUSE;
rio_spin_unlock(&PortP->portSem);
- if (RIOParam(PortP, OPEN, ((PortP->Cor2Copy & (COR2_RTSFLOW | COR2_CTSFLOW)) == (COR2_RTSFLOW | COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL) {
+ if (RIOParam(PortP, RIOC_OPEN, ((PortP->Cor2Copy & (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) == (RIOC_COR2_RTSFLOW | RIOC_COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL)
continue; /* with next port */
- }
rio_spin_lock(&PortP->portSem);
PortP->MagicFlags &= ~MAGIC_REBOOT;
}
@@ -429,7 +428,7 @@
*/
PktCmdP = (struct PktCmd __iomem *) &PacketP->data[0];
- writeb(WFLUSH, &PktCmdP->Command);
+ writeb(RIOC_WFLUSH, &PktCmdP->Command);
p = PortP->HostPort % (u16) PORTS_PER_RTA;
diff --git a/drivers/char/rio/rioparam.c b/drivers/char/rio/rioparam.c
index da276ed..4810b84 100644
--- a/drivers/char/rio/rioparam.c
+++ b/drivers/char/rio/rioparam.c
@@ -177,7 +177,7 @@
}
rio_spin_lock_irqsave(&PortP->portSem, flags);
- if (cmd == OPEN) {
+ if (cmd == RIOC_OPEN) {
/*
** If the port is set to store or lock the parameters, and it is
** paramed with OPEN, we want to restore the saved port termio, but
@@ -241,50 +241,50 @@
case CS5:
{
rio_dprintk(RIO_DEBUG_PARAM, "5 bit data\n");
- Cor1 |= COR1_5BITS;
+ Cor1 |= RIOC_COR1_5BITS;
break;
}
case CS6:
{
rio_dprintk(RIO_DEBUG_PARAM, "6 bit data\n");
- Cor1 |= COR1_6BITS;
+ Cor1 |= RIOC_COR1_6BITS;
break;
}
case CS7:
{
rio_dprintk(RIO_DEBUG_PARAM, "7 bit data\n");
- Cor1 |= COR1_7BITS;
+ Cor1 |= RIOC_COR1_7BITS;
break;
}
case CS8:
{
rio_dprintk(RIO_DEBUG_PARAM, "8 bit data\n");
- Cor1 |= COR1_8BITS;
+ Cor1 |= RIOC_COR1_8BITS;
break;
}
}
if (TtyP->termios->c_cflag & CSTOPB) {
rio_dprintk(RIO_DEBUG_PARAM, "2 stop bits\n");
- Cor1 |= COR1_2STOP;
+ Cor1 |= RIOC_COR1_2STOP;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "1 stop bit\n");
- Cor1 |= COR1_1STOP;
+ Cor1 |= RIOC_COR1_1STOP;
}
if (TtyP->termios->c_cflag & PARENB) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable parity\n");
- Cor1 |= COR1_NORMAL;
+ Cor1 |= RIOC_COR1_NORMAL;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Disable parity\n");
- Cor1 |= COR1_NOP;
+ Cor1 |= RIOC_COR1_NOP;
}
if (TtyP->termios->c_cflag & PARODD) {
rio_dprintk(RIO_DEBUG_PARAM, "Odd parity\n");
- Cor1 |= COR1_ODD;
+ Cor1 |= RIOC_COR1_ODD;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Even parity\n");
- Cor1 |= COR1_EVEN;
+ Cor1 |= RIOC_COR1_EVEN;
}
/*
@@ -292,11 +292,11 @@
*/
if (TtyP->termios->c_iflag & IXON) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop output control\n");
- Cor2 |= COR2_IXON;
+ Cor2 |= RIOC_COR2_IXON;
} else {
if (PortP->Config & RIO_IXON) {
rio_dprintk(RIO_DEBUG_PARAM, "Force enable start/stop output control\n");
- Cor2 |= COR2_IXON;
+ Cor2 |= RIOC_COR2_IXON;
} else
rio_dprintk(RIO_DEBUG_PARAM, "IXON has been disabled.\n");
}
@@ -304,29 +304,29 @@
if (TtyP->termios->c_iflag & IXANY) {
if (PortP->Config & RIO_IXANY) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable any key to restart output\n");
- Cor2 |= COR2_IXANY;
+ Cor2 |= RIOC_COR2_IXANY;
} else
rio_dprintk(RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n");
}
if (TtyP->termios->c_iflag & IXOFF) {
rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop input control 2\n");
- Cor2 |= COR2_IXOFF;
+ Cor2 |= RIOC_COR2_IXOFF;
}
if (TtyP->termios->c_cflag & HUPCL) {
rio_dprintk(RIO_DEBUG_PARAM, "Hangup on last close\n");
- Cor2 |= COR2_HUPCL;
+ Cor2 |= RIOC_COR2_HUPCL;
}
if (C_CRTSCTS(TtyP)) {
rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n");
- Cor2 |= COR2_CTSFLOW;
- Cor2 |= COR2_RTSFLOW;
+ Cor2 |= RIOC_COR2_CTSFLOW;
+ Cor2 |= RIOC_COR2_RTSFLOW;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n");
- Cor2 &= ~COR2_CTSFLOW;
- Cor2 &= ~COR2_RTSFLOW;
+ Cor2 &= ~RIOC_COR2_CTSFLOW;
+ Cor2 &= ~RIOC_COR2_RTSFLOW;
}
@@ -341,36 +341,36 @@
*/
if (TtyP->termios->c_iflag & IGNBRK) {
rio_dprintk(RIO_DEBUG_PARAM, "Ignore break condition\n");
- Cor4 |= COR4_IGNBRK;
+ Cor4 |= RIOC_COR4_IGNBRK;
}
if (!(TtyP->termios->c_iflag & BRKINT)) {
rio_dprintk(RIO_DEBUG_PARAM, "Break generates NULL condition\n");
- Cor4 |= COR4_NBRKINT;
+ Cor4 |= RIOC_COR4_NBRKINT;
} else {
rio_dprintk(RIO_DEBUG_PARAM, "Interrupt on break condition\n");
}
if (TtyP->termios->c_iflag & INLCR) {
rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage return on input\n");
- Cor4 |= COR4_INLCR;
+ Cor4 |= RIOC_COR4_INLCR;
}
if (TtyP->termios->c_iflag & IGNCR) {
rio_dprintk(RIO_DEBUG_PARAM, "Ignore carriage return on input\n");
- Cor4 |= COR4_IGNCR;
+ Cor4 |= RIOC_COR4_IGNCR;
}
if (TtyP->termios->c_iflag & ICRNL) {
rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on input\n");
- Cor4 |= COR4_ICRNL;
+ Cor4 |= RIOC_COR4_ICRNL;
}
if (TtyP->termios->c_iflag & IGNPAR) {
rio_dprintk(RIO_DEBUG_PARAM, "Ignore characters with parity errors\n");
- Cor4 |= COR4_IGNPAR;
+ Cor4 |= RIOC_COR4_IGNPAR;
}
if (TtyP->termios->c_iflag & PARMRK) {
rio_dprintk(RIO_DEBUG_PARAM, "Mark parity errors\n");
- Cor4 |= COR4_PARMRK;
+ Cor4 |= RIOC_COR4_PARMRK;
}
/*
@@ -378,22 +378,22 @@
** on reception of a config packet.
** The download code handles the zero baud condition.
*/
- Cor4 |= COR4_RAISEMOD;
+ Cor4 |= RIOC_COR4_RAISEMOD;
/*
** COR 5
*/
- Cor5 = COR5_CMOE;
+ Cor5 = RIOC_COR5_CMOE;
/*
** Set to monitor tbusy/tstop (or not).
*/
if (PortP->MonitorTstate)
- Cor5 |= COR5_TSTATE_ON;
+ Cor5 |= RIOC_COR5_TSTATE_ON;
else
- Cor5 |= COR5_TSTATE_OFF;
+ Cor5 |= RIOC_COR5_TSTATE_OFF;
/*
** Could set LNE here if you wanted LNext processing. SVR4 will use it.
@@ -401,24 +401,24 @@
if (TtyP->termios->c_iflag & ISTRIP) {
rio_dprintk(RIO_DEBUG_PARAM, "Strip input characters\n");
if (!(PortP->State & RIO_TRIAD_MODE)) {
- Cor5 |= COR5_ISTRIP;
+ Cor5 |= RIOC_COR5_ISTRIP;
}
}
if (TtyP->termios->c_oflag & ONLCR) {
rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n");
if (PortP->CookMode == COOK_MEDIUM)
- Cor5 |= COR5_ONLCR;
+ Cor5 |= RIOC_COR5_ONLCR;
}
if (TtyP->termios->c_oflag & OCRNL) {
rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on output\n");
if (PortP->CookMode == COOK_MEDIUM)
- Cor5 |= COR5_OCRNL;
+ Cor5 |= RIOC_COR5_OCRNL;
}
if ((TtyP->termios->c_oflag & TABDLY) == TAB3) {
rio_dprintk(RIO_DEBUG_PARAM, "Tab delay 3 set\n");
if (PortP->CookMode == COOK_MEDIUM)
- Cor5 |= COR5_TAB3;
+ Cor5 |= RIOC_COR5_TAB3;
}
/*
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
index 1cb8580..c993548 100644
--- a/drivers/char/rio/riotty.c
+++ b/drivers/char/rio/riotty.c
@@ -211,7 +211,7 @@
rio_dprintk(RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n");
if (repeat_this-- <= 0) {
rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
retval = -EINTR;
goto bombout;
}
@@ -264,7 +264,7 @@
here. If I read the docs correctly the "open"
command piggybacks the parameters immediately.
-- REW */
- RIOParam(PortP, OPEN, 1, OK_TO_SLEEP); /* Open the port */
+ RIOParam(PortP, RIOC_OPEN, 1, OK_TO_SLEEP); /* Open the port */
rio_spin_lock_irqsave(&PortP->portSem, flags);
/*
@@ -275,7 +275,7 @@
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
func_exit();
return -EINTR;
}
@@ -297,7 +297,8 @@
** insert test for carrier here. -- ???
** I already see that test here. What's the deal? -- REW
*/
- if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) {
+ if ((PortP->gs.tty->termios->c_cflag & CLOCAL) ||
+ (PortP->ModemState & RIOC_MSVR1_CD)) {
rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort);
/*
tp->tm.c_state |= CARR_ON;
@@ -325,7 +326,7 @@
** I think it's OK. -- REW
*/
rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", SysPort);
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
/*
tp->tm.c_state &= ~WOPEN;
*/
@@ -416,7 +417,7 @@
*/
PortP->State &= ~RIO_MOPEN;
PortP->State &= ~RIO_CARR_ON;
- PortP->ModemState &= ~MSVR1_CD;
+ PortP->ModemState &= ~RIOC_MSVR1_CD;
/*
** If the device was open as both a Modem and a tty line
** then we need to wimp out here, as the port has not really
@@ -453,7 +454,7 @@
if (repeat_this-- <= 0) {
rv = -EINTR;
rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
goto close_end;
}
rio_dprintk(RIO_DEBUG_TTY, "Calling timeout to flush in closing\n");
@@ -492,8 +493,8 @@
/* Can't call RIOShortCommand with the port locked. */
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
- if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) {
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ if (RIOShortCommand(p, PortP, RIOC_CLOSE, 1, 0) == RIO_FAIL) {
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
rio_spin_lock_irqsave(&PortP->portSem, flags);
goto close_end;
}
@@ -503,7 +504,7 @@
try--;
if (time_after(jiffies, end_time)) {
rio_dprintk(RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
break;
}
rio_dprintk(RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", PortP->PortState & PORT_ISOPEN);
@@ -515,14 +516,14 @@
}
if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n");
- RIOPreemptiveCmd(p, PortP, FCLOSE);
+ RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE);
break;
}
}
rio_spin_lock_irqsave(&PortP->portSem, flags);
rio_dprintk(RIO_DEBUG_TTY, "Close: try was %d on completion\n", try);
- /* RIOPreemptiveCmd(p, PortP, FCLOSE); */
+ /* RIOPreemptiveCmd(p, PortP, RIOC_FCLOSE); */
/*
** 15.10.1998 ARG - ESIL 0761 part fix
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 3f9d0a9..f073c71 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -4,9 +4,9 @@
* Copyright (C) 1994-1996 Dmitry Gorodchanin (pgmdsg@ibi.com)
*
* This code is loosely based on the Linux serial driver, written by
- * Linus Torvalds, Theodore T'so and others. The RISCom/8 card
- * programming info was obtained from various drivers for other OSes
- * (FreeBSD, ISC, etc), but no source code from those drivers were
+ * Linus Torvalds, Theodore T'so and others. The RISCom/8 card
+ * programming info was obtained from various drivers for other OSes
+ * (FreeBSD, ISC, etc), but no source code from those drivers were
* directly included in this driver.
*
*
@@ -33,7 +33,7 @@
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/ioport.h>
@@ -49,7 +49,7 @@
#include <linux/tty_flip.h>
#include <linux/spinlock.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include "riscom8.h"
#include "riscom8_reg.h"
@@ -57,15 +57,15 @@
/* Am I paranoid or not ? ;-) */
#define RISCOM_PARANOIA_CHECK
-/*
- * Crazy InteliCom/8 boards sometimes has swapped CTS & DSR signals.
+/*
+ * Crazy InteliCom/8 boards sometimes have swapped CTS & DSR signals.
* You can slightly speed up things by #undefing the following option,
- * if you are REALLY sure that your board is correct one.
+ * if you are REALLY sure that your board is correct one.
*/
#define RISCOM_BRAIN_DAMAGED_CTS
-/*
+/*
* The following defines are mostly for testing purposes. But if you need
* some nice reporting in your syslog, you can define them also.
*/
@@ -112,7 +112,7 @@
#define RC_NIOPORT ARRAY_SIZE(rc_ioport)
-static inline int rc_paranoia_check(struct riscom_port const * port,
+static int rc_paranoia_check(struct riscom_port const *port,
char *name, const char *routine)
{
#ifdef RISCOM_PARANOIA_CHECK
@@ -134,52 +134,53 @@
}
/*
- *
+ *
* Service functions for RISCom/8 driver.
- *
+ *
*/
/* Get board number from pointer */
-static inline int board_No (struct riscom_board const * bp)
+static inline int board_No(struct riscom_board const *bp)
{
return bp - rc_board;
}
/* Get port number from pointer */
-static inline int port_No (struct riscom_port const * port)
+static inline int port_No(struct riscom_port const *port)
{
- return RC_PORT(port - rc_port);
+ return RC_PORT(port - rc_port);
}
/* Get pointer to board from pointer to port */
-static inline struct riscom_board * port_Board(struct riscom_port const * port)
+static inline struct riscom_board *port_Board(struct riscom_port const *port)
{
return &rc_board[RC_BOARD(port - rc_port)];
}
/* Input Byte from CL CD180 register */
-static inline unsigned char rc_in(struct riscom_board const * bp, unsigned short reg)
+static inline unsigned char rc_in(struct riscom_board const *bp,
+ unsigned short reg)
{
return inb(bp->base + RC_TO_ISA(reg));
}
/* Output Byte to CL CD180 register */
-static inline void rc_out(struct riscom_board const * bp, unsigned short reg,
+static inline void rc_out(struct riscom_board const *bp, unsigned short reg,
unsigned char val)
{
outb(val, bp->base + RC_TO_ISA(reg));
}
/* Wait for Channel Command Register ready */
-static inline void rc_wait_CCR(struct riscom_board const * bp)
+static void rc_wait_CCR(struct riscom_board const *bp)
{
unsigned long delay;
/* FIXME: need something more descriptive then 100000 :) */
- for (delay = 100000; delay; delay--)
+ for (delay = 100000; delay; delay--)
if (!rc_in(bp, CD180_CCR))
return;
-
+
printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
}
@@ -187,11 +188,11 @@
* RISCom/8 probe functions.
*/
-static inline int rc_request_io_range(struct riscom_board * const bp)
+static int rc_request_io_range(struct riscom_board * const bp)
{
int i;
-
- for (i = 0; i < RC_NIOPORT; i++)
+
+ for (i = 0; i < RC_NIOPORT; i++)
if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
"RISCom/8")) {
goto out_release;
@@ -200,42 +201,42 @@
out_release:
printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
board_No(bp), bp->base);
- while(--i >= 0)
+ while (--i >= 0)
release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
return 1;
}
-static inline void rc_release_io_range(struct riscom_board * const bp)
+static void rc_release_io_range(struct riscom_board * const bp)
{
int i;
-
- for (i = 0; i < RC_NIOPORT; i++)
+
+ for (i = 0; i < RC_NIOPORT; i++)
release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
}
-
+
/* Reset and setup CD180 chip */
-static void __init rc_init_CD180(struct riscom_board const * bp)
+static void __init rc_init_CD180(struct riscom_board const *bp)
{
unsigned long flags;
-
+
spin_lock_irqsave(&riscom_lock, flags);
- rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
- rc_wait_CCR(bp); /* Wait for CCR ready */
- rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
+ rc_out(bp, RC_CTOUT, 0); /* Clear timeout */
+ rc_wait_CCR(bp); /* Wait for CCR ready */
+ rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */
spin_unlock_irqrestore(&riscom_lock, flags);
- msleep(50); /* Delay 0.05 sec */
+ msleep(50); /* Delay 0.05 sec */
spin_lock_irqsave(&riscom_lock, flags);
- rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
- rc_out(bp, CD180_GICR, 0); /* Clear all bits */
- rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
- rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for transmitter intr */
- rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for receiver intr */
-
+ rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */
+ rc_out(bp, CD180_GICR, 0); /* Clear all bits */
+ rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */
+ rc_out(bp, CD180_PILR2, RC_ACK_TINT); /* Prio for tx intr */
+ rc_out(bp, CD180_PILR3, RC_ACK_RINT); /* Prio for rx intr */
+
/* Setting up prescaler. We need 4 ticks per 1 ms */
rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8);
rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff);
-
+
spin_unlock_irqrestore(&riscom_lock, flags);
}
@@ -245,12 +246,12 @@
unsigned char val1, val2;
int irqs = 0;
int retries;
-
+
bp->irq = 0;
if (rc_request_io_range(bp))
return 1;
-
+
/* Are the I/O ports here ? */
rc_out(bp, CD180_PPRL, 0x5a);
outb(0xff, 0x80);
@@ -258,34 +259,34 @@
rc_out(bp, CD180_PPRL, 0xa5);
outb(0x00, 0x80);
val2 = rc_in(bp, CD180_PPRL);
-
+
if ((val1 != 0x5a) || (val2 != 0xa5)) {
printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
board_No(bp), bp->base);
goto out_release;
}
-
+
/* It's time to find IRQ for this board */
- for (retries = 0; retries < 5 && irqs <= 0; retries++) {
+ for (retries = 0; retries < 5 && irqs <= 0; retries++) {
irqs = probe_irq_on();
- rc_init_CD180(bp); /* Reset CD180 chip */
- rc_out(bp, CD180_CAR, 2); /* Select port 2 */
+ rc_init_CD180(bp); /* Reset CD180 chip */
+ rc_out(bp, CD180_CAR, 2); /* Select port 2 */
rc_wait_CCR(bp);
- rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
- rc_out(bp, CD180_IER, IER_TXRDY); /* Enable tx empty intr */
+ rc_out(bp, CD180_CCR, CCR_TXEN); /* Enable transmitter */
+ rc_out(bp, CD180_IER, IER_TXRDY);/* Enable tx empty intr */
msleep(50);
irqs = probe_irq_off(irqs);
- val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
- val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
- rc_init_CD180(bp); /* Reset CD180 again */
-
+ val1 = rc_in(bp, RC_BSR); /* Get Board Status reg */
+ val2 = rc_in(bp, RC_ACK_TINT); /* ACK interrupt */
+ rc_init_CD180(bp); /* Reset CD180 again */
+
if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) {
printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
"found.\n", board_No(bp), bp->base);
goto out_release;
}
}
-
+
if (irqs <= 0) {
printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
"at 0x%03x.\n", board_No(bp), bp->base);
@@ -293,113 +294,112 @@
}
bp->irq = irqs;
bp->flags |= RC_BOARD_PRESENT;
-
+
printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
"0x%03x, IRQ %d.\n",
board_No(bp),
(rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */
bp->base, bp->irq);
-
+
return 0;
out_release:
rc_release_io_range(bp);
return 1;
}
-/*
- *
+/*
+ *
* Interrupt processing routines.
- *
+ *
*/
-static inline struct riscom_port * rc_get_port(struct riscom_board const * bp,
- unsigned char const * what)
+static struct riscom_port *rc_get_port(struct riscom_board const *bp,
+ unsigned char const *what)
{
unsigned char channel;
- struct riscom_port * port;
-
+ struct riscom_port *port;
+
channel = rc_in(bp, CD180_GICR) >> GICR_CHAN_OFF;
if (channel < CD180_NCH) {
port = &rc_port[board_No(bp) * RC_NPORT + channel];
- if (port->flags & ASYNC_INITIALIZED) {
+ if (port->flags & ASYNC_INITIALIZED)
return port;
- }
}
- printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
+ printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
board_No(bp), what, channel);
return NULL;
}
-static inline void rc_receive_exc(struct riscom_board const * bp)
+static void rc_receive_exc(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char status;
unsigned char ch, flag;
-
- if (!(port = rc_get_port(bp, "Receive")))
+
+ port = rc_get_port(bp, "Receive");
+ if (port == NULL)
return;
tty = port->tty;
-
-#ifdef RC_REPORT_OVERRUN
+
+#ifdef RC_REPORT_OVERRUN
status = rc_in(bp, CD180_RCSR);
if (status & RCSR_OE)
port->overrun++;
status &= port->mark_mask;
-#else
+#else
status = rc_in(bp, CD180_RCSR) & port->mark_mask;
-#endif
+#endif
ch = rc_in(bp, CD180_RDR);
- if (!status) {
+ if (!status)
return;
- }
if (status & RCSR_TOUT) {
printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
- "Hardware problems ?\n",
+ "Hardware problems ?\n",
board_No(bp), port_No(port));
return;
-
+
} else if (status & RCSR_BREAK) {
printk(KERN_INFO "rc%d: port %d: Handling break...\n",
board_No(bp), port_No(port));
flag = TTY_BREAK;
if (port->flags & ASYNC_SAK)
do_SAK(tty);
-
- } else if (status & RCSR_PE)
+
+ } else if (status & RCSR_PE)
flag = TTY_PARITY;
-
- else if (status & RCSR_FE)
+
+ else if (status & RCSR_FE)
flag = TTY_FRAME;
-
- else if (status & RCSR_OE)
+
+ else if (status & RCSR_OE)
flag = TTY_OVERRUN;
-
else
flag = TTY_NORMAL;
-
+
tty_insert_flip_char(tty, ch, flag);
tty_flip_buffer_push(tty);
}
-static inline void rc_receive(struct riscom_board const * bp)
+static void rc_receive(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char count;
-
- if (!(port = rc_get_port(bp, "Receive")))
+
+ port = rc_get_port(bp, "Receive");
+ if (port == NULL)
return;
-
+
tty = port->tty;
-
+
count = rc_in(bp, CD180_RDCR);
-
+
#ifdef RC_REPORT_FIFO
port->hits[count > 8 ? 9 : count]++;
-#endif
-
+#endif
+
while (count--) {
if (tty_buffer_request_room(tty, 1) == 0) {
printk(KERN_WARNING "rc%d: port %d: Working around "
@@ -412,26 +412,26 @@
tty_flip_buffer_push(tty);
}
-static inline void rc_transmit(struct riscom_board const * bp)
+static void rc_transmit(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char count;
-
-
- if (!(port = rc_get_port(bp, "Transmit")))
+
+ port = rc_get_port(bp, "Transmit");
+ if (port == NULL)
return;
-
+
tty = port->tty;
-
- if (port->IER & IER_TXEMPTY) {
+
+ if (port->IER & IER_TXEMPTY) {
/* FIFO drained */
rc_out(bp, CD180_CAR, port_No(port));
port->IER &= ~IER_TXEMPTY;
rc_out(bp, CD180_IER, port->IER);
return;
}
-
+
if ((port->xmit_cnt <= 0 && !port->break_length)
|| tty->stopped || tty->hw_stopped) {
rc_out(bp, CD180_CAR, port_No(port));
@@ -439,7 +439,7 @@
rc_out(bp, CD180_IER, port->IER);
return;
}
-
+
if (port->break_length) {
if (port->break_length > 0) {
if (port->COR2 & COR2_ETC) {
@@ -451,7 +451,8 @@
rc_out(bp, CD180_TDR, CD180_C_ESC);
rc_out(bp, CD180_TDR, CD180_C_DELAY);
rc_out(bp, CD180_TDR, count);
- if (!(port->break_length -= count))
+ port->break_length -= count;
+ if (port->break_length == 0)
port->break_length--;
} else {
rc_out(bp, CD180_TDR, CD180_C_ESC);
@@ -463,7 +464,7 @@
}
return;
}
-
+
count = CD180_NFIFO;
do {
rc_out(bp, CD180_TDR, port->xmit_buf[port->xmit_tail++]);
@@ -471,7 +472,7 @@
if (--port->xmit_cnt <= 0)
break;
} while (--count > 0);
-
+
if (port->xmit_cnt <= 0) {
rc_out(bp, CD180_CAR, port_No(port));
port->IER &= ~IER_TXRDY;
@@ -481,25 +482,26 @@
tty_wakeup(tty);
}
-static inline void rc_check_modem(struct riscom_board const * bp)
+static void rc_check_modem(struct riscom_board const *bp)
{
struct riscom_port *port;
struct tty_struct *tty;
unsigned char mcr;
-
- if (!(port = rc_get_port(bp, "Modem")))
+
+ port = rc_get_port(bp, "Modem");
+ if (port == NULL)
return;
-
+
tty = port->tty;
-
+
mcr = rc_in(bp, CD180_MCR);
- if (mcr & MCR_CDCHG) {
- if (rc_in(bp, CD180_MSVR) & MSVR_CD)
+ if (mcr & MCR_CDCHG) {
+ if (rc_in(bp, CD180_MSVR) & MSVR_CD)
wake_up_interruptible(&port->open_wait);
else
tty_hangup(tty);
}
-
+
#ifdef RISCOM_BRAIN_DAMAGED_CTS
if (mcr & MCR_CTSCHG) {
if (rc_in(bp, CD180_MSVR) & MSVR_CTS) {
@@ -526,13 +528,13 @@
rc_out(bp, CD180_IER, port->IER);
}
#endif /* RISCOM_BRAIN_DAMAGED_CTS */
-
+
/* Clear change bits */
rc_out(bp, CD180_MCR, 0);
}
/* The main interrupt processing routine */
-static irqreturn_t rc_interrupt(int dummy, void * dev_id)
+static irqreturn_t rc_interrupt(int dummy, void *dev_id)
{
unsigned char status;
unsigned char ack;
@@ -547,13 +549,11 @@
(RC_BSR_TOUT | RC_BSR_TINT |
RC_BSR_MINT | RC_BSR_RINT))) {
handled = 1;
- if (status & RC_BSR_TOUT)
+ if (status & RC_BSR_TOUT)
printk(KERN_WARNING "rc%d: Got timeout. Hardware "
"error?\n", board_No(bp));
-
else if (status & RC_BSR_RINT) {
ack = rc_in(bp, RC_ACK_RINT);
-
if (ack == (RC_ID | GIVR_IT_RCV))
rc_receive(bp);
else if (ack == (RC_ID | GIVR_IT_REXC))
@@ -562,29 +562,23 @@
printk(KERN_WARNING "rc%d: Bad receive ack "
"0x%02x.\n",
board_No(bp), ack);
-
} else if (status & RC_BSR_TINT) {
ack = rc_in(bp, RC_ACK_TINT);
-
if (ack == (RC_ID | GIVR_IT_TX))
rc_transmit(bp);
else
printk(KERN_WARNING "rc%d: Bad transmit ack "
"0x%02x.\n",
board_No(bp), ack);
-
} else /* if (status & RC_BSR_MINT) */ {
ack = rc_in(bp, RC_ACK_MINT);
-
- if (ack == (RC_ID | GIVR_IT_MODEM))
+ if (ack == (RC_ID | GIVR_IT_MODEM))
rc_check_modem(bp);
else
printk(KERN_WARNING "rc%d: Bad modem ack "
"0x%02x.\n",
board_No(bp), ack);
-
- }
-
+ }
rc_out(bp, CD180_EOIR, 0); /* Mark end of interrupt */
rc_out(bp, RC_CTOUT, 0); /* Clear timeout flag */
}
@@ -596,24 +590,24 @@
*/
/* Called with disabled interrupts */
-static int rc_setup_board(struct riscom_board * bp)
+static int rc_setup_board(struct riscom_board *bp)
{
int error;
- if (bp->flags & RC_BOARD_ACTIVE)
+ if (bp->flags & RC_BOARD_ACTIVE)
return 0;
-
+
error = request_irq(bp->irq, rc_interrupt, IRQF_DISABLED,
"RISCom/8", bp);
- if (error)
+ if (error)
return error;
-
+
rc_out(bp, RC_CTOUT, 0); /* Just in case */
bp->DTR = ~0;
rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
-
+
bp->flags |= RC_BOARD_ACTIVE;
-
+
return 0;
}
@@ -622,40 +616,40 @@
{
if (!(bp->flags & RC_BOARD_ACTIVE))
return;
-
+
bp->flags &= ~RC_BOARD_ACTIVE;
-
+
free_irq(bp->irq, NULL);
-
+
bp->DTR = ~0;
rc_out(bp, RC_DTR, bp->DTR); /* Drop DTR on all ports */
-
+
}
/*
- * Setting up port characteristics.
+ * Setting up port characteristics.
* Must be called with disabled interrupts
*/
static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
{
- struct tty_struct *tty;
+ struct tty_struct *tty = port->tty;
unsigned long baud;
long tmp;
unsigned char cor1 = 0, cor3 = 0;
unsigned char mcor1 = 0, mcor2 = 0;
-
- if (!(tty = port->tty) || !tty->termios)
+
+ if (tty == NULL || tty->termios == NULL)
return;
port->IER = 0;
port->COR2 = 0;
port->MSVR = MSVR_RTS;
-
+
baud = tty_get_baud_rate(tty);
-
+
/* Select port on the board */
rc_out(bp, CD180_CAR, port_No(port));
-
+
if (!baud) {
/* Drop DTR & exit */
bp->DTR |= (1u << port_No(port));
@@ -666,69 +660,68 @@
bp->DTR &= ~(1u << port_No(port));
rc_out(bp, RC_DTR, bp->DTR);
}
-
+
/*
- * Now we must calculate some speed depended things
+ * Now we must calculate some speed depended things
*/
-
+
/* Set baud rate for port */
tmp = (((RC_OSCFREQ + baud/2) / baud +
CD180_TPC/2) / CD180_TPC);
- rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
- rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
- rc_out(bp, CD180_RBPRL, tmp & 0xff);
+ rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
+ rc_out(bp, CD180_TBPRH, (tmp >> 8) & 0xff);
+ rc_out(bp, CD180_RBPRL, tmp & 0xff);
rc_out(bp, CD180_TBPRL, tmp & 0xff);
-
+
baud = (baud + 5) / 10; /* Estimated CPS */
-
+
/* Two timer ticks seems enough to wakeup something like SLIP driver */
- tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
+ tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
port->wakeup_chars = (tmp < 0) ? 0 : ((tmp >= SERIAL_XMIT_SIZE) ?
SERIAL_XMIT_SIZE - 1 : tmp);
-
+
/* Receiver timeout will be transmission time for 1.5 chars */
tmp = (RISCOM_TPS + RISCOM_TPS/2 + baud/2) / baud;
tmp = (tmp > 0xff) ? 0xff : tmp;
rc_out(bp, CD180_RTPR, tmp);
-
- switch (C_CSIZE(tty)) {
- case CS5:
+
+ switch (C_CSIZE(tty)) {
+ case CS5:
cor1 |= COR1_5BITS;
break;
- case CS6:
+ case CS6:
cor1 |= COR1_6BITS;
break;
- case CS7:
+ case CS7:
cor1 |= COR1_7BITS;
break;
- case CS8:
+ case CS8:
cor1 |= COR1_8BITS;
break;
}
-
- if (C_CSTOPB(tty))
+ if (C_CSTOPB(tty))
cor1 |= COR1_2SB;
-
+
cor1 |= COR1_IGNORE;
- if (C_PARENB(tty)) {
+ if (C_PARENB(tty)) {
cor1 |= COR1_NORMPAR;
- if (C_PARODD(tty))
+ if (C_PARODD(tty))
cor1 |= COR1_ODDP;
- if (I_INPCK(tty))
+ if (I_INPCK(tty))
cor1 &= ~COR1_IGNORE;
}
/* Set marking of some errors */
port->mark_mask = RCSR_OE | RCSR_TOUT;
- if (I_INPCK(tty))
+ if (I_INPCK(tty))
port->mark_mask |= RCSR_FE | RCSR_PE;
- if (I_BRKINT(tty) || I_PARMRK(tty))
+ if (I_BRKINT(tty) || I_PARMRK(tty))
port->mark_mask |= RCSR_BREAK;
- if (I_IGNPAR(tty))
+ if (I_IGNPAR(tty))
port->mark_mask &= ~(RCSR_FE | RCSR_PE);
- if (I_IGNBRK(tty)) {
+ if (I_IGNBRK(tty)) {
port->mark_mask &= ~RCSR_BREAK;
- if (I_IGNPAR(tty))
+ if (I_IGNPAR(tty))
/* Real raw mode. Ignore all */
port->mark_mask &= ~RCSR_OE;
}
@@ -738,7 +731,8 @@
port->IER |= IER_DSR | IER_CTS;
mcor1 |= MCOR1_DSRZD | MCOR1_CTSZD;
mcor2 |= MCOR2_DSROD | MCOR2_CTSOD;
- tty->hw_stopped = !(rc_in(bp, CD180_MSVR) & (MSVR_CTS|MSVR_DSR));
+ tty->hw_stopped = !(rc_in(bp, CD180_MSVR) &
+ (MSVR_CTS|MSVR_DSR));
#else
port->COR2 |= COR2_CTSAE;
#endif
@@ -761,13 +755,13 @@
mcor1 |= MCOR1_CDZD;
mcor2 |= MCOR2_CDOD;
}
-
- if (C_CREAD(tty))
+
+ if (C_CREAD(tty))
/* Enable receiver */
port->IER |= IER_RXD;
-
+
/* Set input FIFO size (1-8 bytes) */
- cor3 |= RISCOM_RXFIFO;
+ cor3 |= RISCOM_RXFIFO;
/* Setting up CD180 channel registers */
rc_out(bp, CD180_COR1, cor1);
rc_out(bp, CD180_COR2, port->COR2);
@@ -791,36 +785,30 @@
static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port)
{
unsigned long flags;
-
+
if (port->flags & ASYNC_INITIALIZED)
return 0;
-
+
if (!port->xmit_buf) {
/* We may sleep in get_zeroed_page() */
- unsigned long tmp;
-
- if (!(tmp = get_zeroed_page(GFP_KERNEL)))
+ unsigned long tmp = get_zeroed_page(GFP_KERNEL);
+ if (tmp == 0)
return -ENOMEM;
-
- if (port->xmit_buf) {
+ if (port->xmit_buf)
free_page(tmp);
- return -ERESTARTSYS;
- }
- port->xmit_buf = (unsigned char *) tmp;
+ else
+ port->xmit_buf = (unsigned char *) tmp;
}
-
spin_lock_irqsave(&riscom_lock, flags);
- if (port->tty)
+ if (port->tty)
clear_bit(TTY_IO_ERROR, &port->tty->flags);
-
- if (port->count == 1)
+ if (port->count == 1)
bp->count++;
-
port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
rc_change_speed(bp, port);
port->flags |= ASYNC_INITIALIZED;
-
+
spin_unlock_irqrestore(&riscom_lock, flags);
return 0;
}
@@ -829,38 +817,39 @@
static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port)
{
struct tty_struct *tty;
-
- if (!(port->flags & ASYNC_INITIALIZED))
+
+ if (!(port->flags & ASYNC_INITIALIZED))
return;
-
+
#ifdef RC_REPORT_OVERRUN
printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
board_No(bp), port_No(port), port->overrun);
-#endif
+#endif
#ifdef RC_REPORT_FIFO
{
int i;
-
+
printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
board_No(bp), port_No(port));
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < 10; i++)
printk("%ld ", port->hits[i]);
- }
printk("].\n");
}
-#endif
+#endif
if (port->xmit_buf) {
free_page((unsigned long) port->xmit_buf);
port->xmit_buf = NULL;
}
- if (!(tty = port->tty) || C_HUPCL(tty)) {
+ tty = port->tty;
+
+ if (tty == NULL || C_HUPCL(tty)) {
/* Drop DTR */
bp->DTR |= (1u << port_No(port));
rc_out(bp, RC_DTR, bp->DTR);
}
-
- /* Select port */
+
+ /* Select port */
rc_out(bp, CD180_CAR, port_No(port));
/* Reset port */
rc_wait_CCR(bp);
@@ -868,28 +857,26 @@
/* Disable all interrupts from this port */
port->IER = 0;
rc_out(bp, CD180_IER, port->IER);
-
- if (tty)
+
+ if (tty)
set_bit(TTY_IO_ERROR, &tty->flags);
port->flags &= ~ASYNC_INITIALIZED;
-
+
if (--bp->count < 0) {
printk(KERN_INFO "rc%d: rc_shutdown_port: "
"bad board count: %d\n",
board_No(bp), bp->count);
bp->count = 0;
}
-
/*
* If this is the last opened port on the board
* shutdown whole board
*/
- if (!bp->count)
+ if (!bp->count)
rc_shutdown_board(bp);
}
-
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
+static int block_til_ready(struct tty_struct *tty, struct file *filp,
struct riscom_port *port)
{
DECLARE_WAITQUEUE(wait, current);
@@ -921,7 +908,7 @@
return 0;
}
- if (C_CLOCAL(tty))
+ if (C_CLOCAL(tty))
do_clocal = 1;
/*
@@ -959,7 +946,7 @@
if (port->flags & ASYNC_HUP_NOTIFY)
retval = -EAGAIN;
else
- retval = -ERESTARTSYS;
+ retval = -ERESTARTSYS;
break;
}
if (!(port->flags & ASYNC_CLOSING) &&
@@ -978,50 +965,63 @@
port->blocked_open--;
if (retval)
return retval;
-
+
port->flags |= ASYNC_NORMAL_ACTIVE;
return 0;
-}
+}
-static int rc_open(struct tty_struct * tty, struct file * filp)
+static int rc_open(struct tty_struct *tty, struct file *filp)
{
int board;
int error;
- struct riscom_port * port;
- struct riscom_board * bp;
-
+ struct riscom_port *port;
+ struct riscom_board *bp;
+
board = RC_BOARD(tty->index);
if (board >= RC_NBOARD || !(rc_board[board].flags & RC_BOARD_PRESENT))
return -ENODEV;
-
+
bp = &rc_board[board];
port = rc_port + board * RC_NPORT + RC_PORT(tty->index);
if (rc_paranoia_check(port, tty->name, "rc_open"))
return -ENODEV;
-
- if ((error = rc_setup_board(bp)))
+
+ error = rc_setup_board(bp);
+ if (error)
return error;
-
+
port->count++;
tty->driver_data = port;
port->tty = tty;
-
- if ((error = rc_setup_port(bp, port)))
- return error;
-
- if ((error = block_til_ready(tty, filp, port)))
- return error;
-
- return 0;
+
+ error = rc_setup_port(bp, port);
+ if (error == 0)
+ error = block_til_ready(tty, filp, port);
+ return error;
}
-static void rc_close(struct tty_struct * tty, struct file * filp)
+static void rc_flush_buffer(struct tty_struct *tty)
+{
+ struct riscom_port *port = (struct riscom_port *)tty->driver_data;
+ unsigned long flags;
+
+ if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
+ return;
+
+ spin_lock_irqsave(&riscom_lock, flags);
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ spin_unlock_irqrestore(&riscom_lock, flags);
+
+ tty_wakeup(tty);
+}
+
+static void rc_close(struct tty_struct *tty, struct file *filp)
{
struct riscom_port *port = (struct riscom_port *) tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
unsigned long timeout;
-
+
if (!port || rc_paranoia_check(port, tty->name, "close"))
return;
@@ -1029,7 +1029,7 @@
if (tty_hung_up_p(filp))
goto out;
-
+
bp = port_Board(port);
if ((tty->count == 1) && (port->count != 1)) {
printk(KERN_INFO "rc%d: rc_close: bad port count;"
@@ -1047,7 +1047,7 @@
goto out;
port->flags |= ASYNC_CLOSING;
/*
- * Now we wait for the transmit buffer to clear; and we notify
+ * Now we wait for the transmit buffer to clear; and we notify
* the line discipline to only process XON/XOFF characters.
*/
tty->closing = 1;
@@ -1070,24 +1070,22 @@
* has completely drained; this is especially
* important if there is a transmit FIFO!
*/
- timeout = jiffies+HZ;
- while(port->IER & IER_TXEMPTY) {
+ timeout = jiffies + HZ;
+ while (port->IER & IER_TXEMPTY) {
msleep_interruptible(jiffies_to_msecs(port->timeout));
if (time_after(jiffies, timeout))
break;
}
}
rc_shutdown_port(bp, port);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rc_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
port->tty = NULL;
if (port->blocked_open) {
- if (port->close_delay) {
+ if (port->close_delay)
msleep_interruptible(jiffies_to_msecs(port->close_delay));
- }
wake_up_interruptible(&port->open_wait);
}
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING);
@@ -1097,17 +1095,17 @@
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static int rc_write(struct tty_struct * tty,
+static int rc_write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
int c, total = 0;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_write"))
return 0;
-
+
bp = port_Board(port);
if (!tty || !port->xmit_buf)
@@ -1144,38 +1142,41 @@
return total;
}
-static void rc_put_char(struct tty_struct * tty, unsigned char ch)
+static int rc_put_char(struct tty_struct *tty, unsigned char ch)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
+ int ret = 0;
if (rc_paranoia_check(port, tty->name, "rc_put_char"))
- return;
+ return 0;
if (!tty || !port->xmit_buf)
- return;
+ return 0;
spin_lock_irqsave(&riscom_lock, flags);
-
+
if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
goto out;
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++;
+ ret = 1;
out:
spin_unlock_irqrestore(&riscom_lock, flags);
+ return ret;
}
-static void rc_flush_chars(struct tty_struct * tty)
+static void rc_flush_chars(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))
return;
-
+
if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
!port->xmit_buf)
return;
@@ -1189,11 +1190,11 @@
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static int rc_write_room(struct tty_struct * tty)
+static int rc_write_room(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
int ret;
-
+
if (rc_paranoia_check(port, tty->name, "rc_write_room"))
return 0;
@@ -1206,39 +1207,22 @@
static int rc_chars_in_buffer(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
-
+
if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))
return 0;
-
+
return port->xmit_cnt;
}
-static void rc_flush_buffer(struct tty_struct *tty)
-{
- struct riscom_port *port = (struct riscom_port *)tty->driver_data;
- unsigned long flags;
-
- if (rc_paranoia_check(port, tty->name, "rc_flush_buffer"))
- return;
-
- spin_lock_irqsave(&riscom_lock, flags);
-
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
-
- spin_unlock_irqrestore(&riscom_lock, flags);
-
- tty_wakeup(tty);
-}
-
static int rc_tiocmget(struct tty_struct *tty, struct file *file)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
- struct riscom_board * bp;
+ struct riscom_board *bp;
unsigned char status;
unsigned int result;
unsigned long flags;
- if (rc_paranoia_check(port, tty->name, __FUNCTION__))
+ if (rc_paranoia_check(port, tty->name, __func__))
return -ENODEV;
bp = port_Board(port);
@@ -1266,7 +1250,7 @@
unsigned long flags;
struct riscom_board *bp;
- if (rc_paranoia_check(port, tty->name, __FUNCTION__))
+ if (rc_paranoia_check(port, tty->name, __func__))
return -ENODEV;
bp = port_Board(port);
@@ -1292,11 +1276,11 @@
return 0;
}
-static inline void rc_send_break(struct riscom_port * port, unsigned long length)
+static void rc_send_break(struct riscom_port *port, unsigned long length)
{
struct riscom_board *bp = port_Board(port);
unsigned long flags;
-
+
spin_lock_irqsave(&riscom_lock, flags);
port->break_length = RISCOM_TPS / HZ * length;
@@ -1312,17 +1296,17 @@
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static inline int rc_set_serial_info(struct riscom_port * port,
- struct serial_struct __user * newinfo)
+static int rc_set_serial_info(struct riscom_port *port,
+ struct serial_struct __user *newinfo)
{
struct serial_struct tmp;
struct riscom_board *bp = port_Board(port);
int change_speed;
-
+
if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
return -EFAULT;
-
-#if 0
+
+#if 0
if ((tmp.irq != bp->irq) ||
(tmp.port != bp->base) ||
(tmp.type != PORT_CIRRUS) ||
@@ -1331,16 +1315,16 @@
(tmp.xmit_fifo_size != CD180_NFIFO) ||
(tmp.flags & ~RISCOM_LEGAL_FLAGS))
return -EINVAL;
-#endif
-
+#endif
+
change_speed = ((port->flags & ASYNC_SPD_MASK) !=
(tmp.flags & ASYNC_SPD_MASK));
-
+
if (!capable(CAP_SYS_ADMIN)) {
if ((tmp.close_delay != port->close_delay) ||
(tmp.closing_wait != port->closing_wait) ||
((tmp.flags & ~ASYNC_USR_MASK) !=
- (port->flags & ~ASYNC_USR_MASK)))
+ (port->flags & ~ASYNC_USR_MASK)))
return -EPERM;
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
(tmp.flags & ASYNC_USR_MASK));
@@ -1360,12 +1344,12 @@
return 0;
}
-static inline int rc_get_serial_info(struct riscom_port * port,
+static int rc_get_serial_info(struct riscom_port *port,
struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
struct riscom_board *bp = port_Board(port);
-
+
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_CIRRUS;
tmp.line = port - rc_port;
@@ -1379,19 +1363,18 @@
return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
-static int rc_ioctl(struct tty_struct * tty, struct file * filp,
+static int rc_ioctl(struct tty_struct *tty, struct file *filp,
unsigned int cmd, unsigned long arg)
-
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
void __user *argp = (void __user *)arg;
- int retval;
-
+ int retval = 0;
+
if (rc_paranoia_check(port, tty->name, "rc_ioctl"))
return -ENODEV;
-
+
switch (cmd) {
- case TCSBRK: /* SVID version: non-zero arg --> no break */
+ case TCSBRK: /* SVID version: non-zero arg --> no break */
retval = tty_check_change(tty);
if (retval)
return retval;
@@ -1399,45 +1382,40 @@
if (!arg)
rc_send_break(port, HZ/4); /* 1/4 second */
break;
- case TCSBRKP: /* support for POSIX tcsendbreak() */
+ case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
if (retval)
return retval;
tty_wait_until_sent(tty, 0);
rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
break;
- case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned __user *)argp);
- case TIOCSSOFTCAR:
- if (get_user(arg,(unsigned __user *) argp))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
+ case TIOCGSERIAL:
+ lock_kernel();
+ retval = rc_get_serial_info(port, argp);
+ unlock_kernel();
break;
- case TIOCGSERIAL:
- return rc_get_serial_info(port, argp);
- case TIOCSSERIAL:
- return rc_set_serial_info(port, argp);
- default:
- return -ENOIOCTLCMD;
+ case TIOCSSERIAL:
+ lock_kernel();
+ retval = rc_set_serial_info(port, argp);
+ unlock_kernel();
+ break;
+ default:
+ retval = -ENOIOCTLCMD;
}
- return 0;
+ return retval;
}
-static void rc_throttle(struct tty_struct * tty)
+static void rc_throttle(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_throttle"))
return;
-
bp = port_Board(port);
spin_lock_irqsave(&riscom_lock, flags);
-
port->MSVR &= ~MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
if (I_IXOFF(tty)) {
@@ -1446,23 +1424,20 @@
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_unthrottle(struct tty_struct * tty)
+static void rc_unthrottle(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))
return;
-
bp = port_Board(port);
-
- spin_lock_irqsave(&riscom_lock, flags);
+ spin_lock_irqsave(&riscom_lock, flags);
port->MSVR |= MSVR_RTS;
rc_out(bp, CD180_CAR, port_No(port));
if (I_IXOFF(tty)) {
@@ -1471,62 +1446,58 @@
rc_wait_CCR(bp);
}
rc_out(bp, CD180_MSVR, port->MSVR);
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_stop(struct tty_struct * tty)
+static void rc_stop(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_stop"))
return;
-
- bp = port_Board(port);
-
- spin_lock_irqsave(&riscom_lock, flags);
+ bp = port_Board(port);
+
+ spin_lock_irqsave(&riscom_lock, flags);
port->IER &= ~IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_start(struct tty_struct * tty)
+static void rc_start(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_start"))
return;
-
+
bp = port_Board(port);
-
+
spin_lock_irqsave(&riscom_lock, flags);
- if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
+ if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
rc_out(bp, CD180_CAR, port_No(port));
rc_out(bp, CD180_IER, port->IER);
}
-
spin_unlock_irqrestore(&riscom_lock, flags);
}
-static void rc_hangup(struct tty_struct * tty)
+static void rc_hangup(struct tty_struct *tty)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
struct riscom_board *bp;
-
+
if (rc_paranoia_check(port, tty->name, "rc_hangup"))
return;
-
+
bp = port_Board(port);
-
+
rc_shutdown_port(bp, port);
port->count = 0;
port->flags &= ~ASYNC_NORMAL_ACTIVE;
@@ -1534,17 +1505,14 @@
wake_up_interruptible(&port->open_wait);
}
-static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termios)
+static void rc_set_termios(struct tty_struct *tty,
+ struct ktermios *old_termios)
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
unsigned long flags;
-
+
if (rc_paranoia_check(port, tty->name, "rc_set_termios"))
return;
-
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
- return;
spin_lock_irqsave(&riscom_lock, flags);
rc_change_speed(port_Board(port), port);
@@ -1583,9 +1551,9 @@
int i;
riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);
- if (!riscom_driver)
+ if (!riscom_driver)
return -ENOMEM;
-
+
riscom_driver->owner = THIS_MODULE;
riscom_driver->name = "ttyL";
riscom_driver->major = RISCOM8_NORMAL_MAJOR;
@@ -1598,23 +1566,21 @@
riscom_driver->init_termios.c_ospeed = 9600;
riscom_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(riscom_driver, &riscom_ops);
- if ((error = tty_register_driver(riscom_driver))) {
+ error = tty_register_driver(riscom_driver);
+ if (error != 0) {
put_tty_driver(riscom_driver);
printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
- "error = %d\n",
- error);
+ "error = %d\n", error);
return 1;
}
-
memset(rc_port, 0, sizeof(rc_port));
for (i = 0; i < RC_NPORT * RC_NBOARD; i++) {
rc_port[i].magic = RISCOM8_MAGIC;
- rc_port[i].close_delay = 50 * HZ/100;
- rc_port[i].closing_wait = 3000 * HZ/100;
+ rc_port[i].close_delay = 50 * HZ / 100;
+ rc_port[i].closing_wait = 3000 * HZ / 100;
init_waitqueue_head(&rc_port[i].open_wait);
init_waitqueue_head(&rc_port[i].close_wait);
}
-
return 0;
}
@@ -1627,13 +1593,13 @@
#ifndef MODULE
/*
* Called at boot time.
- *
+ *
* You can specify IO base for up to RC_NBOARD cards,
* using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt.
* Note that there will be no probing at default
* addresses in this case.
*
- */
+ */
static int __init riscom8_setup(char *str)
{
int ints[RC_NBOARD];
@@ -1644,7 +1610,7 @@
for (i = 0; i < RC_NBOARD; i++) {
if (i < ints[0])
rc_board[i].base = ints[i+1];
- else
+ else
rc_board[i].base = 0;
}
return 1;
@@ -1659,8 +1625,8 @@
static char no_boards_msg[] __initdata =
KERN_INFO "rc: No RISCom/8 boards detected.\n";
-/*
- * This routine must be called by kernel at boot time
+/*
+ * This routine must be called by kernel at boot time
*/
static int __init riscom8_init(void)
{
@@ -1669,13 +1635,12 @@
printk(banner);
- if (rc_init_drivers())
+ if (rc_init_drivers())
return -EIO;
- for (i = 0; i < RC_NBOARD; i++)
- if (rc_board[i].base && !rc_probe(&rc_board[i]))
+ for (i = 0; i < RC_NBOARD; i++)
+ if (rc_board[i].base && !rc_probe(&rc_board[i]))
found++;
-
if (!found) {
rc_release_drivers();
printk(no_boards_msg);
@@ -1702,13 +1667,13 @@
* by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter.
*
*/
-static int __init riscom8_init_module (void)
+static int __init riscom8_init_module(void)
{
#ifdef MODULE
int i;
if (iobase || iobase1 || iobase2 || iobase3) {
- for(i = 0; i < RC_NBOARD; i++)
+ for (i = 0; i < RC_NBOARD; i++)
rc_board[i].base = 0;
}
@@ -1724,18 +1689,17 @@
return riscom8_init();
}
-
-static void __exit riscom8_exit_module (void)
+
+static void __exit riscom8_exit_module(void)
{
int i;
-
+
rc_release_drivers();
- for (i = 0; i < RC_NBOARD; i++)
- if (rc_board[i].flags & RC_BOARD_PRESENT)
+ for (i = 0; i < RC_NBOARD; i++)
+ if (rc_board[i].flags & RC_BOARD_PRESENT)
rc_release_io_range(&rc_board[i]);
-
+
}
module_init(riscom8_init_module);
module_exit(riscom8_exit_module);
-
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index f585bc8..743dc80 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -449,7 +449,8 @@
while (1) {
if (tty->stopped || tty->hw_stopped)
break;
- c = min(info->xmit_fifo_room, min(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail));
+ c = min(info->xmit_fifo_room, info->xmit_cnt);
+ c = min(c, XMIT_BUF_SIZE - info->xmit_tail);
if (c <= 0 || info->xmit_fifo_room <= 0)
break;
sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2);
@@ -1433,29 +1434,38 @@
{
struct r_port *info = (struct r_port *) tty->driver_data;
void __user *argp = (void __user *)arg;
+ int ret = 0;
if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))
return -ENXIO;
+ lock_kernel();
+
switch (cmd) {
case RCKP_GET_STRUCT:
if (copy_to_user(argp, info, sizeof (struct r_port)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
case RCKP_GET_CONFIG:
- return get_config(info, argp);
+ ret = get_config(info, argp);
+ break;
case RCKP_SET_CONFIG:
- return set_config(info, argp);
+ ret = set_config(info, argp);
+ break;
case RCKP_GET_PORTS:
- return get_ports(info, argp);
+ ret = get_ports(info, argp);
+ break;
case RCKP_RESET_RM2:
- return reset_rm2(info, argp);
+ ret = reset_rm2(info, argp);
+ break;
case RCKP_GET_VERSION:
- return get_version(info, argp);
+ ret = get_version(info, argp);
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -ENOIOCTLCMD;
}
- return 0;
+ unlock_kernel();
+ return ret;
}
static void rp_send_xchar(struct tty_struct *tty, char ch)
@@ -1575,6 +1585,7 @@
jiffies);
printk(KERN_INFO "cps=%d...\n", info->cps);
#endif
+ lock_kernel();
while (1) {
txcnt = sGetTxCnt(cp);
if (!txcnt) {
@@ -1602,6 +1613,7 @@
break;
}
__set_current_state(TASK_RUNNING);
+ unlock_kernel();
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies);
#endif
@@ -1651,14 +1663,14 @@
* writing routines will write directly to transmit FIFO.
* Write buffer and counters protected by spinlocks
*/
-static void rp_put_char(struct tty_struct *tty, unsigned char ch)
+static int rp_put_char(struct tty_struct *tty, unsigned char ch)
{
struct r_port *info = (struct r_port *) tty->driver_data;
CHANNEL_t *cp;
unsigned long flags;
if (rocket_paranoia_check(info, "rp_put_char"))
- return;
+ return 0;
/*
* Grab the port write mutex, locking out other processes that try to
@@ -1687,6 +1699,7 @@
}
spin_unlock_irqrestore(&info->slock, flags);
mutex_unlock(&info->write_mtx);
+ return 1;
}
/*
@@ -1749,10 +1762,10 @@
/* Write remaining data into the port's xmit_buf */
while (1) {
- if (!info->tty) /* Seemingly obligatory check... */
+ if (!info->tty) /* Seemingly obligatory check... */
goto end;
-
- c = min(count, min(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head));
+ c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
+ c = min(c, XMIT_BUF_SIZE - info->xmit_head);
if (c <= 0)
break;
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index b01d381..143cc43 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -55,7 +55,7 @@
static inline void out32(unsigned short port, Byte_t *p)
{
- u32 value = le32_to_cpu(get_unaligned((__le32 *)p));
+ u32 value = get_unaligned_le32(p);
#ifdef ROCKET_DEBUG_IO
printk(KERN_DEBUG "out32(%x, %lx)...\n", port, value);
#endif
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index e2ec2ee..5f80a9d 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -1069,10 +1069,8 @@
}
#ifdef CONFIG_PROC_FS
- ent = create_proc_entry("driver/rtc", 0, NULL);
- if (ent)
- ent->proc_fops = &rtc_proc_fops;
- else
+ ent = proc_create("driver/rtc", 0, NULL, &rtc_proc_fops);
+ if (!ent)
printk(KERN_WARNING "rtc: Failed to register with procfs.\n");
#endif
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index df8cd0c..fd2db07 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -1060,7 +1060,7 @@
} /* config_setup */
-static void cy_put_char(struct tty_struct *tty, unsigned char ch)
+static int cy_put_char(struct tty_struct *tty, unsigned char ch)
{
struct cyclades_port *info = (struct cyclades_port *)tty->driver_data;
unsigned long flags;
@@ -1070,7 +1070,7 @@
#endif
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
- return;
+ return 0;
if (!info->xmit_buf)
return;
@@ -1078,13 +1078,14 @@
local_irq_save(flags);
if (info->xmit_cnt >= PAGE_SIZE - 1) {
local_irq_restore(flags);
- return;
+ return 0;
}
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= PAGE_SIZE - 1;
info->xmit_cnt++;
local_irq_restore(flags);
+ return 1;
} /* cy_put_char */
static void cy_flush_chars(struct tty_struct *tty)
@@ -1539,6 +1540,8 @@
printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
#endif
+ lock_kernel();
+
switch (cmd) {
case CYGETMON:
ret_val = get_mon_info(info, argp);
@@ -1584,18 +1587,6 @@
break;
/* The following commands are incompletely implemented!!! */
- case TIOCGSOFTCAR:
- ret_val =
- put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long __user *)argp);
- break;
- case TIOCSSOFTCAR:
- ret_val = get_user(val, (unsigned long __user *)argp);
- if (ret_val)
- break;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0));
- break;
case TIOCGSERIAL:
ret_val = get_serial_info(info, argp);
break;
@@ -1605,6 +1596,7 @@
default:
ret_val = -ENOIOCTLCMD;
}
+ unlock_kernel();
#ifdef SERIAL_DEBUG_OTHER
printk("cy_ioctl done\n");
@@ -1683,8 +1675,7 @@
if (info->flags & ASYNC_INITIALIZED)
tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ cy_flush_buffer(tty);
tty_ldisc_flush(tty);
info->tty = NULL;
if (info->blocked_open) {
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index b9c1dba..8fe099a 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -80,7 +80,7 @@
sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
if (sd == NULL) {
printk("%s: couldn't allocate subchannel data\n",
- __FUNCTION__);
+ __func__);
return -ENOMEM;
}
@@ -90,7 +90,7 @@
if (sd->sd_subch < 0) {
kfree(sd);
- printk("%s: couldn't allocate subchannel\n", __FUNCTION__);
+ printk("%s: couldn't allocate subchannel\n", __func__);
return -EBUSY;
}
@@ -110,7 +110,7 @@
if (rv) {
ia64_sn_irtr_close(sd->sd_nasid, sd->sd_subch);
kfree(sd);
- printk("%s: irq request failed (%d)\n", __FUNCTION__, rv);
+ printk("%s: irq request failed (%d)\n", __func__, rv);
return -EBUSY;
}
@@ -215,7 +215,7 @@
*/
if (count < len) {
pr_debug("%s: only accepting %d of %d bytes\n",
- __FUNCTION__, (int) count, len);
+ __func__, (int) count, len);
}
len = min((int) count, len);
if (copy_to_user(buf, sd->sd_rb, len))
@@ -384,7 +384,7 @@
if (alloc_chrdev_region(&first_dev, 0, num_cnodes,
SYSCTL_BASENAME) < 0) {
printk("%s: failed to register SN system controller device\n",
- __FUNCTION__);
+ __func__);
return -ENODEV;
}
snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME);
@@ -403,7 +403,7 @@
GFP_KERNEL);
if (!scd) {
printk("%s: failed to allocate device info"
- "for %s/%s\n", __FUNCTION__,
+ "for %s/%s\n", __func__,
SYSCTL_BASENAME, devname);
continue;
}
@@ -412,7 +412,7 @@
scd->scd_nasid = cnodeid_to_nasid(cnode);
if (!(salbuf = kmalloc(SCDRV_BUFSZ, GFP_KERNEL))) {
printk("%s: failed to allocate driver buffer"
- "(%s%s)\n", __FUNCTION__,
+ "(%s%s)\n", __func__,
SYSCTL_BASENAME, devname);
kfree(scd);
continue;
@@ -424,7 +424,7 @@
("%s: failed to initialize SAL for"
" system controller communication"
" (%s/%s): outdated PROM?\n",
- __FUNCTION__, SYSCTL_BASENAME, devname);
+ __func__, SYSCTL_BASENAME, devname);
kfree(scd);
kfree(salbuf);
continue;
@@ -435,7 +435,7 @@
if (cdev_add(&scd->scd_cdev, dev, 1)) {
printk("%s: failed to register system"
" controller device (%s%s)\n",
- __FUNCTION__, SYSCTL_BASENAME, devname);
+ __func__, SYSCTL_BASENAME, devname);
kfree(scd);
kfree(salbuf);
continue;
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
index 1b75b0b..53b3d44 100644
--- a/drivers/char/snsc_event.c
+++ b/drivers/char/snsc_event.c
@@ -63,16 +63,13 @@
scdrv_parse_event(char *event, int *src, int *code, int *esp_code, char *desc)
{
char *desc_end;
- __be32 from_buf;
/* record event source address */
- from_buf = get_unaligned((__be32 *)event);
- *src = be32_to_cpup(&from_buf);
+ *src = get_unaligned_be32(event);
event += 4; /* move on to event code */
/* record the system controller's event code */
- from_buf = get_unaligned((__be32 *)event);
- *code = be32_to_cpup(&from_buf);
+ *code = get_unaligned_be32(event);
event += 4; /* move on to event arguments */
/* how many arguments are in the packet? */
@@ -86,8 +83,7 @@
/* not an integer argument, so give up */
return -1;
}
- from_buf = get_unaligned((__be32 *)event);
- *esp_code = be32_to_cpup(&from_buf);
+ *esp_code = get_unaligned_be32(event);
event += 4;
/* parse out the event description */
@@ -275,7 +271,7 @@
event_sd = kzalloc(sizeof (struct subch_data_s), GFP_KERNEL);
if (event_sd == NULL) {
printk(KERN_WARNING "%s: couldn't allocate subchannel info"
- " for event monitoring\n", __FUNCTION__);
+ " for event monitoring\n", __func__);
return;
}
@@ -289,7 +285,7 @@
if (event_sd->sd_subch < 0) {
kfree(event_sd);
printk(KERN_WARNING "%s: couldn't open event subchannel\n",
- __FUNCTION__);
+ __func__);
return;
}
@@ -299,7 +295,7 @@
"system controller events", event_sd);
if (rv) {
printk(KERN_WARNING "%s: irq request failed (%d)\n",
- __FUNCTION__, rv);
+ __func__, rv);
ia64_sn_irtr_close(event_sd->sd_nasid, event_sd->sd_subch);
kfree(event_sd);
return;
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index c03ad16..58533de 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -506,7 +506,7 @@
while (--n && (command)) \
udelay(1); \
if (!n && (verbose || !quiet)) \
- printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __FUNCTION__, __LINE__); \
+ printk(KERN_WARNING "sonypi command failed at %s : %s (line %d)\n", __FILE__, __func__, __LINE__); \
}
#ifdef CONFIG_ACPI
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index 4b5b5b7..2ee4d98 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -131,8 +131,8 @@
#define SX_DEBUG_FIFO 0x0800
-#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__FUNCTION__)
-#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __FUNCTION__)
+#define func_enter() dprintk (SX_DEBUG_FLOW, "io8: enter %s\n",__func__)
+#define func_exit() dprintk (SX_DEBUG_FLOW, "io8: exit %s\n", __func__)
#define jiffies_from_ms(a) ((((a) * HZ)/1000)+1)
@@ -874,7 +874,7 @@
spin_lock_irqsave(&bp->lock, flags);
- dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
+ dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __func__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
if (!(bp->flags & SX_BOARD_ACTIVE)) {
dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", bp->irq);
spin_unlock_irqrestore(&bp->lock, flags);
@@ -1504,6 +1504,27 @@
return 0;
}
+static void sx_flush_buffer(struct tty_struct *tty)
+{
+ struct specialix_port *port = (struct specialix_port *)tty->driver_data;
+ unsigned long flags;
+ struct specialix_board * bp;
+
+ func_enter();
+
+ if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
+ func_exit();
+ return;
+ }
+
+ bp = port_Board(port);
+ spin_lock_irqsave(&port->lock, flags);
+ port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
+ spin_unlock_irqrestore(&port->lock, flags);
+ tty_wakeup(tty);
+
+ func_exit();
+}
static void sx_close(struct tty_struct * tty, struct file * filp)
{
@@ -1597,8 +1618,7 @@
}
sx_shutdown_port(bp, port);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ sx_flush_buffer(tty);
tty_ldisc_flush(tty);
spin_lock_irqsave(&port->lock, flags);
tty->closing = 0;
@@ -1670,7 +1690,7 @@
}
-static void sx_put_char(struct tty_struct * tty, unsigned char ch)
+static int sx_put_char(struct tty_struct * tty, unsigned char ch)
{
struct specialix_port *port = (struct specialix_port *)tty->driver_data;
unsigned long flags;
@@ -1680,12 +1700,12 @@
if (sx_paranoia_check(port, tty->name, "sx_put_char")) {
func_exit();
- return;
+ return 0;
}
dprintk (SX_DEBUG_TX, "check tty: %p %p\n", tty, port->xmit_buf);
if (!port->xmit_buf) {
func_exit();
- return;
+ return 0;
}
bp = port_Board(port);
spin_lock_irqsave(&port->lock, flags);
@@ -1695,7 +1715,7 @@
spin_unlock_irqrestore(&port->lock, flags);
dprintk (SX_DEBUG_TX, "Exit size\n");
func_exit();
- return;
+ return 0;
}
dprintk (SX_DEBUG_TX, "Handle xmit: %p %p\n", port, port->xmit_buf);
port->xmit_buf[port->xmit_head++] = ch;
@@ -1704,6 +1724,7 @@
spin_unlock_irqrestore(&port->lock, flags);
func_exit();
+ return 1;
}
@@ -1770,28 +1791,6 @@
}
-static void sx_flush_buffer(struct tty_struct *tty)
-{
- struct specialix_port *port = (struct specialix_port *)tty->driver_data;
- unsigned long flags;
- struct specialix_board * bp;
-
- func_enter();
-
- if (sx_paranoia_check(port, tty->name, "sx_flush_buffer")) {
- func_exit();
- return;
- }
-
- bp = port_Board(port);
- spin_lock_irqsave(&port->lock, flags);
- port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;
- spin_unlock_irqrestore(&port->lock, flags);
- tty_wakeup(tty);
-
- func_exit();
-}
-
static int sx_tiocmget(struct tty_struct *tty, struct file *file)
{
@@ -1803,7 +1802,7 @@
func_enter();
- if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ if (sx_paranoia_check(port, tty->name, __func__)) {
func_exit();
return -ENODEV;
}
@@ -1845,7 +1844,7 @@
func_enter();
- if (sx_paranoia_check(port, tty->name, __FUNCTION__)) {
+ if (sx_paranoia_check(port, tty->name, __func__)) {
func_exit();
return -ENODEV;
}
@@ -1922,29 +1921,13 @@
int change_speed;
func_enter();
- /*
- if (!access_ok(VERIFY_READ, (void *) newinfo, sizeof(tmp))) {
- func_exit();
- return -EFAULT;
- }
- */
+
if (copy_from_user(&tmp, newinfo, sizeof(tmp))) {
func_enter();
return -EFAULT;
}
-#if 0
- if ((tmp.irq != bp->irq) ||
- (tmp.port != bp->base) ||
- (tmp.type != PORT_CIRRUS) ||
- (tmp.baud_base != (SX_OSCFREQ + CD186x_TPC/2) / CD186x_TPC) ||
- (tmp.custom_divisor != 0) ||
- (tmp.xmit_fifo_size != CD186x_NFIFO) ||
- (tmp.flags & ~SPECIALIX_LEGAL_FLAGS)) {
- func_exit();
- return -EINVAL;
- }
-#endif
+ lock_kernel();
change_speed = ((port->flags & ASYNC_SPD_MASK) !=
(tmp.flags & ASYNC_SPD_MASK));
@@ -1956,6 +1939,7 @@
((tmp.flags & ~ASYNC_USR_MASK) !=
(port->flags & ~ASYNC_USR_MASK))) {
func_exit();
+ unlock_kernel();
return -EPERM;
}
port->flags = ((port->flags & ~ASYNC_USR_MASK) |
@@ -1972,6 +1956,7 @@
sx_change_speed(bp, port);
}
func_exit();
+ unlock_kernel();
return 0;
}
@@ -1984,12 +1969,8 @@
func_enter();
- /*
- if (!access_ok(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)))
- return -EFAULT;
- */
-
memset(&tmp, 0, sizeof(tmp));
+ lock_kernel();
tmp.type = PORT_CIRRUS;
tmp.line = port - sx_port;
tmp.port = bp->base;
@@ -2000,6 +1981,7 @@
tmp.closing_wait = port->closing_wait * HZ/100;
tmp.custom_divisor = port->custom_divisor;
tmp.xmit_fifo_size = CD186x_NFIFO;
+ unlock_kernel();
if (copy_to_user(retinfo, &tmp, sizeof(tmp))) {
func_exit();
return -EFAULT;
@@ -2045,23 +2027,6 @@
sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);
func_exit();
return 0;
- case TIOCGSOFTCAR:
- if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) {
- func_exit();
- return -EFAULT;
- }
- func_exit();
- return 0;
- case TIOCSSOFTCAR:
- if (get_user(arg, (unsigned long __user *) argp)) {
- func_exit();
- return -EFAULT;
- }
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- func_exit();
- return 0;
case TIOCGSERIAL:
func_exit();
return sx_get_serial_info(port, argp);
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 874aaa0..d17be10 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -875,6 +875,7 @@
timeout = HZ;
tend = jiffies + timeout;
+ lock_kernel();
while (stl_datastate(portp)) {
if (signal_pending(current))
break;
@@ -882,6 +883,7 @@
if (time_after_eq(jiffies, tend))
break;
}
+ unlock_kernel();
}
/*****************************************************************************/
@@ -1273,18 +1275,9 @@
rc = 0;
+ lock_kernel();
+
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *) argp);
- break;
- case TIOCSSOFTCAR:
- if (get_user(ival, (unsigned int __user *) arg))
- return -EFAULT;
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- break;
case TIOCGSERIAL:
rc = stl_getserial(portp, argp);
break;
@@ -1308,7 +1301,7 @@
rc = -ENOIOCTLCMD;
break;
}
-
+ unlock_kernel();
return rc;
}
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index a6e1c9b..f39f6fd 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -384,11 +384,11 @@
#define sx_dprintk(f, str...) /* nothing */
#endif
-#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__)
-#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__FUNCTION__)
+#define func_enter() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s\n",__func__)
+#define func_exit() sx_dprintk(SX_DEBUG_FLOW, "sx: exit %s\n",__func__)
#define func_enter2() sx_dprintk(SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
- __FUNCTION__, port->line)
+ __func__, port->line)
/*
* Firmware loader driver specific routines
@@ -1574,7 +1574,7 @@
sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n",
port->gs.count);
/*printk("%s SETTING port count to zero: %p count: %d\n",
- __FUNCTION__, port, port->gs.count);
+ __func__, port, port->gs.count);
port->gs.count = 0;*/
}
@@ -1844,6 +1844,7 @@
int rv;
func_enter();
+ lock_kernel();
if (flag)
rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK);
@@ -1852,7 +1853,7 @@
if (rv != 1)
printk(KERN_ERR "sx: couldn't send break (%x).\n",
read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat)));
-
+ unlock_kernel();
func_exit();
}
@@ -1888,23 +1889,12 @@
int rc;
struct sx_port *port = tty->driver_data;
void __user *argp = (void __user *)arg;
- int ival;
/* func_enter2(); */
rc = 0;
+ lock_kernel();
switch (cmd) {
- case TIOCGSOFTCAR:
- rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned __user *)argp);
- break;
- case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned __user *)argp)) == 0) {
- tty->termios->c_cflag =
- (tty->termios->c_cflag & ~CLOCAL) |
- (ival ? CLOCAL : 0);
- }
- break;
case TIOCGSERIAL:
rc = gs_getserial(&port->gs, argp);
break;
@@ -1915,6 +1905,7 @@
rc = -ENOIOCTLCMD;
break;
}
+ unlock_kernel();
/* func_exit(); */
return rc;
@@ -2549,7 +2540,7 @@
goto err_flag;
}
board->base2 =
- board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
+ board->base = ioremap_nocache(board->hw_base, SI2_EISA_WINDOW_LEN);
if (!board->base) {
dev_err(dev, "can't remap memory\n");
goto err_reg;
@@ -2626,7 +2617,7 @@
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
- rebase = ioremap(hwbase, 0x80);
+ rebase = ioremap_nocache(hwbase, 0x80);
t = readl(rebase + CNTRL_REG_OFFSET);
if (t != CNTRL_REG_GOODVALUE) {
printk(KERN_DEBUG "sx: performing cntrl reg fix: %08x -> "
@@ -2770,7 +2761,7 @@
if (!request_region(board->hw_base, board->hw_len, "sx"))
continue;
board->base2 =
- board->base = ioremap(board->hw_base, board->hw_len);
+ board->base = ioremap_nocache(board->hw_base, board->hw_len);
if (!board->base)
goto err_sx_reg;
board->flags &= ~SX_BOARD_TYPE;
@@ -2794,7 +2785,7 @@
if (!request_region(board->hw_base, board->hw_len, "sx"))
continue;
board->base2 =
- board->base = ioremap(board->hw_base, board->hw_len);
+ board->base = ioremap_nocache(board->hw_base, board->hw_len);
if (!board->base)
goto err_si_reg;
board->flags &= ~SX_BOARD_TYPE;
@@ -2817,7 +2808,7 @@
if (!request_region(board->hw_base, board->hw_len, "sx"))
continue;
board->base2 =
- board->base = ioremap(board->hw_base, board->hw_len);
+ board->base = ioremap_nocache(board->hw_base, board->hw_len);
if (!board->base)
goto err_si1_reg;
board->flags &= ~SX_BOARD_TYPE;
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index fadab1d..ac5080d 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -2026,34 +2026,35 @@
*
* Return Value: None
*/
-static void mgsl_put_char(struct tty_struct *tty, unsigned char ch)
+static int mgsl_put_char(struct tty_struct *tty, unsigned char ch)
{
- struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;
+ struct mgsl_struct *info = tty->driver_data;
unsigned long flags;
+ int ret = 0;
- if ( debug_level >= DEBUG_LEVEL_INFO ) {
- printk( "%s(%d):mgsl_put_char(%d) on %s\n",
- __FILE__,__LINE__,ch,info->device_name);
+ if (debug_level >= DEBUG_LEVEL_INFO) {
+ printk(KERN_DEBUG "%s(%d):mgsl_put_char(%d) on %s\n",
+ __FILE__, __LINE__, ch, info->device_name);
}
if (mgsl_paranoia_check(info, tty->name, "mgsl_put_char"))
- return;
+ return 0;
if (!tty || !info->xmit_buf)
- return;
+ return 0;
- spin_lock_irqsave(&info->irq_spinlock,flags);
+ spin_lock_irqsave(&info->irq_spinlock, flags);
- if ( (info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active ) {
-
+ if ((info->params.mode == MGSL_MODE_ASYNC ) || !info->tx_active) {
if (info->xmit_cnt < SERIAL_XMIT_SIZE - 1) {
info->xmit_buf[info->xmit_head++] = ch;
info->xmit_head &= SERIAL_XMIT_SIZE-1;
info->xmit_cnt++;
+ ret = 1;
}
}
-
- spin_unlock_irqrestore(&info->irq_spinlock,flags);
+ spin_unlock_irqrestore(&info->irq_spinlock, flags);
+ return ret;
} /* end of mgsl_put_char() */
@@ -2942,6 +2943,7 @@
unsigned int cmd, unsigned long arg)
{
struct mgsl_struct * info = (struct mgsl_struct *)tty->driver_data;
+ int ret;
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__,
@@ -2956,7 +2958,10 @@
return -EIO;
}
- return mgsl_ioctl_common(info, cmd, arg);
+ lock_kernel();
+ ret = mgsl_ioctl_common(info, cmd, arg);
+ unlock_kernel();
+ return ret;
}
static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg)
@@ -3153,8 +3158,7 @@
if (info->flags & ASYNC_INITIALIZED)
mgsl_wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ mgsl_flush_buffer(tty);
tty_ldisc_flush(tty);
@@ -3217,7 +3221,8 @@
* interval should also be less than the timeout.
* Note: use tight timings here to satisfy the NIST-PCTS.
*/
-
+
+ lock_kernel();
if ( info->params.data_rate ) {
char_time = info->timeout/(32 * 5);
if (!char_time)
@@ -3247,6 +3252,7 @@
break;
}
}
+ unlock_kernel();
exit:
if (debug_level >= DEBUG_LEVEL_INFO)
@@ -4144,7 +4150,8 @@
}
info->lcr_mem_requested = true;
- info->memory_base = ioremap(info->phys_memory_base,0x40000);
+ info->memory_base = ioremap_nocache(info->phys_memory_base,
+ 0x40000);
if (!info->memory_base) {
printk( "%s(%d):Cant map shared memory on device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
@@ -4157,12 +4164,14 @@
goto errout;
}
- info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE) + info->lcr_offset;
+ info->lcr_base = ioremap_nocache(info->phys_lcr_base,
+ PAGE_SIZE);
if (!info->lcr_base) {
printk( "%s(%d):Cant map LCR memory on device %s MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
goto errout;
}
+ info->lcr_base += info->lcr_offset;
} else {
/* claim DMA channel */
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index f3d8d72..2001b0e 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -151,7 +151,7 @@
static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void put_char(struct tty_struct *tty, unsigned char ch);
+static int put_char(struct tty_struct *tty, unsigned char ch);
static void send_xchar(struct tty_struct *tty, char ch);
static void wait_until_sent(struct tty_struct *tty, int timeout);
static int write_room(struct tty_struct *tty);
@@ -771,8 +771,7 @@
if (info->flags & ASYNC_INITIALIZED)
wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ flush_buffer(tty);
tty_ldisc_flush(tty);
shutdown(info);
@@ -913,20 +912,24 @@
return ret;
}
-static void put_char(struct tty_struct *tty, unsigned char ch)
+static int put_char(struct tty_struct *tty, unsigned char ch)
{
struct slgt_info *info = tty->driver_data;
unsigned long flags;
+ int ret;
if (sanity_check(info, tty->name, "put_char"))
- return;
+ return 0;
DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
if (!info->tx_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active && (info->tx_count < info->max_frame_size))
+ if (!info->tx_active && (info->tx_count < info->max_frame_size)) {
info->tx_buf[info->tx_count++] = ch;
+ ret = 1;
+ }
spin_unlock_irqrestore(&info->lock,flags);
+ return ret;
}
static void send_xchar(struct tty_struct *tty, char ch)
@@ -967,6 +970,8 @@
* Note: use tight timings here to satisfy the NIST-PCTS.
*/
+ lock_kernel();
+
if (info->params.data_rate) {
char_time = info->timeout/(32 * 5);
if (!char_time)
@@ -984,6 +989,7 @@
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
+ unlock_kernel();
exit:
DBGINFO(("%s wait_until_sent exit\n", info->device_name));
@@ -1097,6 +1103,7 @@
struct serial_icounter_struct __user *p_cuser; /* user space */
unsigned long flags;
void __user *argp = (void __user *)arg;
+ int ret;
if (sanity_check(info, tty->name, "ioctl"))
return -ENODEV;
@@ -1108,37 +1115,54 @@
return -EIO;
}
+ lock_kernel();
+
switch (cmd) {
case MGSL_IOCGPARAMS:
- return get_params(info, argp);
+ ret = get_params(info, argp);
+ break;
case MGSL_IOCSPARAMS:
- return set_params(info, argp);
+ ret = set_params(info, argp);
+ break;
case MGSL_IOCGTXIDLE:
- return get_txidle(info, argp);
+ ret = get_txidle(info, argp);
+ break;
case MGSL_IOCSTXIDLE:
- return set_txidle(info, (int)arg);
+ ret = set_txidle(info, (int)arg);
+ break;
case MGSL_IOCTXENABLE:
- return tx_enable(info, (int)arg);
+ ret = tx_enable(info, (int)arg);
+ break;
case MGSL_IOCRXENABLE:
- return rx_enable(info, (int)arg);
+ ret = rx_enable(info, (int)arg);
+ break;
case MGSL_IOCTXABORT:
- return tx_abort(info);
+ ret = tx_abort(info);
+ break;
case MGSL_IOCGSTATS:
- return get_stats(info, argp);
+ ret = get_stats(info, argp);
+ break;
case MGSL_IOCWAITEVENT:
- return wait_mgsl_event(info, argp);
+ ret = wait_mgsl_event(info, argp);
+ break;
case TIOCMIWAIT:
- return modem_input_wait(info,(int)arg);
+ ret = modem_input_wait(info,(int)arg);
+ break;
case MGSL_IOCGIF:
- return get_interface(info, argp);
+ ret = get_interface(info, argp);
+ break;
case MGSL_IOCSIF:
- return set_interface(info,(int)arg);
+ ret = set_interface(info,(int)arg);
+ break;
case MGSL_IOCSGPIO:
- return set_gpio(info, argp);
+ ret = set_gpio(info, argp);
+ break;
case MGSL_IOCGGPIO:
- return get_gpio(info, argp);
+ ret = get_gpio(info, argp);
+ break;
case MGSL_IOCWAITGPIO:
- return wait_gpio(info, argp);
+ ret = wait_gpio(info, argp);
+ break;
case TIOCGICOUNT:
spin_lock_irqsave(&info->lock,flags);
cnow = info->icount;
@@ -1155,12 +1179,14 @@
put_user(cnow.parity, &p_cuser->parity) ||
put_user(cnow.brk, &p_cuser->brk) ||
put_user(cnow.buf_overrun, &p_cuser->buf_overrun))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ ret = 0;
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -ENOIOCTLCMD;
}
- return 0;
+ unlock_kernel();
+ return ret;
}
/*
@@ -3324,7 +3350,7 @@
else
info->reg_addr_requested = true;
- info->reg_addr = ioremap(info->phys_reg_addr, SLGT_REG_SIZE);
+ info->reg_addr = ioremap_nocache(info->phys_reg_addr, SLGT_REG_SIZE);
if (!info->reg_addr) {
DBGERR(("%s cant map device registers, addr=%08X\n",
info->device_name, info->phys_reg_addr));
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index e98c3e6..bec54866 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -519,7 +519,7 @@
static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
static int write(struct tty_struct *tty, const unsigned char *buf, int count);
-static void put_char(struct tty_struct *tty, unsigned char ch);
+static int put_char(struct tty_struct *tty, unsigned char ch);
static void send_xchar(struct tty_struct *tty, char ch);
static void wait_until_sent(struct tty_struct *tty, int timeout);
static int write_room(struct tty_struct *tty);
@@ -862,8 +862,7 @@
if (info->flags & ASYNC_INITIALIZED)
wait_until_sent(tty, info->timeout);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ flush_buffer(tty);
tty_ldisc_flush(tty);
@@ -1046,10 +1045,11 @@
/* Add a character to the transmit buffer.
*/
-static void put_char(struct tty_struct *tty, unsigned char ch)
+static int put_char(struct tty_struct *tty, unsigned char ch)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
unsigned long flags;
+ int ret = 0;
if ( debug_level >= DEBUG_LEVEL_INFO ) {
printk( "%s(%d):%s put_char(%d)\n",
@@ -1057,10 +1057,10 @@
}
if (sanity_check(info, tty->name, "put_char"))
- return;
+ return 0;
if (!info->tx_buf)
- return;
+ return 0;
spin_lock_irqsave(&info->lock,flags);
@@ -1072,10 +1072,12 @@
if (info->tx_put >= info->max_frame_size)
info->tx_put -= info->max_frame_size;
info->tx_count++;
+ ret = 1;
}
}
spin_unlock_irqrestore(&info->lock,flags);
+ return ret;
}
/* Send a high-priority XON/XOFF character
@@ -1119,6 +1121,8 @@
if (sanity_check(info, tty->name, "wait_until_sent"))
return;
+ lock_kernel();
+
if (!(info->flags & ASYNC_INITIALIZED))
goto exit;
@@ -1161,6 +1165,7 @@
}
exit:
+ unlock_kernel();
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s wait_until_sent() exit\n",
__FILE__,__LINE__, info->device_name );
@@ -1176,6 +1181,7 @@
if (sanity_check(info, tty->name, "write_room"))
return 0;
+ lock_kernel();
if (info->params.mode == MGSL_MODE_HDLC) {
ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;
} else {
@@ -1183,6 +1189,7 @@
if (ret < 0)
ret = 0;
}
+ unlock_kernel();
if (debug_level >= DEBUG_LEVEL_INFO)
printk("%s(%d):%s write_room()=%d\n",
@@ -1303,7 +1310,7 @@
*
* Return Value: 0 if success, otherwise error code
*/
-static int ioctl(struct tty_struct *tty, struct file *file,
+static int do_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;
@@ -1393,6 +1400,16 @@
return 0;
}
+static int ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret;
+ lock_kernel();
+ ret = do_ioctl(tty, file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+
/*
* /proc fs routines....
*/
@@ -3626,7 +3643,8 @@
else
info->sca_statctrl_requested = true;
- info->memory_base = ioremap(info->phys_memory_base,SCA_MEM_SIZE);
+ info->memory_base = ioremap_nocache(info->phys_memory_base,
+ SCA_MEM_SIZE);
if (!info->memory_base) {
printk( "%s(%d):%s Cant map shared memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_memory_base );
@@ -3634,7 +3652,7 @@
goto errout;
}
- info->lcr_base = ioremap(info->phys_lcr_base,PAGE_SIZE);
+ info->lcr_base = ioremap_nocache(info->phys_lcr_base, PAGE_SIZE);
if (!info->lcr_base) {
printk( "%s(%d):%s Cant map LCR memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_lcr_base );
@@ -3643,7 +3661,7 @@
}
info->lcr_base += info->lcr_offset;
- info->sca_base = ioremap(info->phys_sca_base,PAGE_SIZE);
+ info->sca_base = ioremap_nocache(info->phys_sca_base, PAGE_SIZE);
if (!info->sca_base) {
printk( "%s(%d):%s Cant map SCA memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_sca_base );
@@ -3652,7 +3670,8 @@
}
info->sca_base += info->sca_offset;
- info->statctrl_base = ioremap(info->phys_statctrl_base,PAGE_SIZE);
+ info->statctrl_base = ioremap_nocache(info->phys_statctrl_base,
+ PAGE_SIZE);
if (!info->statctrl_base) {
printk( "%s(%d):%s Cant map SCA Status/Control memory, MemAddr=%08X\n",
__FILE__,__LINE__,info->device_name, info->phys_statctrl_base );
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 1ade193..9e9bad8b 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -196,6 +196,48 @@
#define sysrq_showlocks_op (*(struct sysrq_key_op *)0)
#endif
+#ifdef CONFIG_SMP
+static DEFINE_SPINLOCK(show_lock);
+
+static void showacpu(void *dummy)
+{
+ unsigned long flags;
+
+ /* Idle CPUs have no interesting backtrace. */
+ if (idle_cpu(smp_processor_id()))
+ return;
+
+ spin_lock_irqsave(&show_lock, flags);
+ printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+ show_stack(NULL, NULL);
+ spin_unlock_irqrestore(&show_lock, flags);
+}
+
+static void sysrq_showregs_othercpus(struct work_struct *dummy)
+{
+ smp_call_function(showacpu, NULL, 0, 0);
+}
+
+static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus);
+
+static void sysrq_handle_showallcpus(int key, struct tty_struct *tty)
+{
+ struct pt_regs *regs = get_irq_regs();
+ if (regs) {
+ printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+ show_regs(regs);
+ }
+ schedule_work(&sysrq_showallcpus);
+}
+
+static struct sysrq_key_op sysrq_showallcpus_op = {
+ .handler = sysrq_handle_showallcpus,
+ .help_msg = "aLlcpus",
+ .action_msg = "Show backtrace of all active CPUs",
+ .enable_mask = SYSRQ_ENABLE_DUMP,
+};
+#endif
+
static void sysrq_handle_showregs(int key, struct tty_struct *tty)
{
struct pt_regs *regs = get_irq_regs();
@@ -340,7 +382,11 @@
&sysrq_kill_op, /* i */
NULL, /* j */
&sysrq_SAK_op, /* k */
+#ifdef CONFIG_SMP
+ &sysrq_showallcpus_op, /* l */
+#else
NULL, /* l */
+#endif
&sysrq_showmem_op, /* m */
&sysrq_unrt_op, /* n */
/* o: This will often be registered as 'Off' at init time */
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c
index ce5ebe3..663cd15d 100644
--- a/drivers/char/toshiba.c
+++ b/drivers/char/toshiba.c
@@ -426,7 +426,7 @@
int i,major,minor,day,year,month,flag;
unsigned char signature[7] = { 0x54,0x4f,0x53,0x48,0x49,0x42,0x41 };
SMMRegisters regs;
- void __iomem *bios = ioremap(0xf0000, 0x10000);
+ void __iomem *bios = ioremap_cache(0xf0000, 0x10000);
if (!bios)
return -ENOMEM;
@@ -520,12 +520,11 @@
{
struct proc_dir_entry *pde;
- pde = create_proc_entry("toshiba", 0, NULL);
+ pde = proc_create("toshiba", 0, NULL, &proc_toshiba_fops);
if (!pde) {
misc_deregister(&tosh_device);
return -ENOMEM;
}
- pde->proc_fops = &proc_toshiba_fops;
}
#endif
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index 8f3f762..3738cfa 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -23,7 +23,7 @@
config TCG_TIS
tristate "TPM Interface Specification 1.2 Interface"
- depends on PNPACPI
+ depends on PNP
---help---
If you have a TPM security chip that is compliant with the
TCG TIS 1.2 TPM specification say Yes and it will be accessible
@@ -32,7 +32,6 @@
config TCG_NSC
tristate "National Semiconductor TPM Interface"
- depends on PNPACPI
---help---
If you have a TPM security chip from National Semiconductor
say Yes and it will be accessible from within Linux. To
@@ -48,7 +47,7 @@
config TCG_INFINEON
tristate "Infineon Technologies TPM Interface"
- depends on PNPACPI
+ depends on PNP
---help---
If you have a TPM security chip from Infineon Technologies
(either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 6313326..ab18c1e 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -264,7 +264,7 @@
static struct platform_device *pdev = NULL;
-static void __devexit tpm_nsc_remove(struct device *dev)
+static void tpm_nsc_remove(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
if ( chip ) {
diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c
index 7722466..3582f43 100644
--- a/drivers/char/tty_audit.c
+++ b/drivers/char/tty_audit.c
@@ -11,6 +11,7 @@
#include <linux/audit.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/tty.h>
struct tty_audit_buf {
@@ -92,7 +93,7 @@
get_task_comm(name, tsk);
audit_log_untrustedstring(ab, name);
audit_log_format(ab, " data=");
- audit_log_n_untrustedstring(ab, buf->valid, buf->data);
+ audit_log_n_untrustedstring(ab, buf->data, buf->valid);
audit_log_end(ab);
}
buf->valid = 0;
@@ -151,14 +152,9 @@
/**
* tty_audit_push_task - Flush task's pending audit data
*/
-void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
+void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
{
struct tty_audit_buf *buf;
- /* FIXME I think this is correct. Check against netlink once that is
- * I really need to read this code more closely. But that's for
- * another patch.
- */
- unsigned int sessionid = audit_get_sessionid(tsk);
spin_lock_irq(&tsk->sighand->siglock);
buf = tsk->signal->tty_audit_buf;
@@ -238,6 +234,10 @@
if (unlikely(size == 0))
return;
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY
+ && tty->driver->subtype == PTY_TYPE_MASTER)
+ return;
+
buf = tty_audit_buf_get(tty);
if (!buf)
return;
@@ -300,53 +300,3 @@
tty_audit_buf_put(buf);
}
}
-
-/**
- * tty_audit_opening - A TTY is being opened.
- *
- * As a special hack, tasks that close all their TTYs and open new ones
- * are assumed to be system daemons (e.g. getty) and auditing is
- * automatically disabled for them.
- */
-void tty_audit_opening(void)
-{
- int disable;
-
- disable = 1;
- spin_lock_irq(¤t->sighand->siglock);
- if (current->signal->audit_tty == 0)
- disable = 0;
- spin_unlock_irq(¤t->sighand->siglock);
- if (!disable)
- return;
-
- task_lock(current);
- if (current->files) {
- struct fdtable *fdt;
- unsigned i;
-
- /*
- * We don't take a ref to the file, so we must hold ->file_lock
- * instead.
- */
- spin_lock(¤t->files->file_lock);
- fdt = files_fdtable(current->files);
- for (i = 0; i < fdt->max_fds; i++) {
- struct file *filp;
-
- filp = fcheck_files(current->files, i);
- if (filp && is_tty(filp)) {
- disable = 0;
- break;
- }
- }
- spin_unlock(¤t->files->file_lock);
- }
- task_unlock(current);
- if (!disable)
- return;
-
- spin_lock_irq(¤t->sighand->siglock);
- current->signal->audit_tty = 0;
- spin_unlock_irq(¤t->sighand->siglock);
-}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 98b65a2..49c1a22 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -78,6 +78,7 @@
#include <linux/tty_flip.h>
#include <linux/devpts_fs.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/console.h>
#include <linux/timer.h>
#include <linux/ctype.h>
@@ -91,7 +92,6 @@
#include <linux/module.h>
#include <linux/smp_lock.h>
#include <linux/device.h>
-#include <linux/idr.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/delay.h>
@@ -137,9 +137,6 @@
#ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
-extern int pty_limit; /* Config limit on Unix98 ptys */
-static DEFINE_IDR(allocated_ptys);
-static DEFINE_MUTEX(allocated_ptys_lock);
static int ptmx_open(struct inode *, struct file *);
#endif
@@ -152,8 +149,7 @@
static unsigned int tty_poll(struct file *, poll_table *);
static int tty_open(struct inode *, struct file *);
static int tty_release(struct inode *, struct file *);
-int tty_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
#ifdef CONFIG_COMPAT
static long tty_compat_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
@@ -1109,8 +1105,8 @@
a reference to the old ldisc. If we ended up flipping back
to the existing ldisc we have two references to it */
- if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc)
- tty->driver->set_ldisc(tty);
+ if (tty->ldisc.num != o_ldisc.num && tty->ops->set_ldisc)
+ tty->ops->set_ldisc(tty);
tty_ldisc_put(o_ldisc.num);
@@ -1182,9 +1178,8 @@
if (*str == '\0')
str = NULL;
- if (tty_line >= 0 && tty_line <= p->num && p->poll_init &&
- !p->poll_init(p, tty_line, str)) {
-
+ if (tty_line >= 0 && tty_line <= p->num && p->ops &&
+ p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
res = p;
*line = tty_line;
break;
@@ -1205,26 +1200,37 @@
* not in the foreground, send a SIGTTOU. If the signal is blocked or
* ignored, go ahead and perform the operation. (POSIX 7.2)
*
- * Locking: none
+ * Locking: ctrl_lock
*/
int tty_check_change(struct tty_struct *tty)
{
+ unsigned long flags;
+ int ret = 0;
+
if (current->signal->tty != tty)
return 0;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+
if (!tty->pgrp) {
printk(KERN_WARNING "tty_check_change: tty->pgrp == NULL!\n");
- return 0;
+ goto out;
}
if (task_pgrp(current) == tty->pgrp)
- return 0;
+ goto out;
if (is_ignored(SIGTTOU))
- return 0;
- if (is_current_pgrp_orphaned())
- return -EIO;
+ goto out;
+ if (is_current_pgrp_orphaned()) {
+ ret = -EIO;
+ goto out;
+ }
kill_pgrp(task_pgrp(current), SIGTTOU, 1);
set_thread_flag(TIF_SIGPENDING);
- return -ERESTARTSYS;
+ ret = -ERESTARTSYS;
+out:
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ return ret;
}
EXPORT_SYMBOL(tty_check_change);
@@ -1247,8 +1253,8 @@
return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
}
-static int hung_up_tty_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static long hung_up_tty_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
{
return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
}
@@ -1264,7 +1270,7 @@
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
- .ioctl = tty_ioctl,
+ .unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
@@ -1277,7 +1283,7 @@
.read = tty_read,
.write = tty_write,
.poll = tty_poll,
- .ioctl = tty_ioctl,
+ .unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = ptmx_open,
.release = tty_release,
@@ -1290,7 +1296,7 @@
.read = tty_read,
.write = redirected_tty_write,
.poll = tty_poll,
- .ioctl = tty_ioctl,
+ .unlocked_ioctl = tty_ioctl,
.compat_ioctl = tty_compat_ioctl,
.open = tty_open,
.release = tty_release,
@@ -1302,7 +1308,7 @@
.read = hung_up_tty_read,
.write = hung_up_tty_write,
.poll = hung_up_tty_poll,
- .ioctl = hung_up_tty_ioctl,
+ .unlocked_ioctl = hung_up_tty_ioctl,
.compat_ioctl = hung_up_tty_compat_ioctl,
.release = tty_release,
};
@@ -1404,6 +1410,7 @@
struct task_struct *p;
struct tty_ldisc *ld;
int closecount = 0, n;
+ unsigned long flags;
if (!tty)
return;
@@ -1441,8 +1448,7 @@
/* We may have no line discipline at this point */
if (ld->flush_buffer)
ld->flush_buffer(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
ld->write_wakeup)
ld->write_wakeup(tty);
@@ -1480,19 +1486,24 @@
__group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p);
__group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p);
put_pid(p->signal->tty_old_pgrp); /* A noop */
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->pgrp)
p->signal->tty_old_pgrp = get_pid(tty->pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
spin_unlock_irq(&p->sighand->siglock);
} while_each_pid_task(tty->session, PIDTYPE_SID, p);
}
read_unlock(&tasklist_lock);
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->flags = 0;
put_pid(tty->session);
put_pid(tty->pgrp);
tty->session = NULL;
tty->pgrp = NULL;
tty->ctrl_status = 0;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
/*
* If one of the devices matches a console pointer, we
* cannot just call hangup() because that will cause
@@ -1500,11 +1511,11 @@
* So we just call close() the right number of times.
*/
if (cons_filp) {
- if (tty->driver->close)
+ if (tty->ops->close)
for (n = 0; n < closecount; n++)
- tty->driver->close(tty, cons_filp);
- } else if (tty->driver->hangup)
- (tty->driver->hangup)(tty);
+ tty->ops->close(tty, cons_filp);
+ } else if (tty->ops->hangup)
+ (tty->ops->hangup)(tty);
/*
* We don't want to have driver/ldisc interactions beyond
* the ones we did here. The driver layer expects no
@@ -1626,16 +1637,17 @@
struct tty_struct *tty;
struct pid *tty_pgrp = NULL;
- lock_kernel();
mutex_lock(&tty_mutex);
tty = get_current_tty();
if (tty) {
tty_pgrp = get_pid(tty->pgrp);
mutex_unlock(&tty_mutex);
+ lock_kernel();
/* XXX: here we race, there is nothing protecting tty */
if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
tty_vhangup(tty);
+ unlock_kernel();
} else if (on_exit) {
struct pid *old_pgrp;
spin_lock_irq(¤t->sighand->siglock);
@@ -1648,7 +1660,6 @@
put_pid(old_pgrp);
}
mutex_unlock(&tty_mutex);
- unlock_kernel();
return;
}
if (tty_pgrp) {
@@ -1667,10 +1678,13 @@
/* It is possible that do_tty_hangup has free'd this tty */
tty = get_current_tty();
if (tty) {
+ unsigned long flags;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(tty->session);
put_pid(tty->pgrp);
tty->session = NULL;
tty->pgrp = NULL;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
} else {
#ifdef TTY_DEBUG_HANGUP
printk(KERN_DEBUG "error attempted to write to tty [0x%p]"
@@ -1683,7 +1697,6 @@
read_lock(&tasklist_lock);
session_clear_tty(task_session(current));
read_unlock(&tasklist_lock);
- unlock_kernel();
}
/**
@@ -1693,8 +1706,10 @@
void no_tty(void)
{
struct task_struct *tsk = current;
+ lock_kernel();
if (tsk->signal->leader)
disassociate_ctty(0);
+ unlock_kernel();
proc_clear_tty(tsk);
}
@@ -1714,21 +1729,26 @@
* but not always.
*
* Locking:
- * Broken. Relies on BKL which is unsafe here.
+ * Uses the tty control lock internally
*/
void stop_tty(struct tty_struct *tty)
{
- if (tty->stopped)
+ unsigned long flags;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (tty->stopped) {
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
return;
+ }
tty->stopped = 1;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_START;
tty->ctrl_status |= TIOCPKT_STOP;
wake_up_interruptible(&tty->link->read_wait);
}
- if (tty->driver->stop)
- (tty->driver->stop)(tty);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->ops->stop)
+ (tty->ops->stop)(tty);
}
EXPORT_SYMBOL(stop_tty);
@@ -1743,21 +1763,26 @@
* driver start method is invoked and the line discipline woken.
*
* Locking:
- * Broken. Relies on BKL which is unsafe here.
+ * ctrl_lock
*/
void start_tty(struct tty_struct *tty)
{
- if (!tty->stopped || tty->flow_stopped)
+ unsigned long flags;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ if (!tty->stopped || tty->flow_stopped) {
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
return;
+ }
tty->stopped = 0;
if (tty->link && tty->link->packet) {
tty->ctrl_status &= ~TIOCPKT_STOP;
tty->ctrl_status |= TIOCPKT_START;
wake_up_interruptible(&tty->link->read_wait);
}
- if (tty->driver->start)
- (tty->driver->start)(tty);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ if (tty->ops->start)
+ (tty->ops->start)(tty);
/* If we have a running line discipline it may need kicking */
tty_wakeup(tty);
}
@@ -1775,10 +1800,8 @@
* for hung up devices before calling the line discipline method.
*
* Locking:
- * Locks the line discipline internally while needed
- * For historical reasons the line discipline read method is
- * invoked under the BKL. This will go away in time so do not rely on it
- * in new code. Multiple read calls may be outstanding in parallel.
+ * Locks the line discipline internally while needed. Multiple
+ * read calls may be outstanding in parallel.
*/
static ssize_t tty_read(struct file *file, char __user *buf, size_t count,
@@ -1799,13 +1822,11 @@
/* We want to wait for the line discipline to sort out in this
situation */
ld = tty_ldisc_ref_wait(tty);
- lock_kernel();
if (ld->read)
i = (ld->read)(tty, file, buf, count);
else
i = -EIO;
tty_ldisc_deref(ld);
- unlock_kernel();
if (i > 0)
inode->i_atime = current_fs_time(inode->i_sb);
return i;
@@ -1893,9 +1914,7 @@
ret = -EFAULT;
if (copy_from_user(tty->write_buf, buf, size))
break;
- lock_kernel();
ret = write(tty, file, tty->write_buf, size);
- unlock_kernel();
if (ret <= 0)
break;
written += ret;
@@ -1948,10 +1967,13 @@
tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_write"))
return -EIO;
- if (!tty || !tty->driver->write ||
+ if (!tty || !tty->ops->write ||
(test_bit(TTY_IO_ERROR, &tty->flags)))
return -EIO;
-
+ /* Short term debug to catch buggy drivers */
+ if (tty->ops->write_room == NULL)
+ printk(KERN_ERR "tty driver %s lacks a write_room method.\n",
+ tty->driver->name);
ld = tty_ldisc_ref_wait(tty);
if (!ld->write)
ret = -EIO;
@@ -2098,6 +2120,7 @@
goto fail_no_mem;
initialize_tty_struct(tty);
tty->driver = driver;
+ tty->ops = driver->ops;
tty->index = idx;
tty_line_name(driver, idx, tty->name);
@@ -2128,6 +2151,7 @@
goto free_mem_out;
initialize_tty_struct(o_tty);
o_tty->driver = driver->other;
+ o_tty->ops = driver->ops;
o_tty->index = idx;
tty_line_name(driver->other, idx, o_tty->name);
@@ -2432,8 +2456,8 @@
}
}
#endif
- if (tty->driver->close)
- tty->driver->close(tty, filp);
+ if (tty->ops->close)
+ tty->ops->close(tty, filp);
/*
* Sanity check: if tty->count is going to zero, there shouldn't be
@@ -2612,15 +2636,9 @@
*/
release_tty(tty, idx);
-#ifdef CONFIG_UNIX98_PTYS
/* Make this pty number available for reallocation */
- if (devpts) {
- mutex_lock(&allocated_ptys_lock);
- idr_remove(&allocated_ptys, idx);
- mutex_unlock(&allocated_ptys_lock);
- }
-#endif
-
+ if (devpts)
+ devpts_kill_index(idx);
}
/**
@@ -2716,8 +2734,8 @@
printk(KERN_DEBUG "opening %s...", tty->name);
#endif
if (!retval) {
- if (tty->driver->open)
- retval = tty->driver->open(tty, filp);
+ if (tty->ops->open)
+ retval = tty->ops->open(tty, filp);
else
retval = -ENODEV;
}
@@ -2755,7 +2773,6 @@
__proc_set_tty(current, tty);
spin_unlock_irq(¤t->sighand->siglock);
mutex_unlock(&tty_mutex);
- tty_audit_opening();
return 0;
}
@@ -2777,29 +2794,13 @@
struct tty_struct *tty;
int retval;
int index;
- int idr_ret;
nonseekable_open(inode, filp);
/* find a device that is not in use. */
- mutex_lock(&allocated_ptys_lock);
- if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
- mutex_unlock(&allocated_ptys_lock);
- return -ENOMEM;
- }
- idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
- if (idr_ret < 0) {
- mutex_unlock(&allocated_ptys_lock);
- if (idr_ret == -EAGAIN)
- return -ENOMEM;
- return -EIO;
- }
- if (index >= pty_limit) {
- idr_remove(&allocated_ptys, index);
- mutex_unlock(&allocated_ptys_lock);
- return -EIO;
- }
- mutex_unlock(&allocated_ptys_lock);
+ index = devpts_new_index();
+ if (index < 0)
+ return index;
mutex_lock(&tty_mutex);
retval = init_dev(ptm_driver, index, &tty);
@@ -2812,23 +2813,19 @@
filp->private_data = tty;
file_move(filp, &tty->tty_files);
- retval = -ENOMEM;
- if (devpts_pty_new(tty->link))
+ retval = devpts_pty_new(tty->link);
+ if (retval)
goto out1;
- check_tty_count(tty, "tty_open");
- retval = ptm_driver->open(tty, filp);
- if (!retval) {
- tty_audit_opening();
+ check_tty_count(tty, "ptmx_open");
+ retval = ptm_driver->ops->open(tty, filp);
+ if (!retval)
return 0;
- }
out1:
release_dev(filp);
return retval;
out:
- mutex_lock(&allocated_ptys_lock);
- idr_remove(&allocated_ptys, index);
- mutex_unlock(&allocated_ptys_lock);
+ devpts_kill_index(index);
return retval;
}
#endif
@@ -2885,6 +2882,7 @@
static int tty_fasync(int fd, struct file *filp, int on)
{
struct tty_struct *tty;
+ unsigned long flags;
int retval;
tty = (struct tty_struct *)filp->private_data;
@@ -2900,6 +2898,7 @@
struct pid *pid;
if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = 1;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->pgrp) {
pid = tty->pgrp;
type = PIDTYPE_PGID;
@@ -2907,6 +2906,7 @@
pid = task_pid(current);
type = PIDTYPE_PID;
}
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
retval = __f_setown(filp, pid, type, 0);
if (retval)
return retval;
@@ -2992,6 +2992,8 @@
struct winsize __user *arg)
{
struct winsize tmp_ws;
+ struct pid *pgrp, *rpgrp;
+ unsigned long flags;
if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
return -EFAULT;
@@ -3009,10 +3011,21 @@
}
}
#endif
- if (tty->pgrp)
- kill_pgrp(tty->pgrp, SIGWINCH, 1);
- if ((real_tty->pgrp != tty->pgrp) && real_tty->pgrp)
- kill_pgrp(real_tty->pgrp, SIGWINCH, 1);
+ /* Get the PID values and reference them so we can
+ avoid holding the tty ctrl lock while sending signals */
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ pgrp = get_pid(tty->pgrp);
+ rpgrp = get_pid(real_tty->pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+ if (pgrp)
+ kill_pgrp(pgrp, SIGWINCH, 1);
+ if (rpgrp != pgrp && rpgrp)
+ kill_pgrp(rpgrp, SIGWINCH, 1);
+
+ put_pid(pgrp);
+ put_pid(rpgrp);
+
tty->winsize = tmp_ws;
real_tty->winsize = tmp_ws;
done:
@@ -3073,10 +3086,13 @@
if (get_user(nonblock, p))
return -EFAULT;
+ /* file->f_flags is still BKL protected in the fs layer - vomit */
+ lock_kernel();
if (nonblock)
file->f_flags |= O_NONBLOCK;
else
file->f_flags &= ~O_NONBLOCK;
+ unlock_kernel();
return 0;
}
@@ -3134,6 +3150,27 @@
}
/**
+ * tty_get_pgrp - return a ref counted pgrp pid
+ * @tty: tty to read
+ *
+ * Returns a refcounted instance of the pid struct for the process
+ * group controlling the tty.
+ */
+
+struct pid *tty_get_pgrp(struct tty_struct *tty)
+{
+ unsigned long flags;
+ struct pid *pgrp;
+
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
+ pgrp = get_pid(tty->pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+
+ return pgrp;
+}
+EXPORT_SYMBOL_GPL(tty_get_pgrp);
+
+/**
* tiocgpgrp - get process group
* @tty: tty passed by user
* @real_tty: tty side of the tty pased by the user if a pty else the tty
@@ -3147,13 +3184,18 @@
static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
{
+ struct pid *pid;
+ int ret;
/*
* (tty == real_tty) is a cheap way of
* testing if the tty is NOT a master pty.
*/
if (tty == real_tty && current->signal->tty != real_tty)
return -ENOTTY;
- return put_user(pid_vnr(real_tty->pgrp), p);
+ pid = tty_get_pgrp(real_tty);
+ ret = put_user(pid_vnr(pid), p);
+ put_pid(pid);
+ return ret;
}
/**
@@ -3165,7 +3207,7 @@
* Set the process group of the tty to the session passed. Only
* permitted where the tty session is our session.
*
- * Locking: None
+ * Locking: RCU, ctrl lock
*/
static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
@@ -3173,6 +3215,7 @@
struct pid *pgrp;
pid_t pgrp_nr;
int retval = tty_check_change(real_tty);
+ unsigned long flags;
if (retval == -EIO)
return -ENOTTY;
@@ -3195,8 +3238,10 @@
if (session_of_pgrp(pgrp) != task_session(current))
goto out_unlock;
retval = 0;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(real_tty->pgrp);
real_tty->pgrp = get_pid(pgrp);
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
out_unlock:
rcu_read_unlock();
return retval;
@@ -3240,10 +3285,16 @@
static int tiocsetd(struct tty_struct *tty, int __user *p)
{
int ldisc;
+ int ret;
if (get_user(ldisc, p))
return -EFAULT;
- return tty_set_ldisc(tty, ldisc);
+
+ lock_kernel();
+ ret = tty_set_ldisc(tty, ldisc);
+ unlock_kernel();
+
+ return ret;
}
/**
@@ -3263,18 +3314,18 @@
{
if (tty_write_lock(tty, 0) < 0)
return -EINTR;
- tty->driver->break_ctl(tty, -1);
+ tty->ops->break_ctl(tty, -1);
if (!signal_pending(current))
msleep_interruptible(duration);
- tty->driver->break_ctl(tty, 0);
+ tty->ops->break_ctl(tty, 0);
tty_write_unlock(tty);
- if (signal_pending(current))
+ if (!signal_pending(current))
return -EINTR;
return 0;
}
/**
- * tiocmget - get modem status
+ * tty_tiocmget - get modem status
* @tty: tty device
* @file: user file pointer
* @p: pointer to result
@@ -3289,8 +3340,8 @@
{
int retval = -EINVAL;
- if (tty->driver->tiocmget) {
- retval = tty->driver->tiocmget(tty, file);
+ if (tty->ops->tiocmget) {
+ retval = tty->ops->tiocmget(tty, file);
if (retval >= 0)
retval = put_user(retval, p);
@@ -3299,7 +3350,7 @@
}
/**
- * tiocmset - set modem status
+ * tty_tiocmset - set modem status
* @tty: tty device
* @file: user file pointer
* @cmd: command - clear bits, set bits or set all
@@ -3316,7 +3367,7 @@
{
int retval = -EINVAL;
- if (tty->driver->tiocmset) {
+ if (tty->ops->tiocmset) {
unsigned int set, clear, val;
retval = get_user(val, p);
@@ -3340,7 +3391,7 @@
set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
- retval = tty->driver->tiocmset(tty, file, set, clear);
+ retval = tty->ops->tiocmset(tty, file, set, clear);
}
return retval;
}
@@ -3348,20 +3399,18 @@
/*
* Split this up, as gcc can choke on it otherwise..
*/
-int tty_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct tty_struct *tty, *real_tty;
void __user *p = (void __user *)arg;
int retval;
struct tty_ldisc *ld;
+ struct inode *inode = file->f_dentry->d_inode;
tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
- /* CHECKME: is this safe as one end closes ? */
-
real_tty = tty;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@@ -3370,21 +3419,28 @@
/*
* Break handling by driver
*/
- if (!tty->driver->break_ctl) {
+
+ retval = -EINVAL;
+
+ if (!tty->ops->break_ctl) {
switch (cmd) {
case TIOCSBRK:
case TIOCCBRK:
- if (tty->driver->ioctl)
- return tty->driver->ioctl(tty, file, cmd, arg);
- return -EINVAL;
+ if (tty->ops->ioctl)
+ retval = tty->ops->ioctl(tty, file, cmd, arg);
+ if (retval != -EINVAL && retval != -ENOIOCTLCMD)
+ printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
+ return retval;
/* These two ioctl's always return success; even if */
/* the driver doesn't support them. */
case TCSBRK:
case TCSBRKP:
- if (!tty->driver->ioctl)
+ if (!tty->ops->ioctl)
return 0;
- retval = tty->driver->ioctl(tty, file, cmd, arg);
+ retval = tty->ops->ioctl(tty, file, cmd, arg);
+ if (retval != -EINVAL && retval != -ENOIOCTLCMD)
+ printk(KERN_WARNING "tty: driver %s needs updating to use break_ctl\n", tty->driver->name);
if (retval == -ENOIOCTLCMD)
retval = 0;
return retval;
@@ -3442,7 +3498,6 @@
case TIOCGSID:
return tiocgsid(tty, real_tty, p);
case TIOCGETD:
- /* FIXME: check this is ok */
return put_user(tty->ldisc.num, (int __user *)p);
case TIOCSETD:
return tiocsetd(tty, p);
@@ -3454,11 +3509,13 @@
* Break handling
*/
case TIOCSBRK: /* Turn break on, unconditionally */
- tty->driver->break_ctl(tty, -1);
+ if (tty->ops->break_ctl)
+ tty->ops->break_ctl(tty, -1);
return 0;
case TIOCCBRK: /* Turn break off, unconditionally */
- tty->driver->break_ctl(tty, 0);
+ if (tty->ops->break_ctl)
+ tty->ops->break_ctl(tty, 0);
return 0;
case TCSBRK: /* SVID version: non-zero arg --> no break */
/* non-zero arg means wait for all output data
@@ -3487,8 +3544,8 @@
}
break;
}
- if (tty->driver->ioctl) {
- retval = (tty->driver->ioctl)(tty, file, cmd, arg);
+ if (tty->ops->ioctl) {
+ retval = (tty->ops->ioctl)(tty, file, cmd, arg);
if (retval != -ENOIOCTLCMD)
return retval;
}
@@ -3515,8 +3572,8 @@
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
- if (tty->driver->compat_ioctl) {
- retval = (tty->driver->compat_ioctl)(tty, file, cmd, arg);
+ if (tty->ops->compat_ioctl) {
+ retval = (tty->ops->compat_ioctl)(tty, file, cmd, arg);
if (retval != -ENOIOCTLCMD)
return retval;
}
@@ -3566,8 +3623,7 @@
tty_ldisc_flush(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
read_lock(&tasklist_lock);
/* Kill the entire session */
@@ -3773,19 +3829,32 @@
mutex_init(&tty->atomic_read_lock);
mutex_init(&tty->atomic_write_lock);
spin_lock_init(&tty->read_lock);
+ spin_lock_init(&tty->ctrl_lock);
INIT_LIST_HEAD(&tty->tty_files);
INIT_WORK(&tty->SAK_work, do_SAK_work);
}
-/*
- * The default put_char routine if the driver did not define one.
+/**
+ * tty_put_char - write one character to a tty
+ * @tty: tty
+ * @ch: character
+ *
+ * Write one byte to the tty using the provided put_char method
+ * if present. Returns the number of characters successfully output.
+ *
+ * Note: the specific put_char operation in the driver layer may go
+ * away soon. Don't call it directly, use this method
*/
-static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
+int tty_put_char(struct tty_struct *tty, unsigned char ch)
{
- tty->driver->write(tty, &ch, 1);
+ if (tty->ops->put_char)
+ return tty->ops->put_char(tty, ch);
+ return tty->ops->write(tty, &ch, 1);
}
+EXPORT_SYMBOL_GPL(tty_put_char);
+
static struct class *tty_class;
/**
@@ -3868,37 +3937,8 @@
void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op)
{
- driver->open = op->open;
- driver->close = op->close;
- driver->write = op->write;
- driver->put_char = op->put_char;
- driver->flush_chars = op->flush_chars;
- driver->write_room = op->write_room;
- driver->chars_in_buffer = op->chars_in_buffer;
- driver->ioctl = op->ioctl;
- driver->compat_ioctl = op->compat_ioctl;
- driver->set_termios = op->set_termios;
- driver->throttle = op->throttle;
- driver->unthrottle = op->unthrottle;
- driver->stop = op->stop;
- driver->start = op->start;
- driver->hangup = op->hangup;
- driver->break_ctl = op->break_ctl;
- driver->flush_buffer = op->flush_buffer;
- driver->set_ldisc = op->set_ldisc;
- driver->wait_until_sent = op->wait_until_sent;
- driver->send_xchar = op->send_xchar;
- driver->read_proc = op->read_proc;
- driver->write_proc = op->write_proc;
- driver->tiocmget = op->tiocmget;
- driver->tiocmset = op->tiocmset;
-#ifdef CONFIG_CONSOLE_POLL
- driver->poll_init = op->poll_init;
- driver->poll_get_char = op->poll_get_char;
- driver->poll_put_char = op->poll_put_char;
-#endif
-}
-
+ driver->ops = op;
+};
EXPORT_SYMBOL(alloc_tty_driver);
EXPORT_SYMBOL(put_tty_driver);
@@ -3961,9 +4001,6 @@
return error;
}
- if (!driver->put_char)
- driver->put_char = tty_default_put_char;
-
mutex_lock(&tty_mutex);
list_add(&driver->tty_drivers, &tty_drivers);
mutex_unlock(&tty_mutex);
@@ -4039,14 +4076,19 @@
}
EXPORT_SYMBOL(proc_clear_tty);
+/* Called under the sighand lock */
+
static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
{
if (tty) {
- /* We should not have a session or pgrp to here but.... */
+ unsigned long flags;
+ /* We should not have a session or pgrp to put here but.... */
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
put_pid(tty->session);
put_pid(tty->pgrp);
- tty->session = get_pid(task_session(tsk));
tty->pgrp = get_pid(task_pgrp(tsk));
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
+ tty->session = get_pid(task_session(tsk));
}
put_pid(tsk->signal->tty_old_pgrp);
tsk->signal->tty = tty;
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index f95a80b..b1a757a 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -21,6 +21,7 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
+#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -39,6 +40,50 @@
#define TERMIOS_OLD 8
+int tty_chars_in_buffer(struct tty_struct *tty)
+{
+ if (tty->ops->chars_in_buffer)
+ return tty->ops->chars_in_buffer(tty);
+ else
+ return 0;
+}
+
+EXPORT_SYMBOL(tty_chars_in_buffer);
+
+int tty_write_room(struct tty_struct *tty)
+{
+ if (tty->ops->write_room)
+ return tty->ops->write_room(tty);
+ return 2048;
+}
+
+EXPORT_SYMBOL(tty_write_room);
+
+void tty_driver_flush_buffer(struct tty_struct *tty)
+{
+ if (tty->ops->flush_buffer)
+ tty->ops->flush_buffer(tty);
+}
+
+EXPORT_SYMBOL(tty_driver_flush_buffer);
+
+void tty_throttle(struct tty_struct *tty)
+{
+ /* check TTY_THROTTLED first so it indicates our state */
+ if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->ops->throttle)
+ tty->ops->throttle(tty);
+}
+EXPORT_SYMBOL(tty_throttle);
+
+void tty_unthrottle(struct tty_struct *tty)
+{
+ if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->ops->unthrottle)
+ tty->ops->unthrottle(tty);
+}
+EXPORT_SYMBOL(tty_unthrottle);
+
/**
* tty_wait_until_sent - wait for I/O to finish
* @tty: tty we are waiting for
@@ -57,15 +102,13 @@
printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
#endif
- if (!tty->driver->chars_in_buffer)
- return;
if (!timeout)
timeout = MAX_SCHEDULE_TIMEOUT;
if (wait_event_interruptible_timeout(tty->write_wait,
- !tty->driver->chars_in_buffer(tty), timeout) < 0)
- return;
- if (tty->driver->wait_until_sent)
- tty->driver->wait_until_sent(tty, timeout);
+ !tty_chars_in_buffer(tty), timeout) >= 0) {
+ if (tty->ops->wait_until_sent)
+ tty->ops->wait_until_sent(tty, timeout);
+ }
}
EXPORT_SYMBOL(tty_wait_until_sent);
@@ -393,8 +436,9 @@
static void change_termios(struct tty_struct *tty, struct ktermios *new_termios)
{
int canon_change;
- struct ktermios old_termios = *tty->termios;
+ struct ktermios old_termios;
struct tty_ldisc *ld;
+ unsigned long flags;
/*
* Perform the actual termios internal changes under lock.
@@ -404,7 +448,7 @@
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
mutex_lock(&tty->termios_mutex);
-
+ old_termios = *tty->termios;
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
@@ -429,17 +473,19 @@
STOP_CHAR(tty) == '\023' &&
START_CHAR(tty) == '\021');
if (old_flow != new_flow) {
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
if (new_flow)
tty->ctrl_status |= TIOCPKT_DOSTOP;
else
tty->ctrl_status |= TIOCPKT_NOSTOP;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
wake_up_interruptible(&tty->link->read_wait);
}
}
- if (tty->driver->set_termios)
- (*tty->driver->set_termios)(tty, &old_termios);
+ if (tty->ops->set_termios)
+ (*tty->ops->set_termios)(tty, &old_termios);
else
tty_termios_copy_hw(tty->termios, &old_termios);
@@ -474,7 +520,9 @@
if (retval)
return retval;
+ mutex_lock(&tty->termios_mutex);
memcpy(&tmp_termios, tty->termios, sizeof(struct ktermios));
+ mutex_unlock(&tty->termios_mutex);
if (opt & TERMIOS_TERMIO) {
if (user_termio_to_kernel_termios(&tmp_termios,
@@ -660,12 +708,14 @@
{
struct tchars tmp;
+ mutex_lock(&tty->termios_mutex);
tmp.t_intrc = tty->termios->c_cc[VINTR];
tmp.t_quitc = tty->termios->c_cc[VQUIT];
tmp.t_startc = tty->termios->c_cc[VSTART];
tmp.t_stopc = tty->termios->c_cc[VSTOP];
tmp.t_eofc = tty->termios->c_cc[VEOF];
tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
+ mutex_unlock(&tty->termios_mutex);
return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -675,12 +725,14 @@
if (copy_from_user(&tmp, tchars, sizeof(tmp)))
return -EFAULT;
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_cc[VINTR] = tmp.t_intrc;
tty->termios->c_cc[VQUIT] = tmp.t_quitc;
tty->termios->c_cc[VSTART] = tmp.t_startc;
tty->termios->c_cc[VSTOP] = tmp.t_stopc;
tty->termios->c_cc[VEOF] = tmp.t_eofc;
tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
#endif
@@ -690,6 +742,7 @@
{
struct ltchars tmp;
+ mutex_lock(&tty->termios_mutex);
tmp.t_suspc = tty->termios->c_cc[VSUSP];
/* what is dsuspc anyway? */
tmp.t_dsuspc = tty->termios->c_cc[VSUSP];
@@ -698,6 +751,7 @@
tmp.t_flushc = tty->termios->c_cc[VEOL2];
tmp.t_werasc = tty->termios->c_cc[VWERASE];
tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
+ mutex_unlock(&tty->termios_mutex);
return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -708,6 +762,7 @@
if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
return -EFAULT;
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_cc[VSUSP] = tmp.t_suspc;
/* what is dsuspc anyway? */
tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;
@@ -716,6 +771,7 @@
tty->termios->c_cc[VEOL2] = tmp.t_flushc;
tty->termios->c_cc[VWERASE] = tmp.t_werasc;
tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
#endif
@@ -732,8 +788,8 @@
{
int was_stopped = tty->stopped;
- if (tty->driver->send_xchar) {
- tty->driver->send_xchar(tty, ch);
+ if (tty->ops->send_xchar) {
+ tty->ops->send_xchar(tty, ch);
return 0;
}
@@ -742,7 +798,7 @@
if (was_stopped)
start_tty(tty);
- tty->driver->write(tty, &ch, 1);
+ tty->ops->write(tty, &ch, 1);
if (was_stopped)
stop_tty(tty);
tty_write_unlock(tty);
@@ -750,6 +806,33 @@
}
/**
+ * tty_change_softcar - carrier change ioctl helper
+ * @tty: tty to update
+ * @arg: enable/disable CLOCAL
+ *
+ * Perform a change to the CLOCAL state and call into the driver
+ * layer to make it visible. All done with the termios mutex
+ */
+
+static int tty_change_softcar(struct tty_struct *tty, int arg)
+{
+ int ret = 0;
+ int bit = arg ? CLOCAL : 0;
+ struct ktermios old;
+
+ mutex_lock(&tty->termios_mutex);
+ old = *tty->termios;
+ tty->termios->c_cflag &= ~CLOCAL;
+ tty->termios->c_cflag |= bit;
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, &old);
+ if ((tty->termios->c_cflag & CLOCAL) != bit)
+ ret = -EINVAL;
+ mutex_unlock(&tty->termios_mutex);
+ return ret;
+}
+
+/**
* tty_mode_ioctl - mode related ioctls
* @tty: tty for the ioctl
* @file: file pointer for the tty
@@ -859,12 +942,7 @@
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))
return -EFAULT;
- mutex_lock(&tty->termios_mutex);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- mutex_unlock(&tty->termios_mutex);
- return 0;
+ return tty_change_softcar(tty, arg);
default:
return -ENOIOCTLCMD;
}
@@ -889,8 +967,7 @@
ld->flush_buffer(tty);
/* fall through */
case TCOFLUSH:
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
break;
default:
tty_ldisc_deref(ld);
@@ -905,6 +982,7 @@
unsigned int cmd, unsigned long arg)
{
struct tty_struct *real_tty;
+ unsigned long flags;
int retval;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
@@ -946,9 +1024,7 @@
case TCFLSH:
return tty_perform_flush(tty, arg);
case TIOCOUTQ:
- return put_user(tty->driver->chars_in_buffer ?
- tty->driver->chars_in_buffer(tty) : 0,
- (int __user *) arg);
+ return put_user(tty_chars_in_buffer(tty), (int __user *) arg);
case TIOCINQ:
retval = tty->read_cnt;
if (L_ICANON(tty))
@@ -963,6 +1039,7 @@
return -ENOTTY;
if (get_user(pktmode, (int __user *) arg))
return -EFAULT;
+ spin_lock_irqsave(&tty->ctrl_lock, flags);
if (pktmode) {
if (!tty->packet) {
tty->packet = 1;
@@ -970,6 +1047,7 @@
}
} else
tty->packet = 0;
+ spin_unlock_irqrestore(&tty->ctrl_lock, flags);
return 0;
}
default:
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index 8de6b95..3d3e1c2 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -628,13 +628,13 @@
/*
* TTY put_char method
*/
-static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
+static int viotty_put_char(struct tty_struct *tty, unsigned char ch)
{
struct port_info *pi;
pi = get_port_data(tty);
if (pi == NULL)
- return;
+ return 0;
/* This will append '\r' as well if the char is '\n' */
if (viochar_is_console(pi))
@@ -642,6 +642,7 @@
if (viopath_isactive(pi->lp))
internal_write(pi, &ch, 1);
+ return 1;
}
/*
@@ -704,8 +705,11 @@
case KDSKBLED:
return 0;
}
-
- return n_tty_ioctl(tty, file, cmd, arg);
+ /* FIXME: WTF is this being called for ??? */
+ lock_kernel();
+ ret = n_tty_ioctl(tty, file, cmd, arg);
+ unlock_kernel();
+ return ret;
}
/*
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index db7a731..58aad638 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -249,6 +249,7 @@
}
static const struct file_operations proc_viotape_operations = {
+ .owner = THIS_MODULE,
.open = proc_viotape_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -915,7 +916,6 @@
int __init viotap_init(void)
{
int ret;
- struct proc_dir_entry *e;
if (!firmware_has_feature(FW_FEATURE_ISERIES))
return -ENODEV;
@@ -968,11 +968,8 @@
if (ret)
goto unreg_class;
- e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL);
- if (e) {
- e->owner = THIS_MODULE;
- e->proc_fops = &proc_viotape_operations;
- }
+ proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL,
+ &proc_viotape_operations);
return 0;
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index df4c3ea..e458b08 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -301,7 +301,7 @@
d = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * (t + nr));
scr_memmovew(d, s, (b - t - nr) * vc->vc_size_row);
- scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_video_erase_char,
+ scr_memsetw(d + (b - t - nr) * vc->vc_cols, vc->vc_scrl_erase_char,
vc->vc_size_row * nr);
}
@@ -319,7 +319,7 @@
s = (unsigned short *)(vc->vc_origin + vc->vc_size_row * t);
step = vc->vc_cols * nr;
scr_memmovew(s + step, s, (b - t - nr) * vc->vc_size_row);
- scr_memsetw(s, vc->vc_video_erase_char, 2 * step);
+ scr_memsetw(s, vc->vc_scrl_erase_char, 2 * step);
}
static void do_update_region(struct vc_data *vc, unsigned long start, int count)
@@ -400,7 +400,7 @@
* Bit 7 : blink
*/
{
- u8 a = vc->vc_color;
+ u8 a = _color;
if (!vc->vc_can_do_color)
return _intensity |
(_italic ? 2 : 0) |
@@ -434,6 +434,7 @@
vc->vc_blink, vc->vc_underline,
vc->vc_reverse ^ vc->vc_decscnm, vc->vc_italic);
vc->vc_video_erase_char = (build_attr(vc, vc->vc_color, 1, vc->vc_blink, 0, vc->vc_decscnm, 0) << 8) | ' ';
+ vc->vc_scrl_erase_char = (build_attr(vc, vc->vc_def_color, 1, false, false, false, false) << 8) | ' ';
}
/* Note: inverting the screen twice should revert to the original state */
@@ -908,15 +909,21 @@
if (vc->vc_tty) {
struct winsize ws, *cws = &vc->vc_tty->winsize;
+ unsigned long flags;
memset(&ws, 0, sizeof(ws));
ws.ws_row = vc->vc_rows;
ws.ws_col = vc->vc_cols;
ws.ws_ypixel = vc->vc_scan_lines;
+
+ mutex_lock(&vc->vc_tty->termios_mutex);
+ spin_lock_irqsave(&vc->vc_tty->ctrl_lock, flags);
if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col) &&
vc->vc_tty->pgrp)
kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1);
+ spin_unlock_irqrestore(&vc->vc_tty->ctrl_lock, flags);
*cws = ws;
+ mutex_unlock(&vc->vc_tty->termios_mutex);
}
if (CON_IS_VISIBLE(vc))
@@ -2540,6 +2547,9 @@
if (get_user(type, p))
return -EFAULT;
ret = 0;
+
+ lock_kernel();
+
switch (type)
{
case TIOCL_SETSEL:
@@ -2559,7 +2569,7 @@
ret = sel_loadlut(p);
break;
case TIOCL_GETSHIFTSTATE:
-
+
/*
* Make it possible to react to Shift+Mousebutton.
* Note that 'shift_state' is an undocumented
@@ -2614,6 +2624,7 @@
ret = -EINVAL;
break;
}
+ unlock_kernel();
return ret;
}
@@ -2631,11 +2642,11 @@
return retval;
}
-static void con_put_char(struct tty_struct *tty, unsigned char ch)
+static int con_put_char(struct tty_struct *tty, unsigned char ch)
{
if (in_interrupt())
- return; /* n_r3964 calls put_char() from interrupt context */
- do_con_write(tty, &ch, 1);
+ return 0; /* n_r3964 calls put_char() from interrupt context */
+ return do_con_write(tty, &ch, 1);
}
static int con_write_room(struct tty_struct *tty)
@@ -3828,7 +3839,7 @@
goto out;
c = (font.width+7)/8 * 32 * font.charcount;
-
+
if (op->data && font.charcount > op->charcount)
rc = -ENOSPC;
if (!(op->flags & KD_FONT_FLAG_OLD)) {
@@ -3993,6 +4004,7 @@
c |= 0x100;
return c;
}
+EXPORT_SYMBOL_GPL(screen_glyph);
/* used by vcs - note the word offset */
unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed)
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index e6f89e8..3211afd 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -373,11 +373,17 @@
unsigned char ucval;
void __user *up = (void __user *)arg;
int i, perm;
-
+ int ret = 0;
+
console = vc->vc_num;
- if (!vc_cons_allocated(console)) /* impossible? */
- return -ENOIOCTLCMD;
+ lock_kernel();
+
+ if (!vc_cons_allocated(console)) { /* impossible? */
+ ret = -ENOIOCTLCMD;
+ goto out;
+ }
+
/*
* To have permissions to do most of the vt ioctls, we either have
@@ -391,15 +397,15 @@
switch (cmd) {
case KIOCSOUND:
if (!perm)
- return -EPERM;
+ goto eperm;
if (arg)
arg = CLOCK_TICK_RATE / arg;
kd_mksound(arg, 0);
- return 0;
+ break;
case KDMKTONE:
if (!perm)
- return -EPERM;
+ goto eperm;
{
unsigned int ticks, count;
@@ -412,7 +418,7 @@
if (count)
count = CLOCK_TICK_RATE / count;
kd_mksound(count, ticks);
- return 0;
+ break;
}
case KDGKBTYPE:
@@ -435,14 +441,18 @@
* KDADDIO and KDDELIO may be able to add ports beyond what
* we reject here, but to be safe...
*/
- if (arg < GPFIRST || arg > GPLAST)
- return -EINVAL;
- return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+ if (arg < GPFIRST || arg > GPLAST) {
+ ret = -EINVAL;
+ break;
+ }
+ ret = sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0;
+ break;
case KDENABIO:
case KDDISABIO:
- return sys_ioperm(GPFIRST, GPNUM,
+ ret = sys_ioperm(GPFIRST, GPNUM,
(cmd == KDENABIO)) ? -ENXIO : 0;
+ break;
#endif
/* Linux m68k/i386 interface for setting the keyboard delay/repeat rate */
@@ -450,19 +460,20 @@
case KDKBDREP:
{
struct kbd_repeat kbrep;
- int err;
if (!capable(CAP_SYS_TTY_CONFIG))
- return -EPERM;
+ goto eperm;
- if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat)))
- return -EFAULT;
- err = kbd_rate(&kbrep);
- if (err)
- return err;
+ if (copy_from_user(&kbrep, up, sizeof(struct kbd_repeat))) {
+ ret = -EFAULT;
+ break;
+ }
+ ret = kbd_rate(&kbrep);
+ if (ret)
+ break;
if (copy_to_user(up, &kbrep, sizeof(struct kbd_repeat)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
}
case KDSETMODE:
@@ -475,7 +486,7 @@
* need to restore their engine state. --BenH
*/
if (!perm)
- return -EPERM;
+ goto eperm;
switch (arg) {
case KD_GRAPHICS:
break;
@@ -485,13 +496,14 @@
case KD_TEXT:
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (vc->vc_mode == (unsigned char) arg)
- return 0;
+ break;
vc->vc_mode = (unsigned char) arg;
if (console != fg_console)
- return 0;
+ break;
/*
* explicitly blank/unblank the screen if switching modes
*/
@@ -501,7 +513,7 @@
else
do_blank_screen(1);
release_console_sem();
- return 0;
+ break;
case KDGETMODE:
ucval = vc->vc_mode;
@@ -513,11 +525,12 @@
* these work like a combination of mmap and KDENABIO.
* this could be easily finished.
*/
- return -EINVAL;
+ ret = -EINVAL;
+ break;
case KDSKBMODE:
if (!perm)
- return -EPERM;
+ goto eperm;
switch(arg) {
case K_RAW:
kbd->kbdmode = VC_RAW;
@@ -534,10 +547,11 @@
compute_shiftstate();
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
tty_ldisc_flush(tty);
- return 0;
+ break;
case KDGKBMODE:
ucval = ((kbd->kbdmode == VC_RAW) ? K_RAW :
@@ -557,28 +571,32 @@
set_vc_kbd_mode(kbd, VC_META);
break;
default:
- return -EINVAL;
+ ret = -EINVAL;
}
- return 0;
+ break;
case KDGKBMETA:
ucval = (vc_kbd_mode(kbd, VC_META) ? K_ESCPREFIX : K_METABIT);
setint:
- return put_user(ucval, (int __user *)arg);
+ ret = put_user(ucval, (int __user *)arg);
+ break;
case KDGETKEYCODE:
case KDSETKEYCODE:
if(!capable(CAP_SYS_TTY_CONFIG))
- perm=0;
- return do_kbkeycode_ioctl(cmd, up, perm);
+ perm = 0;
+ ret = do_kbkeycode_ioctl(cmd, up, perm);
+ break;
case KDGKBENT:
case KDSKBENT:
- return do_kdsk_ioctl(cmd, up, perm, kbd);
+ ret = do_kdsk_ioctl(cmd, up, perm, kbd);
+ break;
case KDGKBSENT:
case KDSKBSENT:
- return do_kdgkb_ioctl(cmd, up, perm);
+ ret = do_kdgkb_ioctl(cmd, up, perm);
+ break;
case KDGKBDIACR:
{
@@ -586,26 +604,31 @@
struct kbdiacr diacr;
int i;
- if (put_user(accent_table_size, &a->kb_cnt))
- return -EFAULT;
+ if (put_user(accent_table_size, &a->kb_cnt)) {
+ ret = -EFAULT;
+ break;
+ }
for (i = 0; i < accent_table_size; i++) {
diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr);
diacr.base = conv_uni_to_8bit(accent_table[i].base);
diacr.result = conv_uni_to_8bit(accent_table[i].result);
- if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr)))
- return -EFAULT;
+ if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) {
+ ret = -EFAULT;
+ break;
+ }
}
- return 0;
+ break;
}
case KDGKBDIACRUC:
{
struct kbdiacrsuc __user *a = up;
if (put_user(accent_table_size, &a->kb_cnt))
- return -EFAULT;
- if (copy_to_user(a->kbdiacruc, accent_table, accent_table_size*sizeof(struct kbdiacruc)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ else if (copy_to_user(a->kbdiacruc, accent_table,
+ accent_table_size*sizeof(struct kbdiacruc)))
+ ret = -EFAULT;
+ break;
}
case KDSKBDIACR:
@@ -616,20 +639,26 @@
int i;
if (!perm)
- return -EPERM;
- if (get_user(ct,&a->kb_cnt))
- return -EFAULT;
- if (ct >= MAX_DIACR)
- return -EINVAL;
+ goto eperm;
+ if (get_user(ct,&a->kb_cnt)) {
+ ret = -EFAULT;
+ break;
+ }
+ if (ct >= MAX_DIACR) {
+ ret = -EINVAL;
+ break;
+ }
accent_table_size = ct;
for (i = 0; i < ct; i++) {
- if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr)))
- return -EFAULT;
+ if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) {
+ ret = -EFAULT;
+ break;
+ }
accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr);
accent_table[i].base = conv_8bit_to_uni(diacr.base);
accent_table[i].result = conv_8bit_to_uni(diacr.result);
}
- return 0;
+ break;
}
case KDSKBDIACRUC:
@@ -638,15 +667,19 @@
unsigned int ct;
if (!perm)
- return -EPERM;
- if (get_user(ct,&a->kb_cnt))
- return -EFAULT;
- if (ct >= MAX_DIACR)
- return -EINVAL;
+ goto eperm;
+ if (get_user(ct,&a->kb_cnt)) {
+ ret = -EFAULT;
+ break;
+ }
+ if (ct >= MAX_DIACR) {
+ ret = -EINVAL;
+ break;
+ }
accent_table_size = ct;
if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
}
/* the ioctls below read/set the flags usually shown in the leds */
@@ -657,26 +690,29 @@
case KDSKBLED:
if (!perm)
- return -EPERM;
- if (arg & ~0x77)
- return -EINVAL;
+ goto eperm;
+ if (arg & ~0x77) {
+ ret = -EINVAL;
+ break;
+ }
kbd->ledflagstate = (arg & 7);
kbd->default_ledflagstate = ((arg >> 4) & 7);
set_leds();
- return 0;
+ break;
/* the ioctls below only set the lights, not the functions */
/* for those, see KDGKBLED and KDSKBLED above */
case KDGETLED:
ucval = getledstate();
setchar:
- return put_user(ucval, (char __user *)arg);
+ ret = put_user(ucval, (char __user *)arg);
+ break;
case KDSETLED:
if (!perm)
- return -EPERM;
+ goto eperm;
setledstate(kbd, arg);
- return 0;
+ break;
/*
* A process can indicate its willingness to accept signals
@@ -688,16 +724,17 @@
case KDSIGACCEPT:
{
if (!perm || !capable(CAP_KILL))
- return -EPERM;
+ goto eperm;
if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
- return -EINVAL;
-
- spin_lock_irq(&vt_spawn_con.lock);
- put_pid(vt_spawn_con.pid);
- vt_spawn_con.pid = get_pid(task_pid(current));
- vt_spawn_con.sig = arg;
- spin_unlock_irq(&vt_spawn_con.lock);
- return 0;
+ ret = -EINVAL;
+ else {
+ spin_lock_irq(&vt_spawn_con.lock);
+ put_pid(vt_spawn_con.pid);
+ vt_spawn_con.pid = get_pid(task_pid(current));
+ vt_spawn_con.sig = arg;
+ spin_unlock_irq(&vt_spawn_con.lock);
+ }
+ break;
}
case VT_SETMODE:
@@ -705,11 +742,15 @@
struct vt_mode tmp;
if (!perm)
- return -EPERM;
- if (copy_from_user(&tmp, up, sizeof(struct vt_mode)))
- return -EFAULT;
- if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS)
- return -EINVAL;
+ goto eperm;
+ if (copy_from_user(&tmp, up, sizeof(struct vt_mode))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ if (tmp.mode != VT_AUTO && tmp.mode != VT_PROCESS) {
+ ret = -EINVAL;
+ goto out;
+ }
acquire_console_sem();
vc->vt_mode = tmp;
/* the frsig is ignored, so we set it to 0 */
@@ -719,7 +760,7 @@
/* no switch is required -- saw@shade.msu.ru */
vc->vt_newvt = -1;
release_console_sem();
- return 0;
+ break;
}
case VT_GETMODE:
@@ -732,7 +773,9 @@
release_console_sem();
rc = copy_to_user(up, &tmp, sizeof(struct vt_mode));
- return rc ? -EFAULT : 0;
+ if (rc)
+ ret = -EFAULT;
+ break;
}
/*
@@ -746,12 +789,16 @@
unsigned short state, mask;
if (put_user(fg_console + 1, &vtstat->v_active))
- return -EFAULT;
- state = 1; /* /dev/tty0 is always open */
- for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
- if (VT_IS_IN_USE(i))
- state |= mask;
- return put_user(state, &vtstat->v_state);
+ ret = -EFAULT;
+ else {
+ state = 1; /* /dev/tty0 is always open */
+ for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask;
+ ++i, mask <<= 1)
+ if (VT_IS_IN_USE(i))
+ state |= mask;
+ ret = put_user(state, &vtstat->v_state);
+ }
+ break;
}
/*
@@ -771,27 +818,31 @@
*/
case VT_ACTIVATE:
if (!perm)
- return -EPERM;
+ goto eperm;
if (arg == 0 || arg > MAX_NR_CONSOLES)
- return -ENXIO;
- arg--;
- acquire_console_sem();
- i = vc_allocate(arg);
- release_console_sem();
- if (i)
- return i;
- set_console(arg);
- return 0;
+ ret = -ENXIO;
+ else {
+ arg--;
+ acquire_console_sem();
+ ret = vc_allocate(arg);
+ release_console_sem();
+ if (ret)
+ break;
+ set_console(arg);
+ }
+ break;
/*
* wait until the specified VT has been activated
*/
case VT_WAITACTIVE:
if (!perm)
- return -EPERM;
+ goto eperm;
if (arg == 0 || arg > MAX_NR_CONSOLES)
- return -ENXIO;
- return vt_waitactive(arg-1);
+ ret = -ENXIO;
+ else
+ ret = vt_waitactive(arg - 1);
+ break;
/*
* If a vt is under process control, the kernel will not switch to it
@@ -805,10 +856,12 @@
*/
case VT_RELDISP:
if (!perm)
- return -EPERM;
- if (vc->vt_mode.mode != VT_PROCESS)
- return -EINVAL;
+ goto eperm;
+ if (vc->vt_mode.mode != VT_PROCESS) {
+ ret = -EINVAL;
+ break;
+ }
/*
* Switching-from response
*/
@@ -829,10 +882,10 @@
int newvt;
newvt = vc->vt_newvt;
vc->vt_newvt = -1;
- i = vc_allocate(newvt);
- if (i) {
+ ret = vc_allocate(newvt);
+ if (ret) {
release_console_sem();
- return i;
+ break;
}
/*
* When we actually do the console switch,
@@ -841,31 +894,27 @@
*/
complete_change_console(vc_cons[newvt].d);
}
- }
-
- /*
- * Switched-to response
- */
- else
- {
+ } else {
+ /*
+ * Switched-to response
+ */
/*
* If it's just an ACK, ignore it
*/
- if (arg != VT_ACKACQ) {
- release_console_sem();
- return -EINVAL;
- }
+ if (arg != VT_ACKACQ)
+ ret = -EINVAL;
}
release_console_sem();
-
- return 0;
+ break;
/*
* Disallocate memory associated to VT (but leave VT1)
*/
case VT_DISALLOCATE:
- if (arg > MAX_NR_CONSOLES)
- return -ENXIO;
+ if (arg > MAX_NR_CONSOLES) {
+ ret = -ENXIO;
+ break;
+ }
if (arg == 0) {
/* deallocate all unused consoles, but leave 0 */
acquire_console_sem();
@@ -877,14 +926,14 @@
/* deallocate a single console, if possible */
arg--;
if (VT_BUSY(arg))
- return -EBUSY;
- if (arg) { /* leave 0 */
+ ret = -EBUSY;
+ else if (arg) { /* leave 0 */
acquire_console_sem();
vc_deallocate(arg);
release_console_sem();
}
}
- return 0;
+ break;
case VT_RESIZE:
{
@@ -893,21 +942,21 @@
ushort ll,cc;
if (!perm)
- return -EPERM;
+ goto eperm;
if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols))
- return -EFAULT;
+ ret = -EFAULT;
+ else {
+ for (i = 0; i < MAX_NR_CONSOLES; i++) {
+ vc = vc_cons[i].d;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- vc = vc_cons[i].d;
-
- if (vc) {
- vc->vc_resize_user = 1;
- vc_lock_resize(vc_cons[i].d, cc, ll);
+ if (vc) {
+ vc->vc_resize_user = 1;
+ vc_lock_resize(vc_cons[i].d, cc, ll);
+ }
}
}
-
- return 0;
+ break;
}
case VT_RESIZEX:
@@ -915,10 +964,13 @@
struct vt_consize __user *vtconsize = up;
ushort ll,cc,vlin,clin,vcol,ccol;
if (!perm)
- return -EPERM;
+ goto eperm;
if (!access_ok(VERIFY_READ, vtconsize,
- sizeof(struct vt_consize)))
- return -EFAULT;
+ sizeof(struct vt_consize))) {
+ ret = -EFAULT;
+ break;
+ }
+ /* FIXME: Should check the copies properly */
__get_user(ll, &vtconsize->v_rows);
__get_user(cc, &vtconsize->v_cols);
__get_user(vlin, &vtconsize->v_vlin);
@@ -928,21 +980,28 @@
vlin = vlin ? vlin : vc->vc_scan_lines;
if (clin) {
if (ll) {
- if (ll != vlin/clin)
- return -EINVAL; /* Parameters don't add up */
+ if (ll != vlin/clin) {
+ /* Parameters don't add up */
+ ret = -EINVAL;
+ break;
+ }
} else
ll = vlin/clin;
}
if (vcol && ccol) {
if (cc) {
- if (cc != vcol/ccol)
- return -EINVAL;
+ if (cc != vcol/ccol) {
+ ret = -EINVAL;
+ break;
+ }
} else
cc = vcol/ccol;
}
- if (clin > 32)
- return -EINVAL;
+ if (clin > 32) {
+ ret = -EINVAL;
+ break;
+ }
for (i = 0; i < MAX_NR_CONSOLES; i++) {
if (!vc_cons[i].d)
@@ -956,19 +1015,20 @@
vc_resize(vc_cons[i].d, cc, ll);
release_console_sem();
}
- return 0;
+ break;
}
case PIO_FONT: {
if (!perm)
- return -EPERM;
+ goto eperm;
op.op = KD_FONT_OP_SET;
op.flags = KD_FONT_FLAG_OLD | KD_FONT_FLAG_DONT_RECALC; /* Compatibility */
op.width = 8;
op.height = 0;
op.charcount = 256;
op.data = up;
- return con_font_op(vc_cons[fg_console].d, &op);
+ ret = con_font_op(vc_cons[fg_console].d, &op);
+ break;
}
case GIO_FONT: {
@@ -978,100 +1038,124 @@
op.height = 32;
op.charcount = 256;
op.data = up;
- return con_font_op(vc_cons[fg_console].d, &op);
+ ret = con_font_op(vc_cons[fg_console].d, &op);
+ break;
}
case PIO_CMAP:
if (!perm)
- return -EPERM;
- return con_set_cmap(up);
+ ret = -EPERM;
+ else
+ ret = con_set_cmap(up);
+ break;
case GIO_CMAP:
- return con_get_cmap(up);
+ ret = con_get_cmap(up);
+ break;
case PIO_FONTX:
case GIO_FONTX:
- return do_fontx_ioctl(cmd, up, perm, &op);
+ ret = do_fontx_ioctl(cmd, up, perm, &op);
+ break;
case PIO_FONTRESET:
{
if (!perm)
- return -EPERM;
+ goto eperm;
#ifdef BROKEN_GRAPHICS_PROGRAMS
/* With BROKEN_GRAPHICS_PROGRAMS defined, the default
font is not saved. */
- return -ENOSYS;
+ ret = -ENOSYS;
+ break;
#else
{
op.op = KD_FONT_OP_SET_DEFAULT;
op.data = NULL;
- i = con_font_op(vc_cons[fg_console].d, &op);
- if (i)
- return i;
+ ret = con_font_op(vc_cons[fg_console].d, &op);
+ if (ret)
+ break;
con_set_default_unimap(vc_cons[fg_console].d);
- return 0;
+ break;
}
#endif
}
case KDFONTOP: {
- if (copy_from_user(&op, up, sizeof(op)))
- return -EFAULT;
+ if (copy_from_user(&op, up, sizeof(op))) {
+ ret = -EFAULT;
+ break;
+ }
if (!perm && op.op != KD_FONT_OP_GET)
- return -EPERM;
- i = con_font_op(vc, &op);
- if (i) return i;
+ goto eperm;
+ ret = con_font_op(vc, &op);
+ if (ret)
+ break;
if (copy_to_user(up, &op, sizeof(op)))
- return -EFAULT;
- return 0;
+ ret = -EFAULT;
+ break;
}
case PIO_SCRNMAP:
if (!perm)
- return -EPERM;
- return con_set_trans_old(up);
+ ret = -EPERM;
+ else
+ ret = con_set_trans_old(up);
+ break;
case GIO_SCRNMAP:
- return con_get_trans_old(up);
+ ret = con_get_trans_old(up);
+ break;
case PIO_UNISCRNMAP:
if (!perm)
- return -EPERM;
- return con_set_trans_new(up);
+ ret = -EPERM;
+ else
+ ret = con_set_trans_new(up);
+ break;
case GIO_UNISCRNMAP:
- return con_get_trans_new(up);
+ ret = con_get_trans_new(up);
+ break;
case PIO_UNIMAPCLR:
{ struct unimapinit ui;
if (!perm)
- return -EPERM;
- i = copy_from_user(&ui, up, sizeof(struct unimapinit));
- if (i) return -EFAULT;
- con_clear_unimap(vc, &ui);
- return 0;
+ goto eperm;
+ ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
+ if (!ret)
+ con_clear_unimap(vc, &ui);
+ break;
}
case PIO_UNIMAP:
case GIO_UNIMAP:
- return do_unimap_ioctl(cmd, up, perm, vc);
+ ret = do_unimap_ioctl(cmd, up, perm, vc);
+ break;
case VT_LOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
- return -EPERM;
+ goto eperm;
vt_dont_switch = 1;
- return 0;
+ break;
case VT_UNLOCKSWITCH:
if (!capable(CAP_SYS_TTY_CONFIG))
- return -EPERM;
+ goto eperm;
vt_dont_switch = 0;
- return 0;
+ break;
case VT_GETHIFONTMASK:
- return put_user(vc->vc_hi_font_mask, (unsigned short __user *)arg);
+ ret = put_user(vc->vc_hi_font_mask,
+ (unsigned short __user *)arg);
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -ENOIOCTLCMD;
}
+out:
+ unlock_kernel();
+ return ret;
+eperm:
+ ret = -EPERM;
+ goto out;
}
/*
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index c159ae6..5f076ae 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -69,6 +69,15 @@
the frequency statically to the highest frequency supported by
the CPU.
+config CPU_FREQ_DEFAULT_GOV_POWERSAVE
+ bool "powersave"
+ depends on EMBEDDED
+ select CPU_FREQ_GOV_POWERSAVE
+ help
+ Use the CPUFreq governor 'powersave' as default. This sets
+ the frequency statically to the lowest frequency supported by
+ the CPU.
+
config CPU_FREQ_DEFAULT_GOV_USERSPACE
bool "userspace"
select CPU_FREQ_GOV_USERSPACE
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index d3575f5..7fce038 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -583,15 +583,13 @@
i += sprintf(&buf[i], "\n");
return i;
}
-/**
- * show_affected_cpus - show the CPUs affected by each transition
- */
-static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
+
+static ssize_t show_cpus(cpumask_t mask, char *buf)
{
ssize_t i = 0;
unsigned int cpu;
- for_each_cpu_mask(cpu, policy->cpus) {
+ for_each_cpu_mask(cpu, mask) {
if (i)
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
@@ -602,6 +600,25 @@
return i;
}
+/**
+ * show_related_cpus - show the CPUs affected by each transition even if
+ * hw coordination is in use
+ */
+static ssize_t show_related_cpus(struct cpufreq_policy *policy, char *buf)
+{
+ if (cpus_empty(policy->related_cpus))
+ return show_cpus(policy->cpus, buf);
+ return show_cpus(policy->related_cpus, buf);
+}
+
+/**
+ * show_affected_cpus - show the CPUs affected by each transition
+ */
+static ssize_t show_affected_cpus(struct cpufreq_policy *policy, char *buf)
+{
+ return show_cpus(policy->cpus, buf);
+}
+
static ssize_t store_scaling_setspeed(struct cpufreq_policy *policy,
const char *buf, size_t count)
{
@@ -646,6 +663,7 @@
define_one_ro(scaling_available_governors);
define_one_ro(scaling_driver);
define_one_ro(scaling_cur_freq);
+define_one_ro(related_cpus);
define_one_ro(affected_cpus);
define_one_rw(scaling_min_freq);
define_one_rw(scaling_max_freq);
@@ -658,6 +676,7 @@
&scaling_min_freq.attr,
&scaling_max_freq.attr,
&affected_cpus.attr,
+ &related_cpus.attr,
&scaling_governor.attr,
&scaling_driver.attr,
&scaling_available_governors.attr,
diff --git a/drivers/cpufreq/cpufreq_powersave.c b/drivers/cpufreq/cpufreq_powersave.c
index 13fe06b..88d2f44 100644
--- a/drivers/cpufreq/cpufreq_powersave.c
+++ b/drivers/cpufreq/cpufreq_powersave.c
@@ -35,12 +35,12 @@
return 0;
}
-static struct cpufreq_governor cpufreq_gov_powersave = {
+struct cpufreq_governor cpufreq_gov_powersave = {
.name = "powersave",
.governor = cpufreq_governor_powersave,
.owner = THIS_MODULE,
};
-
+EXPORT_SYMBOL(cpufreq_gov_powersave);
static int __init cpufreq_gov_powersave_init(void)
{
@@ -58,5 +58,9 @@
MODULE_DESCRIPTION("CPUfreq policy governor 'powersave'");
MODULE_LICENSE("GPL");
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE
+fs_initcall(cpufreq_gov_powersave_init);
+#else
module_init(cpufreq_gov_powersave_init);
+#endif
module_exit(cpufreq_gov_powersave_exit);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index ef09e06..ae70d63 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -288,7 +288,7 @@
if (!stat)
return 0;
- old_index = freq_table_get_index(stat, freq->old);
+ old_index = stat->last_index;
new_index = freq_table_get_index(stat, freq->new);
cpufreq_stats_update(freq->cpu);
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 2b38299..6e6c3c4 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -67,7 +67,7 @@
E7205, E7500, E7501 and E7505 server chipsets.
config EDAC_E752X
- tristate "Intel e752x (e7520, e7525, e7320)"
+ tristate "Intel e752x (e7520, e7525, e7320) and 3100"
depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG
help
Support for error detection and correction on the Intel
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index f220754..2b95f1a 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -17,6 +17,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define AMD76X_REVISION " Ver: 2.0.2 " __DATE__
@@ -344,6 +345,9 @@
static int __init amd76x_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&amd76x_driver);
}
@@ -358,3 +362,6 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
MODULE_DESCRIPTION("MC support for AMD 76x memory controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 6eb4347..c94a0eb 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -29,6 +29,7 @@
#define EDAC_MOD_STR "e752x_edac"
static int force_function_unhide;
+static int sysbus_parity = -1;
static struct edac_pci_ctl_info *e752x_pci;
@@ -62,6 +63,14 @@
#define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593
#endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */
+#ifndef PCI_DEVICE_ID_INTEL_3100_0
+#define PCI_DEVICE_ID_INTEL_3100_0 0x35B0
+#endif /* PCI_DEVICE_ID_INTEL_3100_0 */
+
+#ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR
+#define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1
+#endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */
+
#define E752X_NR_CSROWS 8 /* number of csrows */
/* E752X register addresses - device 0 function 0 */
@@ -152,6 +161,12 @@
/* error syndrome register (16b) */
#define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */
+/* 3100 IMCH specific register addresses - device 0 function 1 */
+#define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */
+#define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */
+#define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */
+#define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */
+
/* ICH5R register addresses - device 30 function 0 */
#define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */
#define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */
@@ -160,7 +175,8 @@
enum e752x_chips {
E7520 = 0,
E7525 = 1,
- E7320 = 2
+ E7320 = 2,
+ I3100 = 3
};
struct e752x_pvt {
@@ -185,8 +201,10 @@
struct e752x_error_info {
u32 ferr_global;
u32 nerr_global;
- u8 hi_ferr;
- u8 hi_nerr;
+ u32 nsi_ferr; /* 3100 only */
+ u32 nsi_nerr; /* 3100 only */
+ u8 hi_ferr; /* all but 3100 */
+ u8 hi_nerr; /* all but 3100 */
u16 sysbus_ferr;
u16 sysbus_nerr;
u8 buf_ferr;
@@ -215,6 +233,10 @@
.err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR,
.ctl_dev = PCI_DEVICE_ID_INTEL_7320_0,
.ctl_name = "E7320"},
+ [I3100] = {
+ .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR,
+ .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0,
+ .ctl_name = "3100"},
};
static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci,
@@ -402,7 +424,7 @@
static char *global_message[11] = {
"PCI Express C1", "PCI Express C", "PCI Express B1",
"PCI Express B", "PCI Express A1", "PCI Express A",
- "DMA Controler", "HUB Interface", "System Bus",
+ "DMA Controler", "HUB or NS Interface", "System Bus",
"DRAM Controler", "Internal Buffer"
};
@@ -455,6 +477,63 @@
do_hub_error(fatal, errors);
}
+#define NSI_FATAL_MASK 0x0c080081
+#define NSI_NON_FATAL_MASK 0x23a0ba64
+#define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK)
+
+static char *nsi_message[30] = {
+ "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */
+ "", /* reserved */
+ "NSI Parity Error", /* bit 2, non-fatal */
+ "", /* reserved */
+ "", /* reserved */
+ "Correctable Error Message", /* bit 5, non-fatal */
+ "Non-Fatal Error Message", /* bit 6, non-fatal */
+ "Fatal Error Message", /* bit 7, fatal */
+ "", /* reserved */
+ "Receiver Error", /* bit 9, non-fatal */
+ "", /* reserved */
+ "Bad TLP", /* bit 11, non-fatal */
+ "Bad DLLP", /* bit 12, non-fatal */
+ "REPLAY_NUM Rollover", /* bit 13, non-fatal */
+ "", /* reserved */
+ "Replay Timer Timeout", /* bit 15, non-fatal */
+ "", /* reserved */
+ "", /* reserved */
+ "", /* reserved */
+ "Data Link Protocol Error", /* bit 19, fatal */
+ "", /* reserved */
+ "Poisoned TLP", /* bit 21, non-fatal */
+ "", /* reserved */
+ "Completion Timeout", /* bit 23, non-fatal */
+ "Completer Abort", /* bit 24, non-fatal */
+ "Unexpected Completion", /* bit 25, non-fatal */
+ "Receiver Overflow", /* bit 26, fatal */
+ "Malformed TLP", /* bit 27, fatal */
+ "", /* reserved */
+ "Unsupported Request" /* bit 29, non-fatal */
+};
+
+static void do_nsi_error(int fatal, u32 errors)
+{
+ int i;
+
+ for (i = 0; i < 30; i++) {
+ if (errors & (1 << i))
+ printk(KERN_WARNING "%sError %s\n",
+ fatal_message[fatal], nsi_message[i]);
+ }
+}
+
+static inline void nsi_error(int fatal, u32 errors, int *error_found,
+ int handle_error)
+{
+ *error_found = 1;
+
+ if (handle_error)
+ do_nsi_error(fatal, errors);
+}
+
static char *membuf_message[4] = {
"Internal PMWB to DRAM parity",
"Internal PMWB to System Bus Parity",
@@ -546,6 +625,31 @@
}
}
+static void e752x_check_ns_interface(struct e752x_error_info *info,
+ int *error_found, int handle_error)
+{
+ u32 stat32;
+
+ stat32 = info->nsi_ferr;
+ if (stat32 & NSI_ERR_MASK) { /* Error, so process */
+ if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */
+ nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
+ handle_error);
+ if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */
+ nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
+ handle_error);
+ }
+ stat32 = info->nsi_nerr;
+ if (stat32 & NSI_ERR_MASK) {
+ if (stat32 & NSI_FATAL_MASK)
+ nsi_error(1, stat32 & NSI_FATAL_MASK, error_found,
+ handle_error);
+ if (stat32 & NSI_NON_FATAL_MASK)
+ nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found,
+ handle_error);
+ }
+}
+
static void e752x_check_sysbus(struct e752x_error_info *info,
int *error_found, int handle_error)
{
@@ -653,7 +757,15 @@
pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global);
if (info->ferr_global) {
- pci_read_config_byte(dev, E752X_HI_FERR, &info->hi_ferr);
+ if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
+ pci_read_config_dword(dev, I3100_NSI_FERR,
+ &info->nsi_ferr);
+ info->hi_ferr = 0;
+ } else {
+ pci_read_config_byte(dev, E752X_HI_FERR,
+ &info->hi_ferr);
+ info->nsi_ferr = 0;
+ }
pci_read_config_word(dev, E752X_SYSBUS_FERR,
&info->sysbus_ferr);
pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr);
@@ -669,10 +781,15 @@
pci_read_config_dword(dev, E752X_DRAM_RETR_ADD,
&info->dram_retr_add);
+ /* ignore the reserved bits just in case */
if (info->hi_ferr & 0x7f)
pci_write_config_byte(dev, E752X_HI_FERR,
info->hi_ferr);
+ if (info->nsi_ferr & NSI_ERR_MASK)
+ pci_write_config_dword(dev, I3100_NSI_FERR,
+ info->nsi_ferr);
+
if (info->sysbus_ferr)
pci_write_config_word(dev, E752X_SYSBUS_FERR,
info->sysbus_ferr);
@@ -692,7 +809,15 @@
pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global);
if (info->nerr_global) {
- pci_read_config_byte(dev, E752X_HI_NERR, &info->hi_nerr);
+ if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
+ pci_read_config_dword(dev, I3100_NSI_NERR,
+ &info->nsi_nerr);
+ info->hi_nerr = 0;
+ } else {
+ pci_read_config_byte(dev, E752X_HI_NERR,
+ &info->hi_nerr);
+ info->nsi_nerr = 0;
+ }
pci_read_config_word(dev, E752X_SYSBUS_NERR,
&info->sysbus_nerr);
pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr);
@@ -706,6 +831,10 @@
pci_write_config_byte(dev, E752X_HI_NERR,
info->hi_nerr);
+ if (info->nsi_nerr & NSI_ERR_MASK)
+ pci_write_config_dword(dev, I3100_NSI_NERR,
+ info->nsi_nerr);
+
if (info->sysbus_nerr)
pci_write_config_word(dev, E752X_SYSBUS_NERR,
info->sysbus_nerr);
@@ -750,6 +879,7 @@
global_error(0, stat32, &error_found, handle_errors);
e752x_check_hub_interface(info, &error_found, handle_errors);
+ e752x_check_ns_interface(info, &error_found, handle_errors);
e752x_check_sysbus(info, &error_found, handle_errors);
e752x_check_membuf(info, &error_found, handle_errors);
e752x_check_dram(mci, info, &error_found, handle_errors);
@@ -920,15 +1050,53 @@
return 1;
}
+/* Setup system bus parity mask register.
+ * Sysbus parity supported on:
+ * e7320/e7520/e7525 + Xeon
+ * i3100 + Xeon/Celeron
+ * Sysbus parity not supported on:
+ * i3100 + Pentium M/Celeron M/Core Duo/Core2 Duo
+ */
+static void e752x_init_sysbus_parity_mask(struct e752x_pvt *pvt)
+{
+ char *cpu_id = cpu_data(0).x86_model_id;
+ struct pci_dev *dev = pvt->dev_d0f1;
+ int enable = 1;
+
+ /* Allow module paramter override, else see if CPU supports parity */
+ if (sysbus_parity != -1) {
+ enable = sysbus_parity;
+ } else if (cpu_id[0] &&
+ ((strstr(cpu_id, "Pentium") && strstr(cpu_id, " M ")) ||
+ (strstr(cpu_id, "Celeron") && strstr(cpu_id, " M ")) ||
+ (strstr(cpu_id, "Core") && strstr(cpu_id, "Duo")))) {
+ e752x_printk(KERN_INFO, "System Bus Parity not "
+ "supported by CPU, disabling\n");
+ enable = 0;
+ }
+
+ if (enable)
+ pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0000);
+ else
+ pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x0309);
+}
+
static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt)
{
struct pci_dev *dev;
dev = pvt->dev_d0f1;
/* Turn off error disable & SMI in case the BIOS turned it on */
- pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
- pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
- pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00);
+ if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) {
+ pci_write_config_dword(dev, I3100_NSI_EMASK, 0);
+ pci_write_config_dword(dev, I3100_NSI_SMICMD, 0);
+ } else {
+ pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00);
+ pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00);
+ }
+
+ e752x_init_sysbus_parity_mask(pvt);
+
pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00);
pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00);
pci_write_config_byte(dev, E752X_BUF_SMICMD, 0x00);
@@ -949,16 +1117,6 @@
debugf0("%s(): mci\n", __func__);
debugf0("Starting Probe1\n");
- /* make sure error reporting method is sane */
- switch (edac_op_state) {
- case EDAC_OPSTATE_POLL:
- case EDAC_OPSTATE_NMI:
- break;
- default:
- edac_op_state = EDAC_OPSTATE_POLL;
- break;
- }
-
/* check to see if device 0 function 1 is enabled; if it isn't, we
* assume the BIOS has reserved it for a reason and is expecting
* exclusive access, we take care not to violate that assumption and
@@ -985,8 +1143,9 @@
debugf3("%s(): init mci\n", __func__);
mci->mtype_cap = MEM_FLAG_RDDR;
- mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED |
- EDAC_FLAG_S4ECD4ED;
+ /* 3100 IMCH supports SECDEC only */
+ mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED :
+ (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED);
/* FIXME - what if different memory types are in different csrows? */
mci->mod_name = EDAC_MOD_STR;
mci->mod_ver = E752X_REVISION;
@@ -1018,7 +1177,10 @@
e752x_init_csrows(mci, pdev, ddrcsr);
e752x_init_mem_map_table(pdev, pvt);
- mci->edac_cap |= EDAC_FLAG_NONE;
+ if (dev_idx == I3100)
+ mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */
+ else
+ mci->edac_cap |= EDAC_FLAG_NONE;
debugf3("%s(): tolm, remapbase, remaplimit\n", __func__);
/* load the top of low memory, remap base, and remap limit vars */
@@ -1110,6 +1272,9 @@
PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
E7320},
{
+ PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ I3100},
+ {
0,
} /* 0 terminated list. */
};
@@ -1128,6 +1293,10 @@
int pci_rc;
debugf3("%s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&e752x_driver);
return (pci_rc < 0) ? pci_rc : 0;
}
@@ -1143,10 +1312,15 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n");
-MODULE_DESCRIPTION("MC support for Intel e752x memory controllers");
+MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers");
module_param(force_function_unhide, int, 0444);
MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:"
" 1=force unhide and hope BIOS doesn't fight driver for Dev0:Fun1 access");
+
module_param(edac_op_state, int, 0444);
MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
+
+module_param(sysbus_parity, int, 0444);
+MODULE_PARM_DESC(sysbus_parity, "0=disable system bus parity checking,"
+ " 1=enable system bus parity checking, default=auto-detect");
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 96ecc49..c7d11cc 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -414,16 +414,6 @@
debugf0("%s(): mci\n", __func__);
- /* make sure error reporting method is sane */
- switch (edac_op_state) {
- case EDAC_OPSTATE_POLL:
- case EDAC_OPSTATE_NMI:
- break;
- default:
- edac_op_state = EDAC_OPSTATE_POLL;
- break;
- }
-
pci_read_config_dword(pdev, E7XXX_DRC, &drc);
drc_chan = dual_channel_active(drc, dev_idx);
@@ -565,6 +555,9 @@
static int __init e7xxx_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&e7xxx_driver);
}
diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c
index b9552bc..63372fa 100644
--- a/drivers/edac/edac_device.c
+++ b/drivers/edac/edac_device.c
@@ -36,7 +36,7 @@
* is protected by the 'device_ctls_mutex' lock
*/
static DEFINE_MUTEX(device_ctls_mutex);
-static struct list_head edac_device_list = LIST_HEAD_INIT(edac_device_list);
+static LIST_HEAD(edac_device_list);
#ifdef CONFIG_EDAC_DEBUG
static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev)
@@ -375,37 +375,6 @@
wait_for_completion(&edac_device->removal_complete);
}
-/**
- * edac_device_find
- * Search for a edac_device_ctl_info structure whose index is 'idx'.
- *
- * If found, return a pointer to the structure.
- * Else return NULL.
- *
- * Caller must hold device_ctls_mutex.
- */
-struct edac_device_ctl_info *edac_device_find(int idx)
-{
- struct list_head *item;
- struct edac_device_ctl_info *edac_dev;
-
- /* Iterate over list, looking for exact match of ID */
- list_for_each(item, &edac_device_list) {
- edac_dev = list_entry(item, struct edac_device_ctl_info, link);
-
- if (edac_dev->dev_idx >= idx) {
- if (edac_dev->dev_idx == idx)
- return edac_dev;
-
- /* not on list, so terminate early */
- break;
- }
- }
-
- return NULL;
-}
-EXPORT_SYMBOL_GPL(edac_device_find);
-
/*
* edac_device_workq_function
* performs the operation scheduled by a workq request
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 063a1bf..a4cf164 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -36,7 +36,7 @@
/* lock to memory controller's control array */
static DEFINE_MUTEX(mem_ctls_mutex);
-static struct list_head mc_devices = LIST_HEAD_INIT(mc_devices);
+static LIST_HEAD(mc_devices);
#ifdef CONFIG_EDAC_DEBUG
@@ -886,24 +886,3 @@
mci->csrows[csrow].channels[channel].ce_count++;
}
EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
-
-/*
- * Iterate over all MC instances and check for ECC, et al, errors
- */
-void edac_check_mc_devices(void)
-{
- struct list_head *item;
- struct mem_ctl_info *mci;
-
- debugf3("%s()\n", __func__);
- mutex_lock(&mem_ctls_mutex);
-
- list_for_each(item, &mc_devices) {
- mci = list_entry(item, struct mem_ctl_info, link);
-
- if (mci->edac_check != NULL)
- mci->edac_check(mci);
- }
-
- mutex_unlock(&mem_ctls_mutex);
-}
diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h
index cbc419c..233d479 100644
--- a/drivers/edac/edac_module.h
+++ b/drivers/edac/edac_module.h
@@ -27,7 +27,6 @@
extern void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci);
extern int edac_create_sysfs_mci_device(struct mem_ctl_info *mci);
extern void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci);
-extern void edac_check_mc_devices(void);
extern int edac_get_log_ue(void);
extern int edac_get_log_ce(void);
extern int edac_get_panic_on_ue(void);
diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c
index 32be435..9b24340 100644
--- a/drivers/edac/edac_pci.c
+++ b/drivers/edac/edac_pci.c
@@ -29,7 +29,7 @@
#include "edac_module.h"
static DEFINE_MUTEX(edac_pci_ctls_mutex);
-static struct list_head edac_pci_list = LIST_HEAD_INIT(edac_pci_list);
+static LIST_HEAD(edac_pci_list);
/*
* edac_pci_alloc_ctl_info
@@ -189,6 +189,9 @@
wait_for_completion(&pci->complete);
}
+#if 0
+/* Older code, but might use in the future */
+
/*
* edac_pci_find()
* Search for an edac_pci_ctl_info structure whose index is 'idx'
@@ -219,6 +222,7 @@
return NULL;
}
EXPORT_SYMBOL_GPL(edac_pci_find);
+#endif
/*
* edac_pci_workq_function()
@@ -422,7 +426,7 @@
*
* a Generic parity check API
*/
-void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
+static void edac_pci_generic_check(struct edac_pci_ctl_info *pci)
{
debugf4("%s()\n", __func__);
edac_pci_do_parity_check();
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
index 71c3195..2c1fa1b 100644
--- a/drivers/edac/edac_pci_sysfs.c
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -37,17 +37,17 @@
return check_pci_errors;
}
-int edac_pci_get_log_pe(void)
+static int edac_pci_get_log_pe(void)
{
return edac_pci_log_pe;
}
-int edac_pci_get_log_npe(void)
+static int edac_pci_get_log_npe(void)
{
return edac_pci_log_npe;
}
-int edac_pci_get_panic_on_pe(void)
+static int edac_pci_get_panic_on_pe(void)
{
return edac_pci_panic_on_pe;
}
@@ -197,7 +197,8 @@
*
* unregister the kobj for the EDAC PCI instance
*/
-void edac_pci_unregister_sysfs_instance_kobj(struct edac_pci_ctl_info *pci)
+static void edac_pci_unregister_sysfs_instance_kobj(
+ struct edac_pci_ctl_info *pci)
{
debugf0("%s()\n", __func__);
@@ -337,7 +338,7 @@
* setup the sysfs for EDAC PCI attributes
* assumes edac_class has already been initialized
*/
-int edac_pci_main_kobj_setup(void)
+static int edac_pci_main_kobj_setup(void)
{
int err;
struct sysdev_class *edac_class;
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
index 5d42928..6c9a0f2 100644
--- a/drivers/edac/i3000_edac.c
+++ b/drivers/edac/i3000_edac.c
@@ -326,15 +326,6 @@
return -ENODEV;
}
- switch (edac_op_state) {
- case EDAC_OPSTATE_POLL:
- case EDAC_OPSTATE_NMI:
- break;
- default:
- edac_op_state = EDAC_OPSTATE_POLL;
- break;
- }
-
c0dra[0] = readb(window + I3000_C0DRA + 0); /* ranks 0,1 */
c0dra[1] = readb(window + I3000_C0DRA + 1); /* ranks 2,3 */
c1dra[0] = readb(window + I3000_C1DRA + 0); /* ranks 0,1 */
@@ -503,6 +494,10 @@
int pci_rc;
debugf3("MC: %s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&i3000_driver);
if (pci_rc < 0)
goto fail0;
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 5a85201..4a16b5b 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -1286,16 +1286,6 @@
if (PCI_FUNC(pdev->devfn) != 0)
return -ENODEV;
- /* make sure error reporting method is sane */
- switch (edac_op_state) {
- case EDAC_OPSTATE_POLL:
- case EDAC_OPSTATE_NMI:
- break;
- default:
- edac_op_state = EDAC_OPSTATE_POLL;
- break;
- }
-
/* Ask the devices for the number of CSROWS and CHANNELS so
* that we can calculate the memory resources, etc
*
@@ -1478,6 +1468,9 @@
debugf2("MC: " __FILE__ ": %s()\n", __func__);
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&i5000_driver);
return (pci_rc < 0) ? pci_rc : 0;
@@ -1501,5 +1494,6 @@
("Linux Networx (http://lnxi.com) Doug Thompson <norsk5@xmission.com>");
MODULE_DESCRIPTION("MC Driver for Intel I5000 memory controllers - "
I5000_REVISION);
+
module_param(edac_op_state, int, 0444);
MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index 83bfe37..c5305e3 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -29,6 +29,7 @@
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define I82443_REVISION "0.1"
@@ -386,6 +387,9 @@
static int __init i82443bxgx_edacmc_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&i82443bxgx_edacmc_driver);
}
@@ -400,3 +404,6 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD");
MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index f5ecd2c..c0088ba 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -14,6 +14,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define I82860_REVISION " Ver: 2.0.2 " __DATE__
@@ -294,6 +295,9 @@
debugf3("%s()\n", __func__);
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
if ((pci_rc = pci_register_driver(&i82860_driver)) < 0)
goto fail0;
@@ -345,3 +349,6 @@
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com) "
"Ben Woodard <woodard@redhat.com>");
MODULE_DESCRIPTION("ECC support for Intel 82860 memory hub controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 031abad..e43bdc4 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -18,6 +18,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define I82875P_REVISION " Ver: 2.0.2 " __DATE__
@@ -393,6 +394,7 @@
struct i82875p_error_info discard;
debugf0("%s()\n", __func__);
+
ovrfl_pdev = pci_get_device(PCI_VEND_DEV(INTEL, 82875_6), NULL);
if (i82875p_setup_overfl_dev(pdev, &ovrfl_pdev, &ovrfl_window))
@@ -532,6 +534,10 @@
int pci_rc;
debugf3("%s()\n", __func__);
+
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&i82875p_driver);
if (pci_rc < 0)
@@ -586,3 +592,6 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Linux Networx (http://lnxi.com) Thayne Harbaugh");
MODULE_DESCRIPTION("MC support for Intel 82875 memory hub controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 0ee8884..2eed3ea 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -14,7 +14,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
-
+#include <linux/edac.h>
#include "edac_core.h"
#define I82975X_REVISION " Ver: 1.0.0 " __DATE__
@@ -611,6 +611,9 @@
debugf3("%s()\n", __func__);
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
pci_rc = pci_register_driver(&i82975x_driver);
if (pci_rc < 0)
goto fail0;
@@ -664,3 +667,6 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Arvind R. <arvind@acarlab.com>");
MODULE_DESCRIPTION("MC support for Intel 82975 memory hub controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
index 9032091..8e6b91b 100644
--- a/drivers/edac/pasemi_edac.c
+++ b/drivers/edac/pasemi_edac.c
@@ -26,6 +26,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define MODULE_NAME "pasemi_edac"
@@ -284,6 +285,9 @@
static int __init pasemi_edac_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&pasemi_edac_driver);
}
@@ -298,3 +302,6 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>");
MODULE_DESCRIPTION("MC support for PA Semi PWRficient memory controller");
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
+
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index e25f712..9900675 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -20,6 +20,7 @@
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <linux/slab.h>
+#include <linux/edac.h>
#include "edac_core.h"
#define R82600_REVISION " Ver: 2.0.2 " __DATE__
@@ -393,6 +394,9 @@
static int __init r82600_init(void)
{
+ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+ opstate_init();
+
return pci_register_driver(&r82600_driver);
}
@@ -412,3 +416,6 @@
module_param(disable_hardware_scrub, bool, 0644);
MODULE_PARM_DESC(disable_hardware_scrub,
"If set, disable the chipset's automatic scrub for CEs");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");
diff --git a/drivers/firewire/fw-sbp2.c b/drivers/firewire/fw-sbp2.c
index 2a999373..b2458bb 100644
--- a/drivers/firewire/fw-sbp2.c
+++ b/drivers/firewire/fw-sbp2.c
@@ -784,7 +784,7 @@
kfree(lu);
}
scsi_remove_host(shost);
- fw_notify("released %s\n", tgt->bus_id);
+ fw_notify("released %s, target %d:0:0\n", tgt->bus_id, shost->host_no);
fw_unit_put(tgt->unit);
scsi_host_put(shost);
@@ -1487,7 +1487,7 @@
if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0)
goto out;
- memcpy(orb->request.command_block, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+ memcpy(orb->request.command_block, cmd->cmnd, cmd->cmd_len);
orb->base.callback = complete_command_orb;
orb->base.request_bus =
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 40ffd76..dc2cec6 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -17,6 +17,15 @@
obscure configurations. Most disk controller BIOS vendors do
not yet implement this feature.
+config EDD_OFF
+ bool "Sets default behavior for EDD detection to off"
+ depends on EDD
+ default n
+ help
+ Say Y if you want EDD disabled by default, even though it is compiled into the
+ kernel. Say N if you want EDD enabled by default. EDD can be dynamically set
+ using the kernel parameter 'edd={on|skipmbr|off}'.
+
config EFI_VARS
tristate "EFI Variable Support via sysfs"
depends on EFI
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index f235940..25918f7 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -63,7 +63,7 @@
return;
dev_dbg(&dcdbas_pdev->dev, "%s: phys: %x size: %lu\n",
- __FUNCTION__, smi_data_buf_phys_addr, smi_data_buf_size);
+ __func__, 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);
@@ -92,7 +92,7 @@
if (!buf) {
dev_dbg(&dcdbas_pdev->dev,
"%s: failed to allocate memory size %lu\n",
- __FUNCTION__, size);
+ __func__, size);
return -ENOMEM;
}
/* memory zeroed by dma_alloc_coherent */
@@ -110,7 +110,7 @@
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);
+ __func__, smi_data_buf_phys_addr, smi_data_buf_size);
return 0;
}
@@ -258,7 +258,7 @@
if (smi_cmd->magic != SMI_CMD_MAGIC) {
dev_info(&dcdbas_pdev->dev, "%s: invalid magic value\n",
- __FUNCTION__);
+ __func__);
return -EBADR;
}
@@ -267,7 +267,7 @@
set_cpus_allowed_ptr(current, &cpumask_of_cpu(0));
if (smp_processor_id() != 0) {
dev_dbg(&dcdbas_pdev->dev, "%s: failed to get CPU 0\n",
- __FUNCTION__);
+ __func__);
ret = -EBUSY;
goto out;
}
@@ -428,7 +428,7 @@
default:
dev_dbg(&dcdbas_pdev->dev, "%s: invalid SMI type %u\n",
- __FUNCTION__, host_control_smi_type);
+ __func__, host_control_smi_type);
return -ENOSYS;
}
@@ -456,13 +456,13 @@
host_control_action = HC_ACTION_NONE;
if (!smi_data_buf) {
- dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __FUNCTION__);
+ dev_dbg(&dcdbas_pdev->dev, "%s: no SMI buffer\n", __func__);
return;
}
if (smi_data_buf_size < sizeof(struct apm_cmd)) {
dev_dbg(&dcdbas_pdev->dev, "%s: SMI buffer too small\n",
- __FUNCTION__);
+ __func__);
return;
}
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index 477a3d0..6a8b1e0 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/firmware/dell_rbu.c
@@ -123,7 +123,7 @@
if (!newpacket) {
printk(KERN_WARNING
"dell_rbu:%s: failed to allocate new "
- "packet\n", __FUNCTION__);
+ "packet\n", __func__);
retval = -ENOMEM;
spin_lock(&rbu_data.lock);
goto out_noalloc;
@@ -152,7 +152,7 @@
printk(KERN_WARNING
"dell_rbu:%s: failed to allocate "
"invalid_addr_packet_array \n",
- __FUNCTION__);
+ __func__);
retval = -ENOMEM;
spin_lock(&rbu_data.lock);
goto out_alloc_packet;
@@ -164,7 +164,7 @@
if (!packet_data_temp_buf) {
printk(KERN_WARNING
"dell_rbu:%s: failed to allocate new "
- "packet\n", __FUNCTION__);
+ "packet\n", __func__);
retval = -ENOMEM;
spin_lock(&rbu_data.lock);
goto out_alloc_packet_array;
@@ -416,7 +416,7 @@
*/
if ((size != 0) && (rbu_data.image_update_buffer == NULL)) {
printk(KERN_ERR "dell_rbu:%s: corruption "
- "check failed\n", __FUNCTION__);
+ "check failed\n", __func__);
return -EINVAL;
}
/*
@@ -642,7 +642,7 @@
if (req_firm_rc) {
printk(KERN_ERR
"dell_rbu:%s request_firmware_nowait"
- " failed %d\n", __FUNCTION__, rc);
+ " failed %d\n", __func__, rc);
rc = -EIO;
} else
rbu_data.entry_created = 1;
@@ -718,7 +718,7 @@
if (IS_ERR(rbu_device)) {
printk(KERN_ERR
"dell_rbu:%s:platform_device_register_simple "
- "failed\n", __FUNCTION__);
+ "failed\n", __func__);
return PTR_ERR(rbu_device);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 24c62b8..7f138c6 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -382,7 +382,7 @@
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
pr_debug("%s: gpio-%d status %d\n",
- __FUNCTION__, gpio, status);
+ __func__, gpio, status);
return status;
}
EXPORT_SYMBOL_GPL(gpio_direction_input);
@@ -420,7 +420,7 @@
spin_unlock_irqrestore(&gpio_lock, flags);
if (status)
pr_debug("%s: gpio-%d status %d\n",
- __FUNCTION__, gpio, status);
+ __func__, gpio, status);
return status;
}
EXPORT_SYMBOL_GPL(gpio_direction_output);
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index e0e0af5..93f9167 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -23,21 +23,19 @@
#define PCA953X_INVERT 2
#define PCA953X_DIRECTION 3
-/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */
-struct pca953x_desc {
- char name[I2C_NAME_SIZE];
- unsigned long driver_data;
-};
-
-static const struct pca953x_desc pca953x_descs[] = {
+static const struct i2c_device_id pca953x_id[] = {
{ "pca9534", 8, },
{ "pca9535", 16, },
{ "pca9536", 4, },
{ "pca9537", 4, },
{ "pca9538", 8, },
{ "pca9539", 16, },
+ { "pca9555", 16, },
+ { "pca9557", 8, },
/* REVISIT several pca955x parts should work here too */
+ { }
};
+MODULE_DEVICE_TABLE(i2c, pca953x_id);
struct pca953x_chip {
unsigned gpio_start;
@@ -192,26 +190,17 @@
gc->owner = THIS_MODULE;
}
-static int __devinit pca953x_probe(struct i2c_client *client)
+static int __devinit pca953x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
- int ret, i;
- const struct pca953x_desc *id = NULL;
+ int ret;
pdata = client->dev.platform_data;
if (pdata == NULL)
return -ENODEV;
- /* this loop vanishes when we get i2c_device_id */
- for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++)
- if (!strcmp(pca953x_descs[i].name, client->name)) {
- id = pca953x_descs + i;
- break;
- }
- if (!id)
- return -ENODEV;
-
chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
@@ -291,6 +280,7 @@
},
.probe = pca953x_probe,
.remove = pca953x_remove,
+ .id_table = pca953x_id,
};
static int __init pca953x_init(void)
diff --git a/drivers/gpio/pcf857x.c b/drivers/gpio/pcf857x.c
index 1106aa1..aa6cc8b 100644
--- a/drivers/gpio/pcf857x.c
+++ b/drivers/gpio/pcf857x.c
@@ -26,6 +26,21 @@
#include <asm/gpio.h>
+static const struct i2c_device_id pcf857x_id[] = {
+ { "pcf8574", 8 },
+ { "pca8574", 8 },
+ { "pca9670", 8 },
+ { "pca9672", 8 },
+ { "pca9674", 8 },
+ { "pcf8575", 16 },
+ { "pca8575", 16 },
+ { "pca9671", 16 },
+ { "pca9673", 16 },
+ { "pca9675", 16 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf857x_id);
+
/*
* The pcf857x, pca857x, and pca967x chips only expose one read and one
* write register. Writing a "one" bit (to match the reset state) lets
@@ -142,7 +157,8 @@
/*-------------------------------------------------------------------------*/
-static int pcf857x_probe(struct i2c_client *client)
+static int pcf857x_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct pcf857x_platform_data *pdata;
struct pcf857x *gpio;
@@ -172,13 +188,8 @@
*
* NOTE: we don't distinguish here between *4 and *4a parts.
*/
- if (strcmp(client->name, "pcf8574") == 0
- || strcmp(client->name, "pca8574") == 0
- || strcmp(client->name, "pca9670") == 0
- || strcmp(client->name, "pca9672") == 0
- || strcmp(client->name, "pca9674") == 0
- ) {
- gpio->chip.ngpio = 8;
+ gpio->chip.ngpio = id->driver_data;
+ if (gpio->chip.ngpio == 8) {
gpio->chip.direction_input = pcf857x_input8;
gpio->chip.get = pcf857x_get8;
gpio->chip.direction_output = pcf857x_output8;
@@ -198,13 +209,7 @@
*
* NOTE: we don't distinguish here between '75 and '75c parts.
*/
- } else if (strcmp(client->name, "pcf8575") == 0
- || strcmp(client->name, "pca8575") == 0
- || strcmp(client->name, "pca9671") == 0
- || strcmp(client->name, "pca9673") == 0
- || strcmp(client->name, "pca9675") == 0
- ) {
- gpio->chip.ngpio = 16;
+ } else if (gpio->chip.ngpio == 16) {
gpio->chip.direction_input = pcf857x_input16;
gpio->chip.get = pcf857x_get16;
gpio->chip.direction_output = pcf857x_output16;
@@ -313,6 +318,7 @@
},
.probe = pcf857x_probe,
.remove = pcf857x_remove,
+ .id_table = pcf857x_id,
};
static int __init pcf857x_init(void)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index e03c67d..f43d6d3 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -606,7 +606,7 @@
case 2:
if ((end - start) < 2)
return NULL;
- item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start));
+ item->data.u16 = get_unaligned_le16(start);
start = (__u8 *)((__le16 *)start + 1);
return start;
@@ -614,7 +614,7 @@
item->size++;
if ((end - start) < 4)
return NULL;
- item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start));
+ item->data.u32 = get_unaligned_le32(start);
start = (__u8 *)((__le32 *)start + 1);
return start;
}
@@ -765,7 +765,7 @@
report += offset >> 3; /* adjust byte index */
offset &= 7; /* now only need bit offset into one byte */
- x = le64_to_cpu(get_unaligned((__le64 *) report));
+ x = get_unaligned_le64(report);
x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */
return (u32) x;
}
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index ed71a8b..5c8b6e0 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -224,7 +224,7 @@
if (in_data & 0xF000) {
printk(KERN_DEBUG
"%s : Doesn't look like an ads7828 device\n",
- __FUNCTION__);
+ __func__);
goto exit_free;
}
}
diff --git a/drivers/hwmon/adt7473.c b/drivers/hwmon/adt7473.c
index 9587869..c1009d6 100644
--- a/drivers/hwmon/adt7473.c
+++ b/drivers/hwmon/adt7473.c
@@ -422,18 +422,14 @@
* number in the range -128 to 127, or as an unsigned number that must
* be offset by 64.
*/
-static int decode_temp(struct adt7473_data *data, u8 raw)
+static int decode_temp(u8 twos_complement, u8 raw)
{
- if (data->temp_twos_complement)
- return (s8)raw;
- return raw - 64;
+ return twos_complement ? (s8)raw : raw - 64;
}
-static u8 encode_temp(struct adt7473_data *data, int cooked)
+static u8 encode_temp(u8 twos_complement, int cooked)
{
- if (data->temp_twos_complement)
- return (cooked & 0xFF);
- return cooked + 64;
+ return twos_complement ? cooked & 0xFF : cooked + 64;
}
static ssize_t show_temp_min(struct device *dev,
@@ -442,8 +438,9 @@
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_min[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_min[attr->index]));
}
static ssize_t set_temp_min(struct device *dev,
@@ -455,7 +452,7 @@
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_min[attr->index] = temp;
@@ -472,8 +469,9 @@
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_max[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_max[attr->index]));
}
static ssize_t set_temp_max(struct device *dev,
@@ -485,7 +483,7 @@
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_max[attr->index] = temp;
@@ -501,8 +499,9 @@
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp[attr->index]));
}
static ssize_t show_fan_min(struct device *dev,
@@ -671,8 +670,9 @@
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_tmax[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_tmax[attr->index]));
}
static ssize_t set_temp_tmax(struct device *dev,
@@ -684,7 +684,7 @@
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_tmax[attr->index] = temp;
@@ -701,8 +701,9 @@
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct adt7473_data *data = adt7473_update_device(dev);
- return sprintf(buf, "%d\n",
- 1000 * decode_temp(data, data->temp_tmin[attr->index]));
+ return sprintf(buf, "%d\n", 1000 * decode_temp(
+ data->temp_twos_complement,
+ data->temp_tmin[attr->index]));
}
static ssize_t set_temp_tmin(struct device *dev,
@@ -714,7 +715,7 @@
struct i2c_client *client = to_i2c_client(dev);
struct adt7473_data *data = i2c_get_clientdata(client);
int temp = simple_strtol(buf, NULL, 10) / 1000;
- temp = encode_temp(data, temp);
+ temp = encode_temp(data->temp_twos_complement, temp);
mutex_lock(&data->lock);
data->temp_tmin[attr->index] = temp;
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index 84712a2..fe2eea4 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -953,12 +953,8 @@
static void asb100_init_client(struct i2c_client *client)
{
struct asb100_data *data = i2c_get_clientdata(client);
- int vid = 0;
- vid = asb100_read_value(client, ASB100_REG_VID_FANDIV) & 0x0f;
- vid |= (asb100_read_value(client, ASB100_REG_CHIPID) & 0x01) << 4;
data->vrm = vid_which_vrm();
- vid = vid_from_reg(vid, data->vrm);
/* Start monitoring */
asb100_write_value(client, ASB100_REG_CONFIG,
diff --git a/drivers/hwmon/f75375s.c b/drivers/hwmon/f75375s.c
index 1464338..dc1f30e 100644
--- a/drivers/hwmon/f75375s.c
+++ b/drivers/hwmon/f75375s.c
@@ -117,7 +117,8 @@
static int f75375_attach_adapter(struct i2c_adapter *adapter);
static int f75375_detect(struct i2c_adapter *adapter, int address, int kind);
static int f75375_detach_client(struct i2c_client *client);
-static int f75375_probe(struct i2c_client *client);
+static int f75375_probe(struct i2c_client *client,
+ const struct i2c_device_id *id);
static int f75375_remove(struct i2c_client *client);
static struct i2c_driver f75375_legacy_driver = {
@@ -128,12 +129,20 @@
.detach_client = f75375_detach_client,
};
+static const struct i2c_device_id f75375_id[] = {
+ { "f75373", f75373 },
+ { "f75375", f75375 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, f75375_id);
+
static struct i2c_driver f75375_driver = {
.driver = {
.name = "f75375",
},
.probe = f75375_probe,
.remove = f75375_remove,
+ .id_table = f75375_id,
};
static inline int f75375_read8(struct i2c_client *client, u8 reg)
@@ -628,7 +637,8 @@
}
-static int f75375_probe(struct i2c_client *client)
+static int f75375_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct f75375_data *data = i2c_get_clientdata(client);
struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data;
@@ -643,15 +653,7 @@
i2c_set_clientdata(client, data);
data->client = client;
mutex_init(&data->update_lock);
-
- if (strcmp(client->name, "f75375") == 0)
- data->kind = f75375;
- else if (strcmp(client->name, "f75373") == 0)
- data->kind = f75373;
- else {
- dev_err(&client->dev, "Unsupported device: %s\n", client->name);
- return -ENODEV;
- }
+ data->kind = id->driver_data;
if ((err = sysfs_create_group(&client->dev.kobj, &f75375_group)))
goto exit_free;
@@ -712,6 +714,7 @@
u8 version = 0;
int err = 0;
const char *name = "";
+ struct i2c_device_id id;
if (!(client = kzalloc(sizeof(*client), GFP_KERNEL))) {
err = -ENOMEM;
@@ -748,7 +751,9 @@
if ((err = i2c_attach_client(client)))
goto exit_free;
- if ((err = f75375_probe(client)) < 0)
+ strlcpy(id.name, name, I2C_NAME_SIZE);
+ id.driver_data = kind;
+ if ((err = f75375_probe(client, &id)) < 0)
goto exit_detach;
return 0;
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 115f409..fa76969 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -248,7 +248,7 @@
/* All registers are word-sized, except for the configuration register.
LM75 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
+ the SMBus standard. */
static int lm75_read_value(struct i2c_client *client, u8 reg)
{
if (reg == LM75_REG_CONF)
@@ -257,9 +257,6 @@
return swab16(i2c_smbus_read_word_data(client, reg));
}
-/* All registers are word-sized, except for the configuration register.
- LM75 uses a high-byte first convention, which is exactly opposite to
- the usual practice. */
static int lm75_write_value(struct i2c_client *client, u8 reg, u16 value)
{
if (reg == LM75_REG_CONF)
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index f61d8f4..eb03544 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -335,11 +335,23 @@
static int __init smsc47b397_find(unsigned short *addr)
{
u8 id, rev;
+ char *name;
superio_enter();
id = force_id ? force_id : superio_inb(SUPERIO_REG_DEVID);
- if ((id != 0x6f) && (id != 0x81) && (id != 0x85)) {
+ switch(id) {
+ case 0x81:
+ name = "SCH5307-NS";
+ break;
+ case 0x6f:
+ name = "LPC47B397-NC";
+ break;
+ case 0x85:
+ case 0x8c:
+ name = "SCH5317";
+ break;
+ default:
superio_exit();
return -ENODEV;
}
@@ -352,8 +364,7 @@
printk(KERN_INFO DRVNAME ": found SMSC %s "
"(base address 0x%04x, revision %u)\n",
- id == 0x81 ? "SCH5307-NS" : id == 0x85 ? "SCH5317" :
- "LPC47B397-NC", *addr, rev);
+ name, *addr, rev);
superio_exit();
return 0;
diff --git a/drivers/hwmon/w83793.c b/drivers/hwmon/w83793.c
index ee35af9..ed3c019 100644
--- a/drivers/hwmon/w83793.c
+++ b/drivers/hwmon/w83793.c
@@ -1024,10 +1024,9 @@
SENSOR_ATTR_2(cpu0_vid, S_IRUGO, show_vid, NULL, NOT_USED, 0),
SENSOR_ATTR_2(cpu1_vid, S_IRUGO, show_vid, NULL, NOT_USED, 1),
};
+static DEVICE_ATTR(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm);
static struct sensor_device_attribute_2 sda_single_files[] = {
- SENSOR_ATTR_2(vrm, S_IWUSR | S_IRUGO, show_vrm, store_vrm,
- NOT_USED, NOT_USED),
SENSOR_ATTR_2(chassis, S_IWUSR | S_IRUGO, show_alarm_beep,
store_chassis_clear, ALARM_STATUS, 30),
SENSOR_ATTR_2(beep_enable, S_IWUSR | S_IRUGO, show_beep_enable,
@@ -1080,6 +1079,7 @@
for (i = 0; i < ARRAY_SIZE(w83793_vid); i++)
device_remove_file(dev, &w83793_vid[i].dev_attr);
+ device_remove_file(dev, &dev_attr_vrm);
for (i = 0; i < ARRAY_SIZE(w83793_left_fan); i++)
device_remove_file(dev, &w83793_left_fan[i].dev_attr);
@@ -1282,7 +1282,6 @@
/* Initialize the chip */
w83793_init_client(client);
- data->vrm = vid_which_vrm();
/*
Only fan 1-5 has their own input pins,
Pwm 1-3 has their own pins
@@ -1293,7 +1292,9 @@
val = w83793_read_value(client, W83793_REG_FANIN_CTRL);
/* check the function of pins 49-56 */
- if (!(tmp & 0x80)) {
+ if (tmp & 0x80) {
+ data->has_vid |= 0x2; /* has VIDB */
+ } else {
data->has_pwm |= 0x18; /* pwm 4,5 */
if (val & 0x01) { /* fan 6 */
data->has_fan |= 0x20;
@@ -1309,13 +1310,15 @@
}
}
+ /* check the function of pins 37-40 */
+ if (!(tmp & 0x29))
+ data->has_vid |= 0x1; /* has VIDA */
if (0x08 == (tmp & 0x0c)) {
if (val & 0x08) /* fan 9 */
data->has_fan |= 0x100;
if (val & 0x10) /* fan 10 */
data->has_fan |= 0x200;
}
-
if (0x20 == (tmp & 0x30)) {
if (val & 0x20) /* fan 11 */
data->has_fan |= 0x400;
@@ -1359,13 +1362,6 @@
if (tmp & 0x02)
data->has_temp |= 0x20;
- /* Detect the VID usage and ignore unused input */
- tmp = w83793_read_value(client, W83793_REG_MFC);
- if (!(tmp & 0x29))
- data->has_vid |= 0x1; /* has VIDA */
- if (tmp & 0x80)
- data->has_vid |= 0x2; /* has VIDB */
-
/* Register sysfs hooks */
for (i = 0; i < ARRAY_SIZE(w83793_sensor_attr_2); i++) {
err = device_create_file(dev,
@@ -1381,6 +1377,12 @@
if (err)
goto exit_remove;
}
+ if (data->has_vid) {
+ data->vrm = vid_which_vrm();
+ err = device_create_file(dev, &dev_attr_vrm);
+ if (err)
+ goto exit_remove;
+ }
for (i = 0; i < ARRAY_SIZE(sda_single_files); i++) {
err = device_create_file(dev, &sda_single_files[i].dev_attr);
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 77f2d48..52e268e 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -301,8 +301,8 @@
msleep(i);
}
- dev_err(&client->dev, "Couldn't read value from register 0x%02x. "
- "Please report.\n", reg);
+ dev_err(&client->dev, "Couldn't read value from register 0x%02x.\n",
+ reg);
return defval;
}
diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c
index e5e96c8..c38a0a1 100644
--- a/drivers/i2c/busses/i2c-amd756-s4882.c
+++ b/drivers/i2c/busses/i2c-amd756-s4882.c
@@ -1,7 +1,7 @@
/*
* i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
*
- * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004, 2008 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
@@ -231,7 +231,8 @@
kfree(s4882_adapter);
s4882_adapter = NULL;
ERROR1:
- i2c_del_adapter(&amd756_smbus);
+ /* Restore physical bus */
+ i2c_add_adapter(&amd756_smbus);
ERROR0:
return error;
}
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 9bbe96c..fdc9ad8 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -38,7 +38,6 @@
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/init.h>
-#include <linux/apm_bios.h>
#include <linux/dmi.h>
#include <asm/io.h>
@@ -223,7 +222,7 @@
dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
return -1;
} else {
- dev_dbg(&piix4_adapter.dev, "Successfull!\n");
+ dev_dbg(&piix4_adapter.dev, "Successful!\n");
}
}
@@ -343,12 +342,7 @@
switch (size) {
- case PIIX4_BYTE: /* Where is the result put? I assume here it is in
- SMBHSTDAT0 but it might just as well be in the
- SMBHSTCMD. No clue in the docs */
-
- data->byte = inb_p(SMBHSTDAT0);
- break;
+ case PIIX4_BYTE:
case PIIX4_BYTE_DATA:
data->byte = inb_p(SMBHSTDAT0);
break;
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 283769c..9ca8f91 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -238,7 +238,7 @@
dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
return -1;
} else {
- dev_dbg(&adap->dev, "Successfull!\n");
+ dev_dbg(&adap->dev, "Successful!\n");
}
}
@@ -316,14 +316,8 @@
}
size = (size == I2C_SMBUS_PROC_CALL) ? SIS5595_PROC_CALL : SIS5595_WORD_DATA;
break;
-/*
- case I2C_SMBUS_BLOCK_DATA:
- printk(KERN_WARNING "sis5595.o: Block data not yet implemented!\n");
- return -1;
- break;
-*/
default:
- printk(KERN_WARNING "sis5595.o: Unsupported transaction %d\n", size);
+ dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
return -1;
}
@@ -338,9 +332,7 @@
switch (size) {
- case SIS5595_BYTE: /* Where is the result put? I assume here it is in
- SMB_DATA but it might just as well be in the
- SMB_CMD. No clue in the docs */
+ case SIS5595_BYTE:
case SIS5595_BYTE_DATA:
data->byte = sis5595_read(SMB_BYTE);
break;
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index 5fd734f..3765dd7 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -136,7 +136,7 @@
dev_dbg(&adap->dev, "Failed! (%02x)\n", temp);
return -1;
} else {
- dev_dbg(&adap->dev, "Successfull!\n");
+ dev_dbg(&adap->dev, "Successful!\n");
}
}
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index c2a9f8c..d08eeec 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -33,7 +33,7 @@
static unsigned short chip_addr[MAX_CHIPS];
module_param_array(chip_addr, ushort, NULL, S_IRUGO);
MODULE_PARM_DESC(chip_addr,
- "Chip addresses (up to 10, between 0x03 and 0x77)\n");
+ "Chip addresses (up to 10, between 0x03 and 0x77)");
struct stub_chip {
u8 pointer;
diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c
index 1b0cfd5..de9db49 100644
--- a/drivers/i2c/busses/i2c-taos-evm.c
+++ b/drivers/i2c/busses/i2c-taos-evm.c
@@ -51,7 +51,6 @@
/* TAOS TSL2550 EVM */
static struct i2c_board_info tsl2550_info = {
I2C_BOARD_INFO("tsl2550", 0x39),
- .type = "tsl2550",
};
/* Instantiate i2c devices based on the adapter name */
@@ -59,7 +58,7 @@
{
if (!strncmp(adapter->name, "TAOS TSL2550 EVM", 16)) {
dev_info(&adapter->dev, "Instantiating device %s at 0x%02x\n",
- tsl2550_info.driver_name, tsl2550_info.addr);
+ tsl2550_info.type, tsl2550_info.addr);
return i2c_new_device(adapter, &tsl2550_info);
}
diff --git a/drivers/i2c/chips/ds1682.c b/drivers/i2c/chips/ds1682.c
index 9e94542..23be4d4 100644
--- a/drivers/i2c/chips/ds1682.c
+++ b/drivers/i2c/chips/ds1682.c
@@ -200,7 +200,8 @@
/*
* Called when a ds1682 device is matched with this driver
*/
-static int ds1682_probe(struct i2c_client *client)
+static int ds1682_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int rc;
@@ -234,12 +235,19 @@
return 0;
}
+static const struct i2c_device_id ds1682_id[] = {
+ { "ds1682", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1682_id);
+
static struct i2c_driver ds1682_driver = {
.driver = {
.name = "ds1682",
},
.probe = ds1682_probe,
.remove = ds1682_remove,
+ .id_table = ds1682_id,
};
static int __init ds1682_init(void)
diff --git a/drivers/i2c/chips/menelaus.c b/drivers/i2c/chips/menelaus.c
index 2dea012..b36db17 100644
--- a/drivers/i2c/chips/menelaus.c
+++ b/drivers/i2c/chips/menelaus.c
@@ -1149,7 +1149,8 @@
static struct i2c_driver menelaus_i2c_driver;
-static int menelaus_probe(struct i2c_client *client)
+static int menelaus_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct menelaus_chip *menelaus;
int rev = 0, val;
@@ -1242,12 +1243,19 @@
return 0;
}
+static const struct i2c_device_id menelaus_id[] = {
+ { "menelaus", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, menelaus_id);
+
static struct i2c_driver menelaus_i2c_driver = {
.driver = {
.name = DRIVER_NAME,
},
.probe = menelaus_probe,
.remove = __exit_p(menelaus_remove),
+ .id_table = menelaus_id,
};
static int __init menelaus_init(void)
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index b67f69c..8594968 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -64,7 +64,6 @@
* as part of board setup by a bootloader.
*/
enum tps_model {
- TPS_UNKNOWN = 0,
TPS65010,
TPS65011,
TPS65012,
@@ -527,11 +526,13 @@
flush_scheduled_work();
debugfs_remove(tps->file);
kfree(tps);
+ i2c_set_clientdata(client, NULL);
the_tps = NULL;
return 0;
}
-static int tps65010_probe(struct i2c_client *client)
+static int tps65010_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tps65010 *tps;
int status;
@@ -552,20 +553,7 @@
mutex_init(&tps->lock);
INIT_DELAYED_WORK(&tps->work, tps65010_work);
tps->client = client;
-
- if (strcmp(client->name, "tps65010") == 0)
- tps->model = TPS65010;
- else if (strcmp(client->name, "tps65011") == 0)
- tps->model = TPS65011;
- else if (strcmp(client->name, "tps65012") == 0)
- tps->model = TPS65012;
- else if (strcmp(client->name, "tps65013") == 0)
- tps->model = TPS65013;
- else {
- dev_warn(&client->dev, "unknown chip '%s'\n", client->name);
- status = -ENODEV;
- goto fail1;
- }
+ tps->model = id->driver_data;
/* the IRQ is active low, but many gpio lines can't support that
* so this driver uses falling-edge triggers instead.
@@ -594,9 +582,6 @@
case TPS65012:
tps->por = 1;
break;
- case TPS_UNKNOWN:
- printk(KERN_WARNING "%s: unknown TPS chip\n", DRIVER_NAME);
- break;
/* else CHGCONFIG.POR is replaced by AUA, enabling a WAIT mode */
}
tps->chgconf = i2c_smbus_read_byte_data(client, TPS_CHGCONFIG);
@@ -615,6 +600,7 @@
i2c_smbus_read_byte_data(client, TPS_DEFGPIO),
i2c_smbus_read_byte_data(client, TPS_MASK3));
+ i2c_set_clientdata(client, tps);
the_tps = tps;
#if defined(CONFIG_USB_GADGET) && !defined(CONFIG_USB_OTG)
@@ -682,12 +668,22 @@
return status;
}
+static const struct i2c_device_id tps65010_id[] = {
+ { "tps65010", TPS65010 },
+ { "tps65011", TPS65011 },
+ { "tps65012", TPS65012 },
+ { "tps65013", TPS65013 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tps65010_id);
+
static struct i2c_driver tps65010_driver = {
.driver = {
.name = "tps65010",
},
.probe = tps65010_probe,
.remove = __exit_p(tps65010_remove),
+ .id_table = tps65010_id,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/i2c/chips/tsl2550.c b/drivers/i2c/chips/tsl2550.c
index a10fd27..1a9cc13 100644
--- a/drivers/i2c/chips/tsl2550.c
+++ b/drivers/i2c/chips/tsl2550.c
@@ -364,7 +364,8 @@
*/
static struct i2c_driver tsl2550_driver;
-static int __devinit tsl2550_probe(struct i2c_client *client)
+static int __devinit tsl2550_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
struct tsl2550_data *data;
@@ -451,6 +452,12 @@
#endif /* CONFIG_PM */
+static const struct i2c_device_id tsl2550_id[] = {
+ { "tsl2550", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tsl2550_id);
+
static struct i2c_driver tsl2550_driver = {
.driver = {
.name = TSL2550_DRV_NAME,
@@ -460,6 +467,7 @@
.resume = tsl2550_resume,
.probe = tsl2550_probe,
.remove = __devexit_p(tsl2550_remove),
+ .id_table = tsl2550_id,
};
static int __init tsl2550_init(void)
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 6c7fa8d..26384da 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -48,6 +48,17 @@
/* ------------------------------------------------------------------------- */
+static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
+ const struct i2c_client *client)
+{
+ while (id->name[0]) {
+ if (strcmp(client->name, id->name) == 0)
+ return id;
+ id++;
+ }
+ return NULL;
+}
+
static int i2c_device_match(struct device *dev, struct device_driver *drv)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -59,6 +70,10 @@
if (!is_newstyle_driver(driver))
return 0;
+ /* match on an id table if there is one */
+ if (driver->id_table)
+ return i2c_match_id(driver->id_table, client) != NULL;
+
/* new style drivers use the same kind of driver matching policy
* as platform devices or SPI: compare device and driver IDs.
*/
@@ -73,11 +88,17 @@
struct i2c_client *client = to_i2c_client(dev);
/* by definition, legacy drivers can't hotplug */
- if (dev->driver || !client->driver_name)
+ if (dev->driver)
return 0;
- if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
- return -ENOMEM;
+ if (client->driver_name[0]) {
+ if (add_uevent_var(env, "MODALIAS=%s", client->driver_name))
+ return -ENOMEM;
+ } else {
+ if (add_uevent_var(env, "MODALIAS=%s%s",
+ I2C_MODULE_PREFIX, client->name))
+ return -ENOMEM;
+ }
dev_dbg(dev, "uevent\n");
return 0;
}
@@ -90,13 +111,19 @@
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_driver *driver = to_i2c_driver(dev->driver);
+ const struct i2c_device_id *id;
int status;
if (!driver->probe)
return -ENODEV;
client->driver = driver;
dev_dbg(dev, "probe\n");
- status = driver->probe(client);
+
+ if (driver->id_table)
+ id = i2c_match_id(driver->id_table, client);
+ else
+ id = NULL;
+ status = driver->probe(client, id);
if (status)
client->driver = NULL;
return status;
@@ -179,9 +206,9 @@
static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
- return client->driver_name
+ return client->driver_name[0]
? sprintf(buf, "%s\n", client->driver_name)
- : 0;
+ : sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
}
static struct device_attribute i2c_dev_attrs[] = {
@@ -300,15 +327,21 @@
EXPORT_SYMBOL_GPL(i2c_unregister_device);
-static int dummy_nop(struct i2c_client *client)
+static int dummy_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ return 0;
+}
+
+static int dummy_remove(struct i2c_client *client)
{
return 0;
}
static struct i2c_driver dummy_driver = {
.driver.name = "dummy",
- .probe = dummy_nop,
- .remove = dummy_nop,
+ .probe = dummy_probe,
+ .remove = dummy_remove,
};
/**
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index fe9df38..68e7f19 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -782,7 +782,7 @@
sector_div(frame, queue_hardsect_size(drive->queue) >> SECTOR_BITS);
- memset(rq->cmd, 0, sizeof(rq->cmd));
+ memset(rq->cmd, 0, BLK_MAX_CDB);
rq->cmd[0] = GPCMD_SEEK;
put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]);
@@ -1694,7 +1694,7 @@
long block = (long)rq->hard_sector / (hard_sect >> 9);
unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9);
- memset(rq->cmd, 0, sizeof(rq->cmd));
+ memset(rq->cmd, 0, BLK_MAX_CDB);
if (rq_data_dir(rq) == READ)
rq->cmd[0] = GPCMD_READ_10;
diff --git a/drivers/ide/ide-cd_verbose.c b/drivers/ide/ide-cd_verbose.c
index 6ed7ca0..6490a2d 100644
--- a/drivers/ide/ide-cd_verbose.c
+++ b/drivers/ide/ide-cd_verbose.c
@@ -326,7 +326,7 @@
printk(KERN_ERR " The failed \"%s\" packet command "
"was: \n \"", s);
- for (i = 0; i < sizeof(failed_command->cmd); i++)
+ for (i = 0; i < BLK_MAX_CDB; i++)
printk(KERN_CONT "%02x ", failed_command->cmd[i]);
printk(KERN_CONT "\"\n");
}
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 788783d..6965253 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -1550,8 +1550,7 @@
void ide_init_drive_cmd (struct request *rq)
{
- memset(rq, 0, sizeof(*rq));
- rq->ref_count = 1;
+ blk_rq_init(NULL, rq);
}
EXPORT_SYMBOL(ide_init_drive_cmd);
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 099a0fe..591deda 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -1347,7 +1347,8 @@
(d->host_flags & IDE_HFLAG_FORCE_LEGACY_IRQS))
hwif->irq = port ? 15 : 14;
- hwif->host_flags = d->host_flags;
+ /* ->host_flags may be set by ->init_iops (or even earlier...) */
+ hwif->host_flags |= d->host_flags;
hwif->pio_mask = d->pio_mask;
/* ->set_pio_mode for DTC2278 is currently limited to port 0 */
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 7b2f381..8d6ad81 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -822,6 +822,7 @@
}
static const struct file_operations ide_drivers_operations = {
+ .owner = THIS_MODULE,
.open = ide_drivers_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -830,16 +831,12 @@
void proc_ide_create(void)
{
- struct proc_dir_entry *entry;
-
proc_ide_root = proc_mkdir("ide", NULL);
if (!proc_ide_root)
return;
- entry = create_proc_entry("drivers", 0, proc_ide_root);
- if (entry)
- entry->proc_fops = &ide_drivers_operations;
+ proc_create("drivers", 0, proc_ide_root, &ide_drivers_operations);
}
void proc_ide_destroy(void)
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 54a43b0..1e1f263 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -662,7 +662,7 @@
static void idetape_init_rq(struct request *rq, u8 cmd)
{
- memset(rq, 0, sizeof(*rq));
+ blk_rq_init(NULL, rq);
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->cmd[0] = cmd;
}
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 9a846a0..0c908ca 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -494,8 +494,7 @@
{
struct request rq;
- memset(&rq, 0, sizeof(rq));
- rq.ref_count = 1;
+ blk_rq_init(NULL, &rq);
rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
rq.buffer = buf;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 999584c..c758dcb 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -564,7 +564,7 @@
if (!(drive->dn % 2))
ide_acpi_get_timing(hwif);
- memset(&rq, 0, sizeof(rq));
+ blk_rq_init(NULL, &rq);
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
rq.cmd_type = REQ_TYPE_PM_SUSPEND;
@@ -602,7 +602,7 @@
ide_acpi_exec_tfs(drive);
- memset(&rq, 0, sizeof(rq));
+ blk_rq_init(NULL, &rq);
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
rq.cmd_type = REQ_TYPE_PM_RESUME;
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index b36a22b..c1922f9 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -412,14 +412,14 @@
return cbl;
}
-#ifndef CONFIG_SPARC64
+#if !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC)
/**
* init_hwif_ali15x3 - Initialize the ALI IDE x86 stuff
* @hwif: interface to configure
*
* Obtain the IRQ tables for an ALi based IDE solution on the PC
* class platforms. This part of the code isn't applicable to the
- * Sparc systems
+ * Sparc and PowerPC systems.
*/
static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
@@ -463,7 +463,9 @@
hwif->irq = irq;
}
}
-#endif
+#else
+#define init_hwif_ali15x3 NULL
+#endif /* !defined(CONFIG_SPARC64) && !defined(CONFIG_PPC) */
/**
* init_dma_ali15x3 - set up DMA on ALi15x3
@@ -517,9 +519,7 @@
static const struct ide_port_info ali15x3_chipset __devinitdata = {
.name = "ALI15X3",
.init_chipset = init_chipset_ali15x3,
-#ifndef CONFIG_SPARC64
.init_hwif = init_hwif_ali15x3,
-#endif
.init_dma = init_dma_ali15x3,
.port_ops = &ali_port_ops,
.pio_mask = ATA_PIO5,
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 4cf8fc5..0006b9e 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -737,8 +737,15 @@
.cable_detect = sil_cable_detect,
};
-static struct ide_dma_ops sil_dma_ops = {
+static const struct ide_dma_ops sil_dma_ops = {
+ .dma_host_set = ide_dma_host_set,
+ .dma_setup = ide_dma_setup,
+ .dma_exec_cmd = ide_dma_exec_cmd,
+ .dma_start = ide_dma_start,
+ .dma_end = __ide_dma_end,
.dma_test_irq = siimage_dma_test_irq,
+ .dma_timeout = ide_dma_timeout,
+ .dma_lost_irq = ide_dma_lost_irq,
};
#define DECLARE_SII_DEV(name_str, p_ops) \
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 29d833e..05710c7 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -520,8 +520,11 @@
char *scratch = buf;
driver = container_of(drv, struct hpsb_protocol_driver, driver);
+ id = driver->id_table;
+ if (!id)
+ return 0;
- for (id = driver->id_table; id->match_flags != 0; id++) {
+ for (; id->match_flags != 0; id++) {
int need_coma = 0;
if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
index 4e3128f..fe78f7d 100644
--- a/drivers/infiniband/core/umem.c
+++ b/drivers/infiniband/core/umem.c
@@ -38,6 +38,7 @@
#include <linux/dma-mapping.h>
#include <linux/sched.h>
#include <linux/hugetlb.h>
+#include <linux/dma-attrs.h>
#include "uverbs.h"
@@ -72,9 +73,10 @@
* @addr: userspace virtual address to start at
* @size: length of region to pin
* @access: IB_ACCESS_xxx flags for memory being pinned
+ * @dmasync: flush in-flight DMA when the memory region is written
*/
struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
- size_t size, int access)
+ size_t size, int access, int dmasync)
{
struct ib_umem *umem;
struct page **page_list;
@@ -87,6 +89,10 @@
int ret;
int off;
int i;
+ DEFINE_DMA_ATTRS(attrs);
+
+ if (dmasync)
+ dma_set_attr(DMA_ATTR_WRITE_BARRIER, &attrs);
if (!can_do_mlock())
return ERR_PTR(-EPERM);
@@ -174,10 +180,11 @@
sg_set_page(&chunk->page_list[i], page_list[i + off], PAGE_SIZE, 0);
}
- chunk->nmap = ib_dma_map_sg(context->device,
- &chunk->page_list[0],
- chunk->nents,
- DMA_BIDIRECTIONAL);
+ chunk->nmap = ib_dma_map_sg_attrs(context->device,
+ &chunk->page_list[0],
+ chunk->nents,
+ DMA_BIDIRECTIONAL,
+ &attrs);
if (chunk->nmap <= 0) {
for (i = 0; i < chunk->nents; ++i)
put_page(sg_page(&chunk->page_list[i]));
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index 6af2c0f..2acf9b6 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -452,7 +452,7 @@
return ERR_PTR(-ENOMEM);
c2mr->pd = c2pd;
- c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+ c2mr->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
if (IS_ERR(c2mr->umem)) {
err = PTR_ERR(c2mr->umem);
kfree(c2mr);
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 66eb703..ed2ee4b 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -456,7 +456,8 @@
ptr = cq->sw_rptr;
while (!Q_EMPTY(ptr, cq->sw_wptr)) {
cqe = cq->sw_queue + (Q_PTR2IDX(ptr, cq->size_log2));
- if ((SQ_TYPE(*cqe) || (CQE_OPCODE(*cqe) == T3_READ_RESP)) &&
+ if ((SQ_TYPE(*cqe) ||
+ ((CQE_OPCODE(*cqe) == T3_READ_RESP) && wq->oldest_read)) &&
(CQE_QPID(*cqe) == wq->qpid))
(*count)++;
ptr++;
@@ -829,7 +830,8 @@
wqe->mpaattrs = attr->mpaattrs;
wqe->qpcaps = attr->qpcaps;
wqe->ulpdu_size = cpu_to_be16(attr->tcp_emss);
- wqe->flags = cpu_to_be32(attr->flags);
+ wqe->rqe_count = cpu_to_be16(attr->rqe_count);
+ wqe->flags_rtr_type = cpu_to_be16(attr->flags|V_RTR_TYPE(attr->rtr_type));
wqe->ord = cpu_to_be32(attr->ord);
wqe->ird = cpu_to_be32(attr->ird);
wqe->qp_dma_addr = cpu_to_be64(attr->qp_dma_addr);
@@ -1135,6 +1137,18 @@
if (RQ_TYPE(*hw_cqe) && (CQE_OPCODE(*hw_cqe) == T3_READ_RESP)) {
/*
+ * If this is an unsolicited read response, then the read
+ * was generated by the kernel driver as part of peer-2-peer
+ * connection setup. So ignore the completion.
+ */
+ if (!wq->oldest_read) {
+ if (CQE_STATUS(*hw_cqe))
+ wq->error = 1;
+ ret = -1;
+ goto skip_cqe;
+ }
+
+ /*
* Don't write to the HWCQ, so create a new read req CQE
* in local memory.
*/
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h
index 99543d6..2bcff7f 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h
@@ -53,6 +53,7 @@
#define T3_MAX_PBL_SIZE 256
#define T3_MAX_RQ_SIZE 1024
#define T3_MAX_NUM_STAG (1<<15)
+#define T3_MAX_MR_SIZE 0x100000000ULL
#define T3_STAG_UNSET 0xffffffff
diff --git a/drivers/infiniband/hw/cxgb3/cxio_wr.h b/drivers/infiniband/hw/cxgb3/cxio_wr.h
index 969d4d9..f1a25a8 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_wr.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_wr.h
@@ -278,6 +278,17 @@
uP_RI_QP_STAG0_ENABLE = 0x10
} __attribute__ ((packed));
+enum rdma_init_rtr_types {
+ RTR_READ = 1,
+ RTR_WRITE = 2,
+ RTR_SEND = 3,
+};
+
+#define S_RTR_TYPE 2
+#define M_RTR_TYPE 0x3
+#define V_RTR_TYPE(x) ((x) << S_RTR_TYPE)
+#define G_RTR_TYPE(x) ((((x) >> S_RTR_TYPE)) & M_RTR_TYPE)
+
struct t3_rdma_init_attr {
u32 tid;
u32 qpid;
@@ -293,7 +304,9 @@
u32 ird;
u64 qp_dma_addr;
u32 qp_dma_size;
- u32 flags;
+ enum rdma_init_rtr_types rtr_type;
+ u16 flags;
+ u16 rqe_count;
u32 irs;
};
@@ -309,8 +322,8 @@
u8 mpaattrs; /* 5 */
u8 qpcaps;
__be16 ulpdu_size;
- __be32 flags; /* bits 31-1 - reservered */
- /* bit 0 - set if RECV posted */
+ __be16 flags_rtr_type;
+ __be16 rqe_count;
__be32 ord; /* 6 */
__be32 ird;
__be64 qp_dma_addr; /* 7 */
@@ -324,7 +337,7 @@
};
enum rdma_init_wr_flags {
- RECVS_POSTED = (1<<0),
+ MPA_INITIATOR = (1<<0),
PRIV_QP = (1<<1),
};
diff --git a/drivers/infiniband/hw/cxgb3/iwch.c b/drivers/infiniband/hw/cxgb3/iwch.c
index 6ba4138..71554ea 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.c
+++ b/drivers/infiniband/hw/cxgb3/iwch.c
@@ -83,6 +83,7 @@
rnicp->attr.max_phys_buf_entries = T3_MAX_PBL_SIZE;
rnicp->attr.max_pds = T3_MAX_NUM_PD - 1;
rnicp->attr.mem_pgsizes_bitmask = 0x7FFF; /* 4KB-128MB */
+ rnicp->attr.max_mr_size = T3_MAX_MR_SIZE;
rnicp->attr.can_resize_wq = 0;
rnicp->attr.max_rdma_reads_per_qp = 8;
rnicp->attr.max_rdma_read_resources =
diff --git a/drivers/infiniband/hw/cxgb3/iwch.h b/drivers/infiniband/hw/cxgb3/iwch.h
index 9ad9b1e..d2409a5 100644
--- a/drivers/infiniband/hw/cxgb3/iwch.h
+++ b/drivers/infiniband/hw/cxgb3/iwch.h
@@ -66,6 +66,7 @@
* size (4k)^i. Phys block list mode unsupported.
*/
u32 mem_pgsizes_bitmask;
+ u64 max_mr_size;
u8 can_resize_wq;
/*
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.c b/drivers/infiniband/hw/cxgb3/iwch_cm.c
index 72ca360..d44a6df 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
@@ -63,6 +63,10 @@
NULL,
};
+int peer2peer = 0;
+module_param(peer2peer, int, 0644);
+MODULE_PARM_DESC(peer2peer, "Support peer2peer ULPs (default=0)");
+
static int ep_timeout_secs = 10;
module_param(ep_timeout_secs, int, 0644);
MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout "
@@ -125,6 +129,12 @@
static void stop_ep_timer(struct iwch_ep *ep)
{
PDBG("%s ep %p\n", __func__, ep);
+ if (!timer_pending(&ep->timer)) {
+ printk(KERN_ERR "%s timer stopped when its not running! ep %p state %u\n",
+ __func__, ep, ep->com.state);
+ WARN_ON(1);
+ return;
+ }
del_timer_sync(&ep->timer);
put_ep(&ep->com);
}
@@ -508,7 +518,7 @@
skb_reset_transport_header(skb);
len = skb->len;
req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
- req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL);
req->wr_lo = htonl(V_WR_TID(ep->hwtid));
req->len = htonl(len);
req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
@@ -559,7 +569,7 @@
set_arp_failure_handler(skb, arp_failure_discard);
skb_reset_transport_header(skb);
req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
- req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL);
req->wr_lo = htonl(V_WR_TID(ep->hwtid));
req->len = htonl(mpalen);
req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
@@ -611,7 +621,7 @@
skb_reset_transport_header(skb);
len = skb->len;
req = (struct tx_data_wr *) skb_push(skb, sizeof(*req));
- req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
+ req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA)|F_WR_COMPL);
req->wr_lo = htonl(V_WR_TID(ep->hwtid));
req->len = htonl(len);
req->param = htonl(V_TX_PORT(ep->l2t->smt_idx) |
@@ -879,6 +889,7 @@
* the MPA header is valid.
*/
state_set(&ep->com, FPDU_MODE);
+ ep->mpa_attr.initiator = 1;
ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
ep->mpa_attr.recv_marker_enabled = markers_enabled;
ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
@@ -901,8 +912,14 @@
/* bind QP and TID with INIT_WR */
err = iwch_modify_qp(ep->com.qp->rhp,
ep->com.qp, mask, &attrs, 1);
- if (!err)
- goto out;
+ if (err)
+ goto err;
+
+ if (peer2peer && iwch_rqes_posted(ep->com.qp) == 0) {
+ iwch_post_zb_read(ep->com.qp);
+ }
+
+ goto out;
err:
abort_connection(ep, skb, GFP_KERNEL);
out:
@@ -995,6 +1012,7 @@
* If we get here we have accumulated the entire mpa
* start reply message including private data.
*/
+ ep->mpa_attr.initiator = 0;
ep->mpa_attr.crc_enabled = (mpa->flags & MPA_CRC) | crc_enabled ? 1 : 0;
ep->mpa_attr.recv_marker_enabled = markers_enabled;
ep->mpa_attr.xmit_marker_enabled = mpa->flags & MPA_MARKERS ? 1 : 0;
@@ -1065,17 +1083,33 @@
PDBG("%s ep %p credits %u\n", __func__, ep, credits);
- if (credits == 0)
+ if (credits == 0) {
+ PDBG(KERN_ERR "%s 0 credit ack ep %p state %u\n",
+ __func__, ep, state_read(&ep->com));
return CPL_RET_BUF_DONE;
+ }
+
BUG_ON(credits != 1);
- BUG_ON(ep->mpa_skb == NULL);
- kfree_skb(ep->mpa_skb);
- ep->mpa_skb = NULL;
dst_confirm(ep->dst);
- if (state_read(&ep->com) == MPA_REP_SENT) {
- ep->com.rpl_done = 1;
- PDBG("waking up ep %p\n", ep);
- wake_up(&ep->com.waitq);
+ if (!ep->mpa_skb) {
+ PDBG("%s rdma_init wr_ack ep %p state %u\n",
+ __func__, ep, state_read(&ep->com));
+ if (ep->mpa_attr.initiator) {
+ PDBG("%s initiator ep %p state %u\n",
+ __func__, ep, state_read(&ep->com));
+ if (peer2peer)
+ iwch_post_zb_read(ep->com.qp);
+ } else {
+ PDBG("%s responder ep %p state %u\n",
+ __func__, ep, state_read(&ep->com));
+ ep->com.rpl_done = 1;
+ wake_up(&ep->com.waitq);
+ }
+ } else {
+ PDBG("%s lsm ack ep %p state %u freeing skb\n",
+ __func__, ep, state_read(&ep->com));
+ kfree_skb(ep->mpa_skb);
+ ep->mpa_skb = NULL;
}
return CPL_RET_BUF_DONE;
}
@@ -1083,8 +1117,11 @@
static int abort_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
{
struct iwch_ep *ep = ctx;
+ unsigned long flags;
+ int release = 0;
PDBG("%s ep %p\n", __func__, ep);
+ BUG_ON(!ep);
/*
* We get 2 abort replies from the HW. The first one must
@@ -1095,9 +1132,22 @@
return CPL_RET_BUF_DONE;
}
- close_complete_upcall(ep);
- state_set(&ep->com, DEAD);
- release_ep_resources(ep);
+ spin_lock_irqsave(&ep->com.lock, flags);
+ switch (ep->com.state) {
+ case ABORTING:
+ close_complete_upcall(ep);
+ __state_set(&ep->com, DEAD);
+ release = 1;
+ break;
+ default:
+ printk(KERN_ERR "%s ep %p state %d\n",
+ __func__, ep, ep->com.state);
+ break;
+ }
+ spin_unlock_irqrestore(&ep->com.lock, flags);
+
+ if (release)
+ release_ep_resources(ep);
return CPL_RET_BUF_DONE;
}
@@ -1470,7 +1520,8 @@
struct sk_buff *rpl_skb;
struct iwch_qp_attributes attrs;
int ret;
- int state;
+ int release = 0;
+ unsigned long flags;
if (is_neg_adv_abort(req->status)) {
PDBG("%s neg_adv_abort ep %p tid %d\n", __func__, ep,
@@ -1488,9 +1539,9 @@
return CPL_RET_BUF_DONE;
}
- state = state_read(&ep->com);
- PDBG("%s ep %p state %u\n", __func__, ep, state);
- switch (state) {
+ spin_lock_irqsave(&ep->com.lock, flags);
+ PDBG("%s ep %p state %u\n", __func__, ep, ep->com.state);
+ switch (ep->com.state) {
case CONNECTING:
break;
case MPA_REQ_WAIT:
@@ -1536,21 +1587,25 @@
break;
case DEAD:
PDBG("%s PEER_ABORT IN DEAD STATE!!!!\n", __func__);
+ spin_unlock_irqrestore(&ep->com.lock, flags);
return CPL_RET_BUF_DONE;
default:
BUG_ON(1);
break;
}
dst_confirm(ep->dst);
+ if (ep->com.state != ABORTING) {
+ __state_set(&ep->com, DEAD);
+ release = 1;
+ }
+ spin_unlock_irqrestore(&ep->com.lock, flags);
rpl_skb = get_skb(skb, sizeof(*rpl), GFP_KERNEL);
if (!rpl_skb) {
printk(KERN_ERR MOD "%s - cannot allocate skb!\n",
__func__);
- dst_release(ep->dst);
- l2t_release(L2DATA(ep->com.tdev), ep->l2t);
- put_ep(&ep->com);
- return CPL_RET_BUF_DONE;
+ release = 1;
+ goto out;
}
rpl_skb->priority = CPL_PRIORITY_DATA;
rpl = (struct cpl_abort_rpl *) skb_put(rpl_skb, sizeof(*rpl));
@@ -1559,10 +1614,9 @@
OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, ep->hwtid));
rpl->cmd = CPL_ABORT_NO_RST;
cxgb3_ofld_send(ep->com.tdev, rpl_skb);
- if (state != ABORTING) {
- state_set(&ep->com, DEAD);
+out:
+ if (release)
release_ep_resources(ep);
- }
return CPL_RET_BUF_DONE;
}
@@ -1661,15 +1715,18 @@
struct iwch_ep *ep = (struct iwch_ep *)arg;
struct iwch_qp_attributes attrs;
unsigned long flags;
+ int abort = 1;
spin_lock_irqsave(&ep->com.lock, flags);
PDBG("%s ep %p tid %u state %d\n", __func__, ep, ep->hwtid,
ep->com.state);
switch (ep->com.state) {
case MPA_REQ_SENT:
+ __state_set(&ep->com, ABORTING);
connect_reply_upcall(ep, -ETIMEDOUT);
break;
case MPA_REQ_WAIT:
+ __state_set(&ep->com, ABORTING);
break;
case CLOSING:
case MORIBUND:
@@ -1679,13 +1736,17 @@
ep->com.qp, IWCH_QP_ATTR_NEXT_STATE,
&attrs, 1);
}
+ __state_set(&ep->com, ABORTING);
break;
default:
- BUG();
+ printk(KERN_ERR "%s unexpected state ep %p state %u\n",
+ __func__, ep, ep->com.state);
+ WARN_ON(1);
+ abort = 0;
}
- __state_set(&ep->com, CLOSING);
spin_unlock_irqrestore(&ep->com.lock, flags);
- abort_connection(ep, NULL, GFP_ATOMIC);
+ if (abort)
+ abort_connection(ep, NULL, GFP_ATOMIC);
put_ep(&ep->com);
}
@@ -1762,16 +1823,19 @@
if (err)
goto err;
+ /* if needed, wait for wr_ack */
+ if (iwch_rqes_posted(qp)) {
+ wait_event(ep->com.waitq, ep->com.rpl_done);
+ err = ep->com.rpl_err;
+ if (err)
+ goto err;
+ }
+
err = send_mpa_reply(ep, conn_param->private_data,
conn_param->private_data_len);
if (err)
goto err;
- /* wait for wr_ack */
- wait_event(ep->com.waitq, ep->com.rpl_done);
- err = ep->com.rpl_err;
- if (err)
- goto err;
state_set(&ep->com, FPDU_MODE);
established_upcall(ep);
@@ -1968,40 +2032,39 @@
PDBG("%s ep %p state %s, abrupt %d\n", __func__, ep,
states[ep->com.state], abrupt);
- if (ep->com.state == DEAD) {
- PDBG("%s already dead ep %p\n", __func__, ep);
- goto out;
- }
-
- if (abrupt) {
- if (ep->com.state != ABORTING) {
- ep->com.state = ABORTING;
- close = 1;
- }
- goto out;
- }
-
switch (ep->com.state) {
case MPA_REQ_WAIT:
case MPA_REQ_SENT:
case MPA_REQ_RCVD:
case MPA_REP_SENT:
case FPDU_MODE:
- start_ep_timer(ep);
- ep->com.state = CLOSING;
close = 1;
+ if (abrupt)
+ ep->com.state = ABORTING;
+ else {
+ ep->com.state = CLOSING;
+ start_ep_timer(ep);
+ }
break;
case CLOSING:
- ep->com.state = MORIBUND;
close = 1;
+ if (abrupt) {
+ stop_ep_timer(ep);
+ ep->com.state = ABORTING;
+ } else
+ ep->com.state = MORIBUND;
break;
case MORIBUND:
+ case ABORTING:
+ case DEAD:
+ PDBG("%s ignoring disconnect ep %p state %u\n",
+ __func__, ep, ep->com.state);
break;
default:
BUG();
break;
}
-out:
+
spin_unlock_irqrestore(&ep->com.lock, flags);
if (close) {
if (abrupt)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_cm.h b/drivers/infiniband/hw/cxgb3/iwch_cm.h
index 2bb7fbd..d7c7e09 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_cm.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.h
@@ -56,6 +56,7 @@
#define put_ep(ep) { \
PDBG("put_ep (via %s:%u) ep %p refcnt %d\n", __func__, __LINE__, \
ep, atomic_read(&((ep)->kref.refcount))); \
+ WARN_ON(atomic_read(&((ep)->kref.refcount)) < 1); \
kref_put(&((ep)->kref), __free_ep); \
}
@@ -225,5 +226,6 @@
int __init iwch_cm_init(void);
void __exit iwch_cm_term(void);
+extern int peer2peer;
#endif /* _IWCH_CM_H_ */
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index ab4695c..d07d3a3 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -602,7 +602,7 @@
if (!mhp)
return ERR_PTR(-ENOMEM);
- mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+ mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
if (IS_ERR(mhp->umem)) {
err = PTR_ERR(mhp->umem);
kfree(mhp);
@@ -998,7 +998,7 @@
props->device_cap_flags = dev->device_cap_flags;
props->vendor_id = (u32)dev->rdev.rnic_info.pdev->vendor;
props->vendor_part_id = (u32)dev->rdev.rnic_info.pdev->device;
- props->max_mr_size = ~0ull;
+ props->max_mr_size = dev->attr.max_mr_size;
props->max_qp = dev->attr.max_qps;
props->max_qp_wr = dev->attr.max_wrs;
props->max_sge = dev->attr.max_sge_per_wr;
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h
index 61356f9..db5100d 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h
@@ -118,6 +118,7 @@
};
struct iwch_mpa_attributes {
+ u8 initiator;
u8 recv_marker_enabled;
u8 xmit_marker_enabled; /* iWARP: enable inbound Read Resp. */
u8 crc_enabled;
@@ -322,6 +323,7 @@
IWCH_QP_QUERY_TEST_USERWRITE = 0x32 /* Test special */
};
+u16 iwch_rqes_posted(struct iwch_qp *qhp);
int iwch_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
struct ib_send_wr **bad_wr);
int iwch_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr,
@@ -331,6 +333,7 @@
struct ib_mw_bind *mw_bind);
int iwch_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc);
int iwch_post_terminate(struct iwch_qp *qhp, struct respQ_msg_t *rsp_msg);
+int iwch_post_zb_read(struct iwch_qp *qhp);
int iwch_register_device(struct iwch_dev *dev);
void iwch_unregister_device(struct iwch_dev *dev);
int iwch_quiesce_qps(struct iwch_cq *chp);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_qp.c b/drivers/infiniband/hw/cxgb3/iwch_qp.c
index 8891c3b..9b4be88 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_qp.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_qp.c
@@ -586,6 +586,36 @@
}
}
+int iwch_post_zb_read(struct iwch_qp *qhp)
+{
+ union t3_wr *wqe;
+ struct sk_buff *skb;
+ u8 flit_cnt = sizeof(struct t3_rdma_read_wr) >> 3;
+
+ PDBG("%s enter\n", __func__);
+ skb = alloc_skb(40, GFP_KERNEL);
+ if (!skb) {
+ printk(KERN_ERR "%s cannot send zb_read!!\n", __func__);
+ return -ENOMEM;
+ }
+ wqe = (union t3_wr *)skb_put(skb, sizeof(struct t3_rdma_read_wr));
+ memset(wqe, 0, sizeof(struct t3_rdma_read_wr));
+ wqe->read.rdmaop = T3_READ_REQ;
+ wqe->read.reserved[0] = 0;
+ wqe->read.reserved[1] = 0;
+ wqe->read.reserved[2] = 0;
+ wqe->read.rem_stag = cpu_to_be32(1);
+ wqe->read.rem_to = cpu_to_be64(1);
+ wqe->read.local_stag = cpu_to_be32(1);
+ wqe->read.local_len = cpu_to_be32(0);
+ wqe->read.local_to = cpu_to_be64(1);
+ wqe->send.wrh.op_seop_flags = cpu_to_be32(V_FW_RIWR_OP(T3_WR_READ));
+ wqe->send.wrh.gen_tid_len = cpu_to_be32(V_FW_RIWR_TID(qhp->ep->hwtid)|
+ V_FW_RIWR_LEN(flit_cnt));
+ skb->priority = CPL_PRIORITY_DATA;
+ return cxgb3_ofld_send(qhp->rhp->rdev.t3cdev_p, skb);
+}
+
/*
* This posts a TERMINATE with layer=RDMA, type=catastrophic.
*/
@@ -671,11 +701,18 @@
/*
- * Return non zero if at least one RECV was pre-posted.
+ * Return count of RECV WRs posted
*/
-static int rqes_posted(struct iwch_qp *qhp)
+u16 iwch_rqes_posted(struct iwch_qp *qhp)
{
- return fw_riwrh_opcode((struct fw_riwrh *)qhp->wq.queue) == T3_WR_RCV;
+ union t3_wr *wqe = qhp->wq.queue;
+ u16 count = 0;
+ while ((count+1) != 0 && fw_riwrh_opcode((struct fw_riwrh *)wqe) == T3_WR_RCV) {
+ count++;
+ wqe++;
+ }
+ PDBG("%s qhp %p count %u\n", __func__, qhp, count);
+ return count;
}
static int rdma_init(struct iwch_dev *rhp, struct iwch_qp *qhp,
@@ -716,8 +753,17 @@
init_attr.ird = qhp->attr.max_ird;
init_attr.qp_dma_addr = qhp->wq.dma_addr;
init_attr.qp_dma_size = (1UL << qhp->wq.size_log2);
- init_attr.flags = rqes_posted(qhp) ? RECVS_POSTED : 0;
+ init_attr.rqe_count = iwch_rqes_posted(qhp);
+ init_attr.flags = qhp->attr.mpa_attr.initiator ? MPA_INITIATOR : 0;
init_attr.flags |= capable(CAP_NET_BIND_SERVICE) ? PRIV_QP : 0;
+ if (peer2peer) {
+ init_attr.rtr_type = RTR_READ;
+ if (init_attr.ord == 0 && qhp->attr.mpa_attr.initiator)
+ init_attr.ord = 1;
+ if (init_attr.ird == 0 && !qhp->attr.mpa_attr.initiator)
+ init_attr.ird = 1;
+ } else
+ init_attr.rtr_type = 0;
init_attr.irs = qhp->ep->rcv_seq;
PDBG("%s init_attr.rq_addr 0x%x init_attr.rq_size = %d "
"flags 0x%x qpcaps 0x%x\n", __func__,
@@ -832,6 +878,7 @@
abort=0;
disconnect = 1;
ep = qhp->ep;
+ get_ep(&ep->com);
}
flush_qp(qhp, &flag);
break;
@@ -848,6 +895,7 @@
abort=1;
disconnect = 1;
ep = qhp->ep;
+ get_ep(&ep->com);
}
goto err;
break;
@@ -929,8 +977,10 @@
* on the EP. This can be a normal close (RTS->CLOSING) or
* an abnormal close (RTS/CLOSING->ERROR).
*/
- if (disconnect)
+ if (disconnect) {
iwch_ep_disconnect(ep, abort, GFP_KERNEL);
+ put_ep(&ep->com);
+ }
/*
* If free is 1, then we've disassociated the EP from the QP
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 3d6d9461..00bab60 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -66,6 +66,7 @@
#include "ehca_irq.h"
#define EHCA_EQE_CACHE_SIZE 20
+#define EHCA_MAX_NUM_QUEUES 0xffff
struct ehca_eqe_cache_entry {
struct ehca_eqe *eqe;
@@ -127,6 +128,8 @@
/* MR pgsize: bit 0-3 means 4K, 64K, 1M, 16M respectively */
u32 hca_cap_mr_pgsize;
int max_mtu;
+ atomic_t num_cqs;
+ atomic_t num_qps;
};
struct ehca_pd {
@@ -344,6 +347,8 @@
extern int ehca_scaling_code;
extern int ehca_lock_hcalls;
extern int ehca_nr_ports;
+extern int ehca_max_cq;
+extern int ehca_max_qp;
struct ipzu_queue_resp {
u32 qe_size; /* queue entry size */
diff --git a/drivers/infiniband/hw/ehca/ehca_cq.c b/drivers/infiniband/hw/ehca/ehca_cq.c
index ec0cfcf..5540b27 100644
--- a/drivers/infiniband/hw/ehca/ehca_cq.c
+++ b/drivers/infiniband/hw/ehca/ehca_cq.c
@@ -132,10 +132,19 @@
if (cqe >= 0xFFFFFFFF - 64 - additional_cqe)
return ERR_PTR(-EINVAL);
+ if (!atomic_add_unless(&shca->num_cqs, 1, ehca_max_cq)) {
+ ehca_err(device, "Unable to create CQ, max number of %i "
+ "CQs reached.", ehca_max_cq);
+ ehca_err(device, "To increase the maximum number of CQs "
+ "use the number_of_cqs module parameter.\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
my_cq = kmem_cache_zalloc(cq_cache, GFP_KERNEL);
if (!my_cq) {
ehca_err(device, "Out of memory for ehca_cq struct device=%p",
device);
+ atomic_dec(&shca->num_cqs);
return ERR_PTR(-ENOMEM);
}
@@ -305,6 +314,7 @@
create_cq_exit1:
kmem_cache_free(cq_cache, my_cq);
+ atomic_dec(&shca->num_cqs);
return cq;
}
@@ -359,6 +369,7 @@
ipz_queue_dtor(NULL, &my_cq->ipz_queue);
kmem_cache_free(cq_cache, my_cq);
+ atomic_dec(&shca->num_cqs);
return 0;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_eq.c b/drivers/infiniband/hw/ehca/ehca_eq.c
index b4ac617..49660df 100644
--- a/drivers/infiniband/hw/ehca/ehca_eq.c
+++ b/drivers/infiniband/hw/ehca/ehca_eq.c
@@ -54,7 +54,8 @@
struct ehca_eq *eq,
const enum ehca_eq_type type, const u32 length)
{
- u64 ret;
+ int ret;
+ u64 h_ret;
u32 nr_pages;
u32 i;
void *vpage;
@@ -73,15 +74,15 @@
return -EINVAL;
}
- ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle,
- &eq->pf,
- type,
- length,
- &eq->ipz_eq_handle,
- &eq->length,
- &nr_pages, &eq->ist);
+ h_ret = hipz_h_alloc_resource_eq(shca->ipz_hca_handle,
+ &eq->pf,
+ type,
+ length,
+ &eq->ipz_eq_handle,
+ &eq->length,
+ &nr_pages, &eq->ist);
- if (ret != H_SUCCESS) {
+ if (h_ret != H_SUCCESS) {
ehca_err(ib_dev, "Can't allocate EQ/NEQ. eq=%p", eq);
return -EINVAL;
}
@@ -97,24 +98,22 @@
u64 rpage;
vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
- if (!vpage) {
- ret = H_RESOURCE;
+ if (!vpage)
goto create_eq_exit2;
- }
rpage = virt_to_abs(vpage);
- ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle,
- eq->ipz_eq_handle,
- &eq->pf,
- 0, 0, rpage, 1);
+ h_ret = hipz_h_register_rpage_eq(shca->ipz_hca_handle,
+ eq->ipz_eq_handle,
+ &eq->pf,
+ 0, 0, rpage, 1);
if (i == (nr_pages - 1)) {
/* last page */
vpage = ipz_qpageit_get_inc(&eq->ipz_queue);
- if (ret != H_SUCCESS || vpage)
+ if (h_ret != H_SUCCESS || vpage)
goto create_eq_exit2;
} else {
- if (ret != H_PAGE_REGISTERED || !vpage)
+ if (h_ret != H_PAGE_REGISTERED || !vpage)
goto create_eq_exit2;
}
}
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 6504897..482103e 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -68,6 +68,8 @@
int ehca_static_rate = -1;
int ehca_scaling_code = 0;
int ehca_lock_hcalls = -1;
+int ehca_max_cq = -1;
+int ehca_max_qp = -1;
module_param_named(open_aqp1, ehca_open_aqp1, bool, S_IRUGO);
module_param_named(debug_level, ehca_debug_level, int, S_IRUGO);
@@ -79,6 +81,8 @@
module_param_named(static_rate, ehca_static_rate, int, S_IRUGO);
module_param_named(scaling_code, ehca_scaling_code, bool, S_IRUGO);
module_param_named(lock_hcalls, ehca_lock_hcalls, bool, S_IRUGO);
+module_param_named(number_of_cqs, ehca_max_cq, int, S_IRUGO);
+module_param_named(number_of_qps, ehca_max_qp, int, S_IRUGO);
MODULE_PARM_DESC(open_aqp1,
"Open AQP1 on startup (default: no)");
@@ -104,6 +108,12 @@
MODULE_PARM_DESC(lock_hcalls,
"Serialize all hCalls made by the driver "
"(default: autodetect)");
+MODULE_PARM_DESC(number_of_cqs,
+ "Max number of CQs which can be allocated "
+ "(default: autodetect)");
+MODULE_PARM_DESC(number_of_qps,
+ "Max number of QPs which can be allocated "
+ "(default: autodetect)");
DEFINE_RWLOCK(ehca_qp_idr_lock);
DEFINE_RWLOCK(ehca_cq_idr_lock);
@@ -355,6 +365,25 @@
if (rblock->memory_page_size_supported & pgsize_map[i])
shca->hca_cap_mr_pgsize |= pgsize_map[i + 1];
+ /* Set maximum number of CQs and QPs to calculate EQ size */
+ if (ehca_max_qp == -1)
+ ehca_max_qp = min_t(int, rblock->max_qp, EHCA_MAX_NUM_QUEUES);
+ else if (ehca_max_qp < 1 || ehca_max_qp > rblock->max_qp) {
+ ehca_gen_err("Requested number of QPs is out of range (1 - %i) "
+ "specified by HW", rblock->max_qp);
+ ret = -EINVAL;
+ goto sense_attributes1;
+ }
+
+ if (ehca_max_cq == -1)
+ ehca_max_cq = min_t(int, rblock->max_cq, EHCA_MAX_NUM_QUEUES);
+ else if (ehca_max_cq < 1 || ehca_max_cq > rblock->max_cq) {
+ ehca_gen_err("Requested number of CQs is out of range (1 - %i) "
+ "specified by HW", rblock->max_cq);
+ ret = -EINVAL;
+ goto sense_attributes1;
+ }
+
/* query max MTU from first port -- it's the same for all ports */
port = (struct hipz_query_port *)rblock;
h_ret = hipz_h_query_port(shca->ipz_hca_handle, 1, port);
@@ -684,7 +713,7 @@
struct ehca_shca *shca;
const u64 *handle;
struct ib_pd *ibpd;
- int ret, i;
+ int ret, i, eq_size;
handle = of_get_property(dev->node, "ibm,hca-handle", NULL);
if (!handle) {
@@ -705,6 +734,8 @@
return -ENOMEM;
}
mutex_init(&shca->modify_mutex);
+ atomic_set(&shca->num_cqs, 0);
+ atomic_set(&shca->num_qps, 0);
for (i = 0; i < ARRAY_SIZE(shca->sport); i++)
spin_lock_init(&shca->sport[i].mod_sqp_lock);
@@ -724,8 +755,9 @@
goto probe1;
}
+ eq_size = 2 * ehca_max_cq + 4 * ehca_max_qp;
/* create event queues */
- ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048);
+ ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, eq_size);
if (ret) {
ehca_err(&shca->ib_device, "Cannot create EQ.");
goto probe1;
diff --git a/drivers/infiniband/hw/ehca/ehca_mrmw.c b/drivers/infiniband/hw/ehca/ehca_mrmw.c
index 46ae4eb..f974367 100644
--- a/drivers/infiniband/hw/ehca/ehca_mrmw.c
+++ b/drivers/infiniband/hw/ehca/ehca_mrmw.c
@@ -323,7 +323,7 @@
}
e_mr->umem = ib_umem_get(pd->uobject->context, start, length,
- mr_access_flags);
+ mr_access_flags, 0);
if (IS_ERR(e_mr->umem)) {
ib_mr = (void *)e_mr->umem;
goto reg_user_mr_exit1;
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 57bef11..18fba92 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -421,8 +421,18 @@
u32 swqe_size = 0, rwqe_size = 0, ib_qp_num;
unsigned long flags;
- if (init_attr->create_flags)
+ if (!atomic_add_unless(&shca->num_qps, 1, ehca_max_qp)) {
+ ehca_err(pd->device, "Unable to create QP, max number of %i "
+ "QPs reached.", ehca_max_qp);
+ ehca_err(pd->device, "To increase the maximum number of QPs "
+ "use the number_of_qps module parameter.\n");
+ return ERR_PTR(-ENOSPC);
+ }
+
+ if (init_attr->create_flags) {
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
+ }
memset(&parms, 0, sizeof(parms));
qp_type = init_attr->qp_type;
@@ -431,6 +441,7 @@
init_attr->sq_sig_type != IB_SIGNAL_ALL_WR) {
ehca_err(pd->device, "init_attr->sg_sig_type=%x not allowed",
init_attr->sq_sig_type);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
@@ -455,6 +466,7 @@
if (is_llqp && has_srq) {
ehca_err(pd->device, "LLQPs can't have an SRQ");
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
@@ -466,6 +478,7 @@
ehca_err(pd->device, "no more than three SGEs "
"supported for SRQ pd=%p max_sge=%x",
pd, init_attr->cap.max_recv_sge);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
}
@@ -477,6 +490,7 @@
qp_type != IB_QPT_SMI &&
qp_type != IB_QPT_GSI) {
ehca_err(pd->device, "wrong QP Type=%x", qp_type);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
@@ -490,6 +504,7 @@
"or max_rq_wr=%x for RC LLQP",
init_attr->cap.max_send_wr,
init_attr->cap.max_recv_wr);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
break;
@@ -497,6 +512,7 @@
if (!EHCA_BMASK_GET(HCA_CAP_UD_LL_QP, shca->hca_cap)) {
ehca_err(pd->device, "UD LLQP not supported "
"by this adapter");
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-ENOSYS);
}
if (!(init_attr->cap.max_send_sge <= 5
@@ -508,20 +524,22 @@
"or max_recv_sge=%x for UD LLQP",
init_attr->cap.max_send_sge,
init_attr->cap.max_recv_sge);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
} else if (init_attr->cap.max_send_wr > 255) {
ehca_err(pd->device,
"Invalid Number of "
"max_send_wr=%x for UD QP_TYPE=%x",
init_attr->cap.max_send_wr, qp_type);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
break;
default:
ehca_err(pd->device, "unsupported LL QP Type=%x",
qp_type);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
- break;
}
} else {
int max_sge = (qp_type == IB_QPT_UD || qp_type == IB_QPT_SMI
@@ -533,6 +551,7 @@
"send_sge=%x recv_sge=%x max_sge=%x",
init_attr->cap.max_send_sge,
init_attr->cap.max_recv_sge, max_sge);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-EINVAL);
}
}
@@ -543,6 +562,7 @@
my_qp = kmem_cache_zalloc(qp_cache, GFP_KERNEL);
if (!my_qp) {
ehca_err(pd->device, "pd=%p not enough memory to alloc qp", pd);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(-ENOMEM);
}
@@ -823,6 +843,7 @@
create_qp_exit0:
kmem_cache_free(qp_cache, my_qp);
+ atomic_dec(&shca->num_qps);
return ERR_PTR(ret);
}
@@ -1948,6 +1969,7 @@
if (HAS_SQ(my_qp))
ipz_queue_dtor(my_pd, &my_qp->ipz_squeue);
kmem_cache_free(qp_cache, my_qp);
+ atomic_dec(&shca->num_qps);
return 0;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
index db4ba92..9d343b7 100644
--- a/drivers/infiniband/hw/ipath/ipath_mr.c
+++ b/drivers/infiniband/hw/ipath/ipath_mr.c
@@ -195,7 +195,8 @@
goto bail;
}
- umem = ib_umem_get(pd->uobject->context, start, length, mr_access_flags);
+ umem = ib_umem_get(pd->uobject->context, start, length,
+ mr_access_flags, 0);
if (IS_ERR(umem))
return (void *) umem;
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index 5e570bb..2f199c5 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -137,7 +137,7 @@
int err;
*umem = ib_umem_get(context, buf_addr, cqe * sizeof (struct mlx4_cqe),
- IB_ACCESS_LOCAL_WRITE);
+ IB_ACCESS_LOCAL_WRITE, 1);
if (IS_ERR(*umem))
return PTR_ERR(*umem);
@@ -221,7 +221,7 @@
}
err = mlx4_cq_alloc(dev->dev, entries, &cq->buf.mtt, uar,
- cq->db.dma, &cq->mcq);
+ cq->db.dma, &cq->mcq, 0);
if (err)
goto err_dbmap;
diff --git a/drivers/infiniband/hw/mlx4/doorbell.c b/drivers/infiniband/hw/mlx4/doorbell.c
index 8e342cc..8aee423 100644
--- a/drivers/infiniband/hw/mlx4/doorbell.c
+++ b/drivers/infiniband/hw/mlx4/doorbell.c
@@ -63,7 +63,7 @@
page->user_virt = (virt & PAGE_MASK);
page->refcnt = 0;
page->umem = ib_umem_get(&context->ibucontext, virt & PAGE_MASK,
- PAGE_SIZE, 0);
+ PAGE_SIZE, 0, 0);
if (IS_ERR(page->umem)) {
err = PTR_ERR(page->umem);
kfree(page);
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index fe2c2e9..68e9248 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -132,7 +132,8 @@
if (!mr)
return ERR_PTR(-ENOMEM);
- mr->umem = ib_umem_get(pd->uobject->context, start, length, access_flags);
+ mr->umem = ib_umem_get(pd->uobject->context, start, length,
+ access_flags, 0);
if (IS_ERR(mr->umem)) {
err = PTR_ERR(mr->umem);
goto err_free;
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index 80ea8b9..8e02ecf 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -482,7 +482,7 @@
goto err;
qp->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
- qp->buf_size, 0);
+ qp->buf_size, 0, 0);
if (IS_ERR(qp->umem)) {
err = PTR_ERR(qp->umem);
goto err;
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 2046197..12d6bc6 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -109,7 +109,7 @@
}
srq->umem = ib_umem_get(pd->uobject->context, ucmd.buf_addr,
- buf_size, 0);
+ buf_size, 0, 0);
if (IS_ERR(srq->umem)) {
err = PTR_ERR(srq->umem);
goto err_srq;
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 3538da1..820205d 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -818,15 +818,9 @@
void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
{
- u32 key;
-
if (!fmr->maps)
return;
- key = tavor_key_to_hw_index(fmr->ibmr.lkey);
- key &= dev->limits.num_mpts - 1;
- fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key);
-
fmr->maps = 0;
writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt);
@@ -834,16 +828,9 @@
void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr)
{
- u32 key;
-
if (!fmr->maps)
return;
- key = arbel_key_to_hw_index(fmr->ibmr.lkey);
- key &= dev->limits.num_mpts - 1;
- key = adjust_key(dev, key);
- fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);
-
fmr->maps = 0;
*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 696e1f3..be34f99 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -39,6 +39,8 @@
#include <rdma/ib_smi.h>
#include <rdma/ib_umem.h>
#include <rdma/ib_user_verbs.h>
+
+#include <linux/sched.h>
#include <linux/mm.h>
#include "mthca_dev.h"
@@ -367,6 +369,8 @@
return ERR_PTR(-EFAULT);
}
+ context->reg_mr_warned = 0;
+
return &context->ibucontext;
}
@@ -1006,17 +1010,31 @@
struct mthca_dev *dev = to_mdev(pd->device);
struct ib_umem_chunk *chunk;
struct mthca_mr *mr;
+ struct mthca_reg_mr ucmd;
u64 *pages;
int shift, n, len;
int i, j, k;
int err = 0;
int write_mtt_size;
+ if (udata->inlen - sizeof (struct ib_uverbs_cmd_hdr) < sizeof ucmd) {
+ if (!to_mucontext(pd->uobject->context)->reg_mr_warned) {
+ mthca_warn(dev, "Process '%s' did not pass in MR attrs.\n",
+ current->comm);
+ mthca_warn(dev, " Update libmthca to fix this.\n");
+ }
+ ++to_mucontext(pd->uobject->context)->reg_mr_warned;
+ ucmd.mr_attrs = 0;
+ } else if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+ return ERR_PTR(-EFAULT);
+
mr = kmalloc(sizeof *mr, GFP_KERNEL);
if (!mr)
return ERR_PTR(-ENOMEM);
- mr->umem = ib_umem_get(pd->uobject->context, start, length, acc);
+ mr->umem = ib_umem_get(pd->uobject->context, start, length, acc,
+ ucmd.mr_attrs & MTHCA_MR_DMASYNC);
+
if (IS_ERR(mr->umem)) {
err = PTR_ERR(mr->umem);
goto err;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 262616c..934bf95 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -67,6 +67,7 @@
struct ib_ucontext ibucontext;
struct mthca_uar uar;
struct mthca_user_db_table *db_tab;
+ int reg_mr_warned;
};
struct mthca_mtt;
diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h
index 02cc0a7..e1262c9 100644
--- a/drivers/infiniband/hw/mthca/mthca_user.h
+++ b/drivers/infiniband/hw/mthca/mthca_user.h
@@ -61,6 +61,16 @@
__u32 reserved;
};
+struct mthca_reg_mr {
+/*
+ * Mark the memory region with a DMA attribute that causes
+ * in-flight DMA to be flushed when the region is written to:
+ */
+#define MTHCA_MR_DMASYNC 0x1
+ __u32 mr_attrs;
+ __u32 reserved;
+};
+
struct mthca_create_cq {
__u32 lkey;
__u32 pdn;
diff --git a/drivers/infiniband/hw/nes/Kconfig b/drivers/infiniband/hw/nes/Kconfig
index 2aeb7ac..d449eb6 100644
--- a/drivers/infiniband/hw/nes/Kconfig
+++ b/drivers/infiniband/hw/nes/Kconfig
@@ -2,6 +2,7 @@
tristate "NetEffect RNIC Driver"
depends on PCI && INET && INFINIBAND
select LIBCRC32C
+ select INET_LRO
---help---
This is a low-level driver for NetEffect RDMA enabled
Network Interface Cards (RNIC).
diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c
index a4e9269..9f7364a 100644
--- a/drivers/infiniband/hw/nes/nes.c
+++ b/drivers/infiniband/hw/nes/nes.c
@@ -91,6 +91,10 @@
module_param_named(debug_level, nes_debug_level, uint, 0644);
MODULE_PARM_DESC(debug_level, "Enable debug output level");
+unsigned int nes_lro_max_aggr = NES_LRO_MAX_AGGR;
+module_param(nes_lro_max_aggr, int, NES_LRO_MAX_AGGR);
+MODULE_PARM_DESC(nes_mro_max_aggr, " nic LRO MAX packet aggregation");
+
LIST_HEAD(nes_adapter_list);
static LIST_HEAD(nes_dev_list);
diff --git a/drivers/infiniband/hw/nes/nes.h b/drivers/infiniband/hw/nes/nes.h
index cdf2e9a..1f9f7bf 100644
--- a/drivers/infiniband/hw/nes/nes.h
+++ b/drivers/infiniband/hw/nes/nes.h
@@ -173,6 +173,7 @@
extern unsigned int send_first;
extern unsigned int nes_drv_opt;
extern unsigned int nes_debug_level;
+extern unsigned int nes_lro_max_aggr;
extern struct list_head nes_adapter_list;
@@ -535,8 +536,8 @@
int nes_read_eeprom_values(struct nes_device *, struct nes_adapter *);
void nes_write_1G_phy_reg(struct nes_device *, u8, u8, u16);
void nes_read_1G_phy_reg(struct nes_device *, u8, u8, u16 *);
-void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16);
-void nes_read_10G_phy_reg(struct nes_device *, u16, u8);
+void nes_write_10G_phy_reg(struct nes_device *, u16, u8, u16, u16);
+void nes_read_10G_phy_reg(struct nes_device *, u8, u8, u16);
struct nes_cqp_request *nes_get_cqp_request(struct nes_device *);
void nes_post_cqp_request(struct nes_device *, struct nes_cqp_request *, int);
int nes_arp_table(struct nes_device *, u32, u8 *, u32);
diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c
index d940fc2..9a4b40f 100644
--- a/drivers/infiniband/hw/nes/nes_cm.c
+++ b/drivers/infiniband/hw/nes/nes_cm.c
@@ -594,7 +594,7 @@
continue;
}
/* this seems like the correct place, but leave send entry unprotected */
- // spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags);
+ /* spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); */
atomic_inc(&send_entry->skb->users);
cm_packets_retrans++;
nes_debug(NES_DBG_CM, "Retransmitting send_entry %p for node %p,"
@@ -1335,7 +1335,7 @@
cm_node->loc_addr, cm_node->loc_port,
cm_node->rem_addr, cm_node->rem_port,
cm_node->state, atomic_read(&cm_node->ref_count));
- // create event
+ /* create event */
cm_node->state = NES_CM_STATE_CLOSED;
create_event(cm_node, NES_CM_EVENT_ABORTED);
@@ -1669,7 +1669,7 @@
if (!cm_node)
return NULL;
- // set our node side to client (active) side
+ /* set our node side to client (active) side */
cm_node->tcp_cntxt.client = 1;
cm_node->tcp_cntxt.rcv_wscale = NES_CM_DEFAULT_RCV_WND_SCALE;
@@ -1694,7 +1694,7 @@
loopbackremotenode->mpa_frame_size = mpa_frame_size -
sizeof(struct ietf_mpa_frame);
- // we are done handling this state, set node to a TSA state
+ /* we are done handling this state, set node to a TSA state */
cm_node->state = NES_CM_STATE_TSA;
cm_node->tcp_cntxt.rcv_nxt = loopbackremotenode->tcp_cntxt.loc_seq_num;
loopbackremotenode->tcp_cntxt.rcv_nxt = cm_node->tcp_cntxt.loc_seq_num;
diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c
index 08964cc..8dc70f9 100644
--- a/drivers/infiniband/hw/nes/nes_hw.c
+++ b/drivers/infiniband/hw/nes/nes_hw.c
@@ -38,6 +38,7 @@
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
#include "nes.h"
@@ -832,7 +833,7 @@
nes_write_indexed(nesdev, 0x00000900, 0x20000001);
nes_write_indexed(nesdev, 0x000060C0, 0x0000028e);
nes_write_indexed(nesdev, 0x000060C8, 0x00000020);
- //
+
nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0);
/* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */
@@ -1207,11 +1208,16 @@
{
struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 counter = 0;
+ u32 sds_common_control0;
u32 mac_index = nesdev->mac_index;
- u32 tx_config;
+ u32 tx_config = 0;
u16 phy_data;
+ u32 temp_phy_data = 0;
+ u32 temp_phy_data2 = 0;
+ u32 i = 0;
- if (nesadapter->OneG_Mode) {
+ if ((nesadapter->OneG_Mode) &&
+ (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) {
nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
printk(PFX "%s: Programming mdc config for 1G\n", __func__);
@@ -1223,7 +1229,7 @@
nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n",
nesadapter->phy_index[mac_index], phy_data);
- nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000);
+ nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000);
/* Reset the PHY */
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000);
@@ -1277,12 +1283,126 @@
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300);
} else {
- if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
+ if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) ||
+ (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
/* setup 10G MDIO operation */
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
tx_config |= 0x14;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
}
+ if ((nesadapter->phy_type[mac_index] == NES_PHY_TYPE_ARGUS)) {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
+
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ mdelay(10);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
+ temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+
+ /*
+ * if firmware is already running (like from a
+ * driver un-load/load, don't do anything.
+ */
+ if (temp_phy_data == temp_phy_data2) {
+ /* configure QT2505 AMCC PHY */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0x0000, 0x8000);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0000);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc302, 0x0044);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc318, 0x0052);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc319, 0x0008);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc31a, 0x0098);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0026, 0x0E00);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0027, 0x0000);
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0x0028, 0xA528);
+
+ /*
+ * remove micro from reset; chip boots from ROM,
+ * uploads EEPROM f/w image, uC executes f/w
+ */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc300, 0x0002);
+
+ /*
+ * wait for heart beat to start to
+ * know loading is done
+ */
+ counter = 0;
+ do {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ if (counter++ > 1000) {
+ nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from heartbeat check <this is bad!!!> \n");
+ break;
+ }
+ mdelay(100);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7ee);
+ temp_phy_data2 = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ } while ((temp_phy_data2 == temp_phy_data));
+
+ /*
+ * wait for tracking to start to know
+ * f/w is good to go
+ */
+ counter = 0;
+ do {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x3, 0xd7fd);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ if (counter++ > 1000) {
+ nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from status check <this is bad!!!> \n");
+ break;
+ }
+ mdelay(1000);
+ /*
+ * nes_debug(NES_DBG_PHY, "AMCC PHY- phy_status not ready yet = 0x%02X\n",
+ * temp_phy_data);
+ */
+ } while (((temp_phy_data & 0xff) != 0x50) && ((temp_phy_data & 0xff) != 0x70));
+
+ /* set LOS Control invert RXLOSB_I_PADINV */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd003, 0x0000);
+ /* set LOS Control to mask of RXLOSB_I */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xc314, 0x0042);
+ /* set LED1 to input mode (LED1 and LED2 share same LED) */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd006, 0x0007);
+ /* set LED2 to RX link_status and activity */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd007, 0x000A);
+ /* set LED3 to RX link_status */
+ nes_write_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 0x1, 0xd008, 0x0009);
+
+ /*
+ * reset the res-calibration on t2
+ * serdes; ensures it is stable after
+ * the amcc phy is stable
+ */
+
+ sds_common_control0 = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0);
+ sds_common_control0 |= 0x1;
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0);
+
+ /* release the res-calibration reset */
+ sds_common_control0 &= 0xfffffffe;
+ nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, sds_common_control0);
+
+ i = 0;
+ while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET) & 0x00000040) != 0x00000040)
+ && (i++ < 5000)) {
+ /* mdelay(1); */
+ }
+
+ /*
+ * wait for link train done before moving on,
+ * or will get an interupt storm
+ */
+ counter = 0;
+ do {
+ temp_phy_data = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200 * (nesdev->mac_index & 1)));
+ if (counter++ > 1000) {
+ nes_debug(NES_DBG_PHY, "AMCC PHY- breaking from link train wait <this is bad, link didnt train!!!>\n");
+ break;
+ }
+ mdelay(1);
+ } while (((temp_phy_data & 0x0f1f0000) != 0x0f0f0000));
+ }
+ }
}
return 0;
}
@@ -1375,6 +1495,25 @@
}
+static int nes_lro_get_skb_hdr(struct sk_buff *skb, void **iphdr,
+ void **tcph, u64 *hdr_flags, void *priv)
+{
+ unsigned int ip_len;
+ struct iphdr *iph;
+ skb_reset_network_header(skb);
+ iph = ip_hdr(skb);
+ if (iph->protocol != IPPROTO_TCP)
+ return -1;
+ ip_len = ip_hdrlen(skb);
+ skb_set_transport_header(skb, ip_len);
+ *tcph = tcp_hdr(skb);
+
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+ *iphdr = iph;
+ return 0;
+}
+
+
/**
* nes_init_nic_qp
*/
@@ -1520,10 +1659,10 @@
}
u64temp = (u64)nesvnic->nic.sq_pbase;
- nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
u64temp = (u64)nesvnic->nic.rq_pbase;
- nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
+ nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP |
@@ -1575,7 +1714,7 @@
nic_rqe = &nesvnic->nic.rq_vbase[counter];
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
- nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
+ nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32));
nesvnic->nic.rx_skb[counter] = skb;
}
@@ -1592,15 +1731,21 @@
nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout;
nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic;
nes_debug(NES_DBG_INIT, "NAPI support Enabled\n");
-
if (nesdev->nesadapter->et_use_adaptive_rx_coalesce)
{
nes_nic_init_timer(nesdev);
if (netdev->mtu > 1500)
jumbomode = 1;
- nes_nic_init_timer_defaults(nesdev, jumbomode);
+ nes_nic_init_timer_defaults(nesdev, jumbomode);
}
-
+ nesvnic->lro_mgr.max_aggr = NES_LRO_MAX_AGGR;
+ nesvnic->lro_mgr.max_desc = NES_MAX_LRO_DESCRIPTORS;
+ nesvnic->lro_mgr.lro_arr = nesvnic->lro_desc;
+ nesvnic->lro_mgr.get_skb_header = nes_lro_get_skb_hdr;
+ nesvnic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID;
+ nesvnic->lro_mgr.dev = netdev;
+ nesvnic->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
+ nesvnic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
return 0;
}
@@ -1620,8 +1765,8 @@
/* Free remaining NIC receive buffers */
while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
- nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
- wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+ nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
+ wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
@@ -1704,17 +1849,17 @@
/* iff NIC, process here, else wait for DPC */
if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) {
nesdev->napi_isr_ran = 0;
- nes_write32(nesdev->regs+NES_INT_STAT,
- (int_stat &
- ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+ nes_write32(nesdev->regs + NES_INT_STAT,
+ (int_stat &
+ ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 | NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3)));
/* Process the CEQs */
nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]);
if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) &&
- (!nesadapter->et_use_adaptive_rx_coalesce)) ||
- ((nesadapter->et_use_adaptive_rx_coalesce) &&
- (nesdev->deepcq_count > nesadapter->et_pkt_rate_low)))) ) {
+ (!nesadapter->et_use_adaptive_rx_coalesce)) ||
+ ((nesadapter->et_use_adaptive_rx_coalesce) &&
+ (nesdev->deepcq_count > nesadapter->et_pkt_rate_low))))) {
if ((nesdev->int_req & NES_INT_TIMER) == 0) {
/* Enable Periodic timer interrupts */
nesdev->int_req |= NES_INT_TIMER;
@@ -1792,12 +1937,12 @@
}
if (int_stat) {
- if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
- NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) {
+ if (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0|
+ NES_INT_MAC1|NES_INT_MAC2 | NES_INT_MAC3)) {
/* Ack the interrupts */
nes_write32(nesdev->regs+NES_INT_STAT,
- (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
- NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
+ (int_stat & ~(NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0|
+ NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3)));
}
temp_int_stat = int_stat;
@@ -1862,8 +2007,8 @@
}
}
/* Don't use the interface interrupt bit stay in loop */
- int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
- NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3;
+ int_stat &= ~NES_INT_INTF | NES_INT_TIMER | NES_INT_MAC0 |
+ NES_INT_MAC1 | NES_INT_MAC2 | NES_INT_MAC3;
} while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS));
if (timer_ints == 1) {
@@ -1874,9 +2019,9 @@
nesdev->timer_only_int_count = 0;
nesdev->int_req &= ~NES_INT_TIMER;
nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
- nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+ nes_write32(nesdev->regs + NES_INT_MASK, ~nesdev->int_req);
} else {
- nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
}
} else {
if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
@@ -1884,7 +2029,7 @@
nes_nic_init_timer(nesdev);
}
nesdev->timer_only_int_count = 0;
- nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
+ nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
}
} else {
nesdev->timer_only_int_count = 0;
@@ -1933,7 +2078,7 @@
do {
if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) &
NES_CEQE_VALID) {
- u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])))<<32) |
+ u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]))) << 32) |
((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX])));
u64temp <<= 1;
cq = *((struct nes_hw_cq **)&u64temp);
@@ -1961,7 +2106,7 @@
*/
static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
{
-// u64 u64temp;
+ /* u64 u64temp; */
u32 head;
u32 aeq_size;
u32 aeqe_misc;
@@ -1980,8 +2125,10 @@
if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) {
if (aeqe_cq_id >= NES_FIRST_QPN) {
/* dealing with an accelerated QP related AE */
-// u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])))<<32) |
-// ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX])));
+ /*
+ * u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX]))) << 32) |
+ * ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX])));
+ */
nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe);
} else {
/* TODO: dealing with a CQP related AE */
@@ -2081,6 +2228,8 @@
u32 u32temp;
u16 phy_data;
u16 temp_phy_data;
+ u32 pcs_val = 0x0f0f0000;
+ u32 pcs_mask = 0x0f1f0000;
spin_lock_irqsave(&nesadapter->phy_lock, flags);
if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) {
@@ -2144,13 +2293,30 @@
nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n",
nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0),
nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200));
- pcs_control_status = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
- pcs_control_status = nes_read_indexed(nesdev,
- NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
+
+ if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_PUMA_1G) {
+ switch (mac_index) {
+ case 1:
+ case 3:
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
+ break;
+ default:
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0);
+ break;
+ }
+ } else {
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200));
+ pcs_control_status = nes_read_indexed(nesdev,
+ NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index & 1) * 0x200));
+ }
+
nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n",
mac_index, pcs_control_status);
- if (nesadapter->OneG_Mode) {
+ if ((nesadapter->OneG_Mode) &&
+ (nesadapter->phy_type[mac_index] != NES_PHY_TYPE_PUMA_1G)) {
u32temp = 0x01010000;
if (nesadapter->port_count > 2) {
u32temp |= 0x02020000;
@@ -2159,24 +2325,59 @@
phy_data = 0;
nes_debug(NES_DBG_PHY, "PCS says the link is down\n");
}
- } else if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
- nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
- temp_phy_data = (u16)nes_read_indexed(nesdev,
- NES_IDX_MAC_MDIO_CONTROL);
- u32temp = 20;
- do {
- nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
- phy_data = (u16)nes_read_indexed(nesdev,
- NES_IDX_MAC_MDIO_CONTROL);
- if ((phy_data == temp_phy_data) || (!(--u32temp)))
- break;
- temp_phy_data = phy_data;
- } while (1);
- nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
- __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
-
} else {
- phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0;
+ switch (nesadapter->phy_type[mac_index]) {
+ case NES_PHY_TYPE_IRIS:
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ u32temp = 20;
+ do {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
+ phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ if ((phy_data == temp_phy_data) || (!(--u32temp)))
+ break;
+ temp_phy_data = phy_data;
+ } while (1);
+ nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
+ __func__, phy_data, nesadapter->mac_link_down[mac_index] ? "DOWN" : "UP");
+ break;
+
+ case NES_PHY_TYPE_ARGUS:
+ /* clear the alarms */
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0x0008);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc001);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc002);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc005);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 4, 0xc006);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9003);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9004);
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 0x9005);
+ /* check link status */
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
+ temp_phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ u32temp = 100;
+ do {
+ nes_read_10G_phy_reg(nesdev, nesadapter->phy_index[mac_index], 1, 1);
+
+ phy_data = (u16)nes_read_indexed(nesdev, NES_IDX_MAC_MDIO_CONTROL);
+ if ((phy_data == temp_phy_data) || (!(--u32temp)))
+ break;
+ temp_phy_data = phy_data;
+ } while (1);
+ nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
+ __func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
+ break;
+
+ case NES_PHY_TYPE_PUMA_1G:
+ if (mac_index < 2)
+ pcs_val = pcs_mask = 0x01010000;
+ else
+ pcs_val = pcs_mask = 0x02020000;
+ /* fall through */
+ default:
+ phy_data = (pcs_val == (pcs_control_status & pcs_mask)) ? 0x4 : 0x0;
+ break;
+ }
}
if (phy_data & 0x0004) {
@@ -2185,8 +2386,8 @@
nes_debug(NES_DBG_PHY, "The Link is UP!!. linkup was %d\n",
nesvnic->linkup);
if (nesvnic->linkup == 0) {
- printk(PFX "The Link is now up for port %u, netdev %p.\n",
- mac_index, nesvnic->netdev);
+ printk(PFX "The Link is now up for port %s, netdev %p.\n",
+ nesvnic->netdev->name, nesvnic->netdev);
if (netif_queue_stopped(nesvnic->netdev))
netif_start_queue(nesvnic->netdev);
nesvnic->linkup = 1;
@@ -2199,8 +2400,8 @@
nes_debug(NES_DBG_PHY, "The Link is Down!!. linkup was %d\n",
nesvnic->linkup);
if (nesvnic->linkup == 1) {
- printk(PFX "The Link is now down for port %u, netdev %p.\n",
- mac_index, nesvnic->netdev);
+ printk(PFX "The Link is now down for port %s, netdev %p.\n",
+ nesvnic->netdev->name, nesvnic->netdev);
if (!(netif_queue_stopped(nesvnic->netdev)))
netif_stop_queue(nesvnic->netdev);
nesvnic->linkup = 0;
@@ -2254,10 +2455,13 @@
u16 pkt_type;
u16 rqes_processed = 0;
u8 sq_cqes = 0;
+ u8 nes_use_lro = 0;
head = cq->cq_head;
cq_size = cq->cq_size;
cq->cqes_pending = 1;
+ if (nesvnic->netdev->features & NETIF_F_LRO)
+ nes_use_lro = 1;
do {
if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
NES_NIC_CQE_VALID) {
@@ -2272,8 +2476,10 @@
/* bump past the vlan tag */
wqe_fragment_length++;
if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
- u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
- u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
+ u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX +
+ wqe_fragment_index * 2]);
+ u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX +
+ wqe_fragment_index * 2])) << 32;
bus_address = (dma_addr_t)u64temp;
if (test_and_clear_bit(nesnic->sq_tail, nesnic->first_frag_overflow)) {
pci_unmap_single(nesdev->pcidev,
@@ -2283,8 +2489,10 @@
}
for (; wqe_fragment_index < 5; wqe_fragment_index++) {
if (wqe_fragment_length[wqe_fragment_index]) {
- u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
- u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
+ u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX +
+ wqe_fragment_index * 2]);
+ u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX
+ + wqe_fragment_index * 2])) <<32;
bus_address = (dma_addr_t)u64temp;
pci_unmap_page(nesdev->pcidev,
bus_address,
@@ -2331,7 +2539,7 @@
if (atomic_read(&nesvnic->rx_skbs_needed) > (nesvnic->nic.rq_size>>1)) {
nes_write32(nesdev->regs+NES_CQE_ALLOC,
cq->cq_number | (cqe_count << 16));
-// nesadapter->tune_timer.cq_count += cqe_count;
+ /* nesadapter->tune_timer.cq_count += cqe_count; */
nesdev->currcq_count += cqe_count;
cqe_count = 0;
nes_replenish_nic_rq(nesvnic);
@@ -2379,9 +2587,16 @@
>> 16);
nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
nesvnic->netdev->name, vlan_tag);
- nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
+ if (nes_use_lro)
+ lro_vlan_hwaccel_receive_skb(&nesvnic->lro_mgr, rx_skb,
+ nesvnic->vlan_grp, vlan_tag, NULL);
+ else
+ nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
} else {
- nes_netif_rx(rx_skb);
+ if (nes_use_lro)
+ lro_receive_skb(&nesvnic->lro_mgr, rx_skb, NULL);
+ else
+ nes_netif_rx(rx_skb);
}
}
@@ -2399,7 +2614,7 @@
/* Replenish Nic CQ */
nes_write32(nesdev->regs+NES_CQE_ALLOC,
cq->cq_number | (cqe_count << 16));
-// nesdev->nesadapter->tune_timer.cq_count += cqe_count;
+ /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */
nesdev->currcq_count += cqe_count;
cqe_count = 0;
}
@@ -2413,26 +2628,27 @@
} while (1);
+ if (nes_use_lro)
+ lro_flush_all(&nesvnic->lro_mgr);
if (sq_cqes) {
barrier();
/* restart the queue if it had been stopped */
if (netif_queue_stopped(nesvnic->netdev))
netif_wake_queue(nesvnic->netdev);
}
-
cq->cq_head = head;
/* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n",
cq->cq_number, cqe_count, cq->cq_head); */
cq->cqe_allocs_pending = cqe_count;
if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
{
-// nesdev->nesadapter->tune_timer.cq_count += cqe_count;
+ /* nesdev->nesadapter->tune_timer.cq_count += cqe_count; */
nesdev->currcq_count += cqe_count;
nes_nic_tune_timer(nesdev);
}
if (atomic_read(&nesvnic->rx_skbs_needed))
nes_replenish_nic_rq(nesvnic);
- }
+}
/**
@@ -2461,7 +2677,7 @@
if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) {
u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head].
- cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
+ cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX]))) << 32) |
((u64)(le32_to_cpu(cq->cq_vbase[head].
cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX])));
cqp = *((struct nes_hw_cqp **)&u64temp);
@@ -2478,7 +2694,7 @@
}
u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
- wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX])))<<32) |
+ wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX]))) << 32) |
((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX])));
cqp_request = *((struct nes_cqp_request **)&u64temp);
@@ -2515,7 +2731,7 @@
} else {
nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
cqp_request,
- le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f);
+ le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX]) & 0x3f);
if (cqp_request->dynamic) {
kfree(cqp_request);
} else {
@@ -2529,7 +2745,7 @@
}
cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
- nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (1 << 16));
+ nes_write32(nesdev->regs + NES_CQE_ALLOC, cq->cq_number | (1 << 16));
if (++cqp->sq_tail >= cqp->sq_size)
cqp->sq_tail = 0;
@@ -2598,13 +2814,13 @@
nes_debug(NES_DBG_AEQ, "\n");
aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) {
- context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
+ context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
} else {
aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
context = (unsigned long)nesadapter->qp_table[le32_to_cpu(
- aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
+ aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]) - NES_FIRST_QPN];
BUG_ON(!context);
}
@@ -2617,7 +2833,6 @@
le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
-
switch (async_event_id) {
case NES_AEQE_AEID_LLP_FIN_RECEIVED:
nesqp = *((struct nes_qp **)&context);
@@ -3021,7 +3236,7 @@
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_ARP_VALID);
cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = cpu_to_le32(
(((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) |
- (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]);
+ (((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]);
cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32(
(((u32)mac_addr[0]) << 16) | (u32)mac_addr[1]);
} else {
diff --git a/drivers/infiniband/hw/nes/nes_hw.h b/drivers/infiniband/hw/nes/nes_hw.h
index 8f36e23..745bf94 100644
--- a/drivers/infiniband/hw/nes/nes_hw.h
+++ b/drivers/infiniband/hw/nes/nes_hw.h
@@ -33,8 +33,12 @@
#ifndef __NES_HW_H
#define __NES_HW_H
-#define NES_PHY_TYPE_1G 2
-#define NES_PHY_TYPE_IRIS 3
+#include <linux/inet_lro.h>
+
+#define NES_PHY_TYPE_1G 2
+#define NES_PHY_TYPE_IRIS 3
+#define NES_PHY_TYPE_ARGUS 4
+#define NES_PHY_TYPE_PUMA_1G 5
#define NES_PHY_TYPE_PUMA_10G 6
#define NES_MULTICAST_PF_MAX 8
@@ -965,7 +969,7 @@
#define NES_NIC_CQ_DOWNWARD_TREND 16
struct nes_hw_tune_timer {
- //u16 cq_count;
+ /* u16 cq_count; */
u16 threshold_low;
u16 threshold_target;
u16 threshold_high;
@@ -982,8 +986,10 @@
#define NES_TIMER_INT_LIMIT 2
#define NES_TIMER_INT_LIMIT_DYNAMIC 10
#define NES_TIMER_ENABLE_LIMIT 4
-#define NES_MAX_LINK_INTERRUPTS 128
-#define NES_MAX_LINK_CHECK 200
+#define NES_MAX_LINK_INTERRUPTS 128
+#define NES_MAX_LINK_CHECK 200
+#define NES_MAX_LRO_DESCRIPTORS 32
+#define NES_LRO_MAX_AGGR 64
struct nes_adapter {
u64 fw_ver;
@@ -1183,6 +1189,9 @@
u8 of_device_registered;
u8 rdma_enabled;
u8 rx_checksum_disabled;
+ u32 lro_max_aggr;
+ struct net_lro_mgr lro_mgr;
+ struct net_lro_desc lro_desc[NES_MAX_LRO_DESCRIPTORS];
};
struct nes_ib_device {
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index e5366b0..1b0938c 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -185,12 +185,13 @@
nic_active |= nic_active_bit;
nes_write_indexed(nesdev, NES_IDX_NIC_BROADCAST_ON, nic_active);
- macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
+ macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
macaddr_high += (u16)netdev->dev_addr[1];
- macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
- macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
- macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
- macaddr_low += (u32)netdev->dev_addr[5];
+
+ macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
+ macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
+ macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
+ macaddr_low += (u32)netdev->dev_addr[5];
/* Program the various MAC regs */
for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
@@ -451,7 +452,7 @@
__le16 *wqe_fragment_length;
u32 nr_frags;
u32 original_first_length;
-// u64 *wqe_fragment_address;
+ /* u64 *wqe_fragment_address; */
/* first fragment (0) is used by copy buffer */
u16 wqe_fragment_index=1;
u16 hoffset;
@@ -461,11 +462,12 @@
u32 old_head;
u32 wqe_misc;
- /* nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
- " (%u frags), tso_size=%u\n",
- netdev->name, skb->len, skb_headlen(skb),
- skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
- */
+ /*
+ * nes_debug(NES_DBG_NIC_TX, "%s Request to tx NIC packet length %u, headlen %u,"
+ * " (%u frags), tso_size=%u\n",
+ * netdev->name, skb->len, skb_headlen(skb),
+ * skb_shinfo(skb)->nr_frags, skb_is_gso(skb));
+ */
if (!netif_carrier_ok(netdev))
return NETDEV_TX_OK;
@@ -795,12 +797,12 @@
memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len);
printk(PFX "%s: Address length = %d, Address = %s\n",
__func__, netdev->addr_len, print_mac(mac, mac_addr->sa_data));
- macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
+ macaddr_high = ((u16)netdev->dev_addr[0]) << 8;
macaddr_high += (u16)netdev->dev_addr[1];
- macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
- macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
- macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
- macaddr_low += (u32)netdev->dev_addr[5];
+ macaddr_low = ((u32)netdev->dev_addr[2]) << 24;
+ macaddr_low += ((u32)netdev->dev_addr[3]) << 16;
+ macaddr_low += ((u32)netdev->dev_addr[4]) << 8;
+ macaddr_low += (u32)netdev->dev_addr[5];
for (i = 0; i < NES_MAX_PORT_COUNT; i++) {
if (nesvnic->qp_nic_index[i] == 0xf) {
@@ -881,12 +883,12 @@
print_mac(mac, multicast_addr->dmi_addr),
perfect_filter_register_address+(mc_index * 8),
mc_nic_index);
- macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8;
+ macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8;
macaddr_high += (u16)multicast_addr->dmi_addr[1];
- macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24;
- macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16;
- macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8;
- macaddr_low += (u32)multicast_addr->dmi_addr[5];
+ macaddr_low = ((u32)multicast_addr->dmi_addr[2]) << 24;
+ macaddr_low += ((u32)multicast_addr->dmi_addr[3]) << 16;
+ macaddr_low += ((u32)multicast_addr->dmi_addr[4]) << 8;
+ macaddr_low += (u32)multicast_addr->dmi_addr[5];
nes_write_indexed(nesdev,
perfect_filter_register_address+(mc_index * 8),
macaddr_low);
@@ -910,23 +912,23 @@
/**
* nes_netdev_change_mtu
*/
-static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
+static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu)
{
struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
- int ret = 0;
- u8 jumbomode=0;
+ struct nes_device *nesdev = nesvnic->nesdev;
+ int ret = 0;
+ u8 jumbomode = 0;
- if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu))
+ if ((new_mtu < ETH_ZLEN) || (new_mtu > max_mtu))
return -EINVAL;
- netdev->mtu = new_mtu;
+ netdev->mtu = new_mtu;
nesvnic->max_frame_size = new_mtu + VLAN_ETH_HLEN;
if (netdev->mtu > 1500) {
jumbomode=1;
}
- nes_nic_init_timer_defaults(nesdev, jumbomode);
+ nes_nic_init_timer_defaults(nesdev, jumbomode);
if (netif_running(netdev)) {
nes_netdev_stop(netdev);
@@ -936,8 +938,7 @@
return ret;
}
-#define NES_ETHTOOL_STAT_COUNT 55
-static const char nes_ethtool_stringset[NES_ETHTOOL_STAT_COUNT][ETH_GSTRING_LEN] = {
+static const char nes_ethtool_stringset[][ETH_GSTRING_LEN] = {
"Link Change Interrupts",
"Linearized SKBs",
"T/GSO Requests",
@@ -993,8 +994,12 @@
"CQ Depth 32",
"CQ Depth 128",
"CQ Depth 256",
+ "LRO aggregated",
+ "LRO flushed",
+ "LRO no_desc",
};
+#define NES_ETHTOOL_STAT_COUNT ARRAY_SIZE(nes_ethtool_stringset)
/**
* nes_netdev_get_rx_csum
@@ -1189,6 +1194,9 @@
target_stat_values[52] = int_mod_cq_depth_32;
target_stat_values[53] = int_mod_cq_depth_128;
target_stat_values[54] = int_mod_cq_depth_256;
+ target_stat_values[55] = nesvnic->lro_mgr.stats.aggregated;
+ target_stat_values[56] = nesvnic->lro_mgr.stats.flushed;
+ target_stat_values[57] = nesvnic->lro_mgr.stats.no_desc;
}
@@ -1219,14 +1227,14 @@
struct ethtool_coalesce *et_coalesce)
{
struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_device *nesdev = nesvnic->nesdev;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
unsigned long flags;
- spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
+ spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
if (et_coalesce->rx_max_coalesced_frames_low) {
- shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low;
+ shared_timer->threshold_low = et_coalesce->rx_max_coalesced_frames_low;
}
if (et_coalesce->rx_max_coalesced_frames_irq) {
shared_timer->threshold_target = et_coalesce->rx_max_coalesced_frames_irq;
@@ -1246,14 +1254,14 @@
nesadapter->et_rx_coalesce_usecs_irq = et_coalesce->rx_coalesce_usecs_irq;
if (et_coalesce->use_adaptive_rx_coalesce) {
nesadapter->et_use_adaptive_rx_coalesce = 1;
- nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
+ nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
nesadapter->et_rx_coalesce_usecs_irq = 0;
if (et_coalesce->pkt_rate_low) {
- nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low;
+ nesadapter->et_pkt_rate_low = et_coalesce->pkt_rate_low;
}
} else {
nesadapter->et_use_adaptive_rx_coalesce = 0;
- nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
+ nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
if (nesadapter->et_rx_coalesce_usecs_irq) {
nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
0x80000000 | ((u32)(nesadapter->et_rx_coalesce_usecs_irq*8)));
@@ -1270,28 +1278,28 @@
struct ethtool_coalesce *et_coalesce)
{
struct nes_vnic *nesvnic = netdev_priv(netdev);
- struct nes_device *nesdev = nesvnic->nesdev;
+ struct nes_device *nesdev = nesvnic->nesdev;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct ethtool_coalesce temp_et_coalesce;
struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
unsigned long flags;
memset(&temp_et_coalesce, 0, sizeof(temp_et_coalesce));
- temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq;
- temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce;
- temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval;
+ temp_et_coalesce.rx_coalesce_usecs_irq = nesadapter->et_rx_coalesce_usecs_irq;
+ temp_et_coalesce.use_adaptive_rx_coalesce = nesadapter->et_use_adaptive_rx_coalesce;
+ temp_et_coalesce.rate_sample_interval = nesadapter->et_rate_sample_interval;
temp_et_coalesce.pkt_rate_low = nesadapter->et_pkt_rate_low;
spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
- temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low;
- temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target;
+ temp_et_coalesce.rx_max_coalesced_frames_low = shared_timer->threshold_low;
+ temp_et_coalesce.rx_max_coalesced_frames_irq = shared_timer->threshold_target;
temp_et_coalesce.rx_max_coalesced_frames_high = shared_timer->threshold_high;
- temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min;
+ temp_et_coalesce.rx_coalesce_usecs_low = shared_timer->timer_in_use_min;
temp_et_coalesce.rx_coalesce_usecs_high = shared_timer->timer_in_use_max;
if (nesadapter->et_use_adaptive_rx_coalesce) {
temp_et_coalesce.rx_coalesce_usecs_irq = shared_timer->timer_in_use;
}
spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
- memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce));
+ memcpy(et_coalesce, &temp_et_coalesce, sizeof(*et_coalesce));
return 0;
}
@@ -1370,30 +1378,38 @@
u16 phy_data;
et_cmd->duplex = DUPLEX_FULL;
- et_cmd->port = PORT_MII;
+ et_cmd->port = PORT_MII;
+
if (nesadapter->OneG_Mode) {
- et_cmd->supported = SUPPORTED_1000baseT_Full|SUPPORTED_Autoneg;
- et_cmd->advertising = ADVERTISED_1000baseT_Full|ADVERTISED_Autoneg;
et_cmd->speed = SPEED_1000;
- nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
- &phy_data);
- if (phy_data&0x1000) {
- et_cmd->autoneg = AUTONEG_ENABLE;
+ if (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) {
+ et_cmd->supported = SUPPORTED_1000baseT_Full;
+ et_cmd->advertising = ADVERTISED_1000baseT_Full;
+ et_cmd->autoneg = AUTONEG_DISABLE;
+ et_cmd->transceiver = XCVR_INTERNAL;
+ et_cmd->phy_address = nesdev->mac_index;
} else {
- et_cmd->autoneg = AUTONEG_DISABLE;
- }
- et_cmd->transceiver = XCVR_EXTERNAL;
- et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
- } else {
- if (nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) {
+ et_cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg;
+ et_cmd->advertising = ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg;
+ nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index], &phy_data);
+ if (phy_data & 0x1000)
+ et_cmd->autoneg = AUTONEG_ENABLE;
+ else
+ et_cmd->autoneg = AUTONEG_DISABLE;
et_cmd->transceiver = XCVR_EXTERNAL;
- et_cmd->port = PORT_FIBRE;
- et_cmd->supported = SUPPORTED_FIBRE;
+ et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
+ }
+ } else {
+ if ((nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) ||
+ (nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_ARGUS)) {
+ et_cmd->transceiver = XCVR_EXTERNAL;
+ et_cmd->port = PORT_FIBRE;
+ et_cmd->supported = SUPPORTED_FIBRE;
et_cmd->advertising = ADVERTISED_FIBRE;
et_cmd->phy_address = nesadapter->phy_index[nesdev->mac_index];
} else {
et_cmd->transceiver = XCVR_INTERNAL;
- et_cmd->supported = SUPPORTED_10000baseT_Full;
+ et_cmd->supported = SUPPORTED_10000baseT_Full;
et_cmd->advertising = ADVERTISED_10000baseT_Full;
et_cmd->phy_address = nesdev->mac_index;
}
@@ -1416,14 +1432,15 @@
struct nes_adapter *nesadapter = nesdev->nesadapter;
u16 phy_data;
- if (nesadapter->OneG_Mode) {
+ if ((nesadapter->OneG_Mode) &&
+ (nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G)) {
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
&phy_data);
if (et_cmd->autoneg) {
/* Turn on Full duplex, Autoneg, and restart autonegotiation */
phy_data |= 0x1300;
} else {
- // Turn off autoneg
+ /* Turn off autoneg */
phy_data &= ~0x1000;
}
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[nesdev->mac_index],
@@ -1454,6 +1471,8 @@
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = ethtool_op_set_flags,
};
@@ -1607,27 +1626,34 @@
list_add_tail(&nesvnic->list, &nesdev->nesadapter->nesvnic_list[nesdev->mac_index]);
if ((nesdev->netdev_count == 0) &&
- (PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index)) {
- nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n",
- NES_IDX_PHY_PCS_CONTROL_STATUS0+(0x200*(nesvnic->logical_port&1)));
+ ((PCI_FUNC(nesdev->pcidev->devfn) == nesdev->mac_index) ||
+ ((nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) &&
+ (((PCI_FUNC(nesdev->pcidev->devfn) == 1) && (nesdev->mac_index == 2)) ||
+ ((PCI_FUNC(nesdev->pcidev->devfn) == 2) && (nesdev->mac_index == 1)))))) {
+ /*
+ * nes_debug(NES_DBG_INIT, "Setting up PHY interrupt mask. Using register index 0x%04X\n",
+ * NES_IDX_PHY_PCS_CONTROL_STATUS0 + (0x200 * (nesvnic->logical_port & 1)));
+ */
u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200*(nesvnic->logical_port&1)));
- u32temp |= 0x00200000;
- nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200*(nesvnic->logical_port&1)), u32temp);
+ (0x200 * (nesdev->mac_index & 1)));
+ if (nesdev->nesadapter->phy_type[nesdev->mac_index] != NES_PHY_TYPE_PUMA_1G) {
+ u32temp |= 0x00200000;
+ nes_write_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
+ (0x200 * (nesdev->mac_index & 1)), u32temp);
+ }
+
u32temp = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 +
- (0x200*(nesvnic->logical_port&1)) );
+ (0x200 * (nesdev->mac_index & 1)));
+
if ((u32temp&0x0f1f0000) == 0x0f0f0000) {
- if (nesdev->nesadapter->phy_type[nesvnic->logical_port] == NES_PHY_TYPE_IRIS) {
+ if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_IRIS) {
nes_init_phy(nesdev);
- nes_read_10G_phy_reg(nesdev, 1,
- nesdev->nesadapter->phy_index[nesvnic->logical_port]);
+ nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1);
temp_phy_data = (u16)nes_read_indexed(nesdev,
NES_IDX_MAC_MDIO_CONTROL);
u32temp = 20;
do {
- nes_read_10G_phy_reg(nesdev, 1,
- nesdev->nesadapter->phy_index[nesvnic->logical_port]);
+ nes_read_10G_phy_reg(nesdev, nesdev->nesadapter->phy_index[nesdev->mac_index], 1, 1);
phy_data = (u16)nes_read_indexed(nesdev,
NES_IDX_MAC_MDIO_CONTROL);
if ((phy_data == temp_phy_data) || (!(--u32temp)))
@@ -1644,6 +1670,14 @@
nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
nesvnic->linkup = 1;
}
+ } else if (nesdev->nesadapter->phy_type[nesdev->mac_index] == NES_PHY_TYPE_PUMA_1G) {
+ nes_debug(NES_DBG_INIT, "mac_index=%d, logical_port=%d, u32temp=0x%04X, PCI_FUNC=%d\n",
+ nesdev->mac_index, nesvnic->logical_port, u32temp, PCI_FUNC(nesdev->pcidev->devfn));
+ if (((nesdev->mac_index < 2) && ((u32temp&0x01010000) == 0x01010000)) ||
+ ((nesdev->mac_index > 1) && ((u32temp&0x02020000) == 0x02020000))) {
+ nes_debug(NES_DBG_INIT, "The Link is UP!!.\n");
+ nesvnic->linkup = 1;
+ }
}
/* clear the MAC interrupt status, assumes direct logical to physical mapping */
u32temp = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (0x200 * nesdev->mac_index));
diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c
index c6d5631..fe83d1b 100644
--- a/drivers/infiniband/hw/nes/nes_utils.c
+++ b/drivers/infiniband/hw/nes/nes_utils.c
@@ -444,15 +444,13 @@
/**
* nes_write_10G_phy_reg
*/
-void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg,
- u8 phy_addr, u16 data)
+void nes_write_10G_phy_reg(struct nes_device *nesdev, u16 phy_addr, u8 dev_addr, u16 phy_reg,
+ u16 data)
{
- u32 dev_addr;
u32 port_addr;
u32 u32temp;
u32 counter;
- dev_addr = 1;
port_addr = phy_addr;
/* set address */
@@ -492,14 +490,12 @@
* This routine only issues the read, the data must be read
* separately.
*/
-void nes_read_10G_phy_reg(struct nes_device *nesdev, u16 phy_reg, u8 phy_addr)
+void nes_read_10G_phy_reg(struct nes_device *nesdev, u8 phy_addr, u8 dev_addr, u16 phy_reg)
{
- u32 dev_addr;
u32 port_addr;
u32 u32temp;
u32 counter;
- dev_addr = 1;
port_addr = phy_addr;
/* set address */
diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c
index ee74f7c..99b3c4a 100644
--- a/drivers/infiniband/hw/nes/nes_verbs.c
+++ b/drivers/infiniband/hw/nes/nes_verbs.c
@@ -1266,7 +1266,7 @@
sq_size = init_attr->cap.max_send_wr;
rq_size = init_attr->cap.max_recv_wr;
- // check if the encoded sizes are OK or not...
+ /* check if the encoded sizes are OK or not... */
sq_encoded_size = nes_get_encoded_size(&sq_size);
rq_encoded_size = nes_get_encoded_size(&rq_size);
@@ -2377,7 +2377,7 @@
u8 single_page = 1;
u8 stag_key;
- region = ib_umem_get(pd->uobject->context, start, length, acc);
+ region = ib_umem_get(pd->uobject->context, start, length, acc, 0);
if (IS_ERR(region)) {
return (struct ib_mr *)region;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index f1f142d..9044f88 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -95,6 +95,8 @@
IPOIB_MCAST_FLAG_SENDONLY = 1,
IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */
IPOIB_MCAST_FLAG_ATTACHED = 3,
+
+ MAX_SEND_CQE = 16,
};
#define IPOIB_OP_RECV (1ul << 31)
@@ -285,7 +287,8 @@
u16 pkey_index;
struct ib_pd *pd;
struct ib_mr *mr;
- struct ib_cq *cq;
+ struct ib_cq *recv_cq;
+ struct ib_cq *send_cq;
struct ib_qp *qp;
u32 qkey;
@@ -305,6 +308,7 @@
struct ib_sge tx_sge[MAX_SKB_FRAGS + 1];
struct ib_send_wr tx_wr;
unsigned tx_outstanding;
+ struct ib_wc send_wc[MAX_SEND_CQE];
struct ib_recv_wr rx_wr;
struct ib_sge rx_sge[IPOIB_UD_RX_SG];
@@ -662,7 +666,6 @@
static inline void ipoib_unregister_debugfs(void) { }
#endif
-
#define ipoib_printk(level, priv, format, arg...) \
printk(level "%s: " format, ((struct ipoib_dev_priv *) priv)->dev->name , ## arg)
#define ipoib_warn(priv, format, arg...) \
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 9db7b0b..97e67d3 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -249,8 +249,8 @@
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ib_qp_init_attr attr = {
.event_handler = ipoib_cm_rx_event_handler,
- .send_cq = priv->cq, /* For drain WR */
- .recv_cq = priv->cq,
+ .send_cq = priv->recv_cq, /* For drain WR */
+ .recv_cq = priv->recv_cq,
.srq = priv->cm.srq,
.cap.max_send_wr = 1, /* For drain WR */
.cap.max_send_sge = 1, /* FIXME: 0 Seems not to work */
@@ -951,8 +951,8 @@
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ib_qp_init_attr attr = {
- .send_cq = priv->cq,
- .recv_cq = priv->cq,
+ .send_cq = priv->recv_cq,
+ .recv_cq = priv->recv_cq,
.srq = priv->cm.srq,
.cap.max_send_wr = ipoib_sendq_size,
.cap.max_send_sge = 1,
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
index 9a47428..10279b7 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ethtool.c
@@ -71,7 +71,7 @@
coal->rx_max_coalesced_frames > 0xffff)
return -EINVAL;
- ret = ib_modify_cq(priv->cq, coal->rx_max_coalesced_frames,
+ ret = ib_modify_cq(priv->recv_cq, coal->rx_max_coalesced_frames,
coal->rx_coalesce_usecs);
if (ret && ret != -ENOSYS) {
ipoib_warn(priv, "failed modifying CQ (%d)\n", ret);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index 7cf1fa7..97b815c 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -364,7 +364,6 @@
struct ipoib_dev_priv *priv = netdev_priv(dev);
unsigned int wr_id = wc->wr_id;
struct ipoib_tx_buf *tx_req;
- unsigned long flags;
ipoib_dbg_data(priv, "send completion: id %d, status: %d\n",
wr_id, wc->status);
@@ -384,13 +383,11 @@
dev_kfree_skb_any(tx_req->skb);
- spin_lock_irqsave(&priv->tx_lock, flags);
++priv->tx_tail;
if (unlikely(--priv->tx_outstanding == ipoib_sendq_size >> 1) &&
netif_queue_stopped(dev) &&
test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
netif_wake_queue(dev);
- spin_unlock_irqrestore(&priv->tx_lock, flags);
if (wc->status != IB_WC_SUCCESS &&
wc->status != IB_WC_WR_FLUSH_ERR)
@@ -399,6 +396,17 @@
wc->status, wr_id, wc->vendor_err);
}
+static int poll_tx(struct ipoib_dev_priv *priv)
+{
+ int n, i;
+
+ n = ib_poll_cq(priv->send_cq, MAX_SEND_CQE, priv->send_wc);
+ for (i = 0; i < n; ++i)
+ ipoib_ib_handle_tx_wc(priv->dev, priv->send_wc + i);
+
+ return n == MAX_SEND_CQE;
+}
+
int ipoib_poll(struct napi_struct *napi, int budget)
{
struct ipoib_dev_priv *priv = container_of(napi, struct ipoib_dev_priv, napi);
@@ -414,7 +422,7 @@
int max = (budget - done);
t = min(IPOIB_NUM_WC, max);
- n = ib_poll_cq(priv->cq, t, priv->ibwc);
+ n = ib_poll_cq(priv->recv_cq, t, priv->ibwc);
for (i = 0; i < n; i++) {
struct ib_wc *wc = priv->ibwc + i;
@@ -425,12 +433,8 @@
ipoib_cm_handle_rx_wc(dev, wc);
else
ipoib_ib_handle_rx_wc(dev, wc);
- } else {
- if (wc->wr_id & IPOIB_OP_CM)
- ipoib_cm_handle_tx_wc(dev, wc);
- else
- ipoib_ib_handle_tx_wc(dev, wc);
- }
+ } else
+ ipoib_cm_handle_tx_wc(priv->dev, wc);
}
if (n != t)
@@ -439,7 +443,7 @@
if (done < budget) {
netif_rx_complete(dev, napi);
- if (unlikely(ib_req_notify_cq(priv->cq,
+ if (unlikely(ib_req_notify_cq(priv->recv_cq,
IB_CQ_NEXT_COMP |
IB_CQ_REPORT_MISSED_EVENTS)) &&
netif_rx_reschedule(dev, napi))
@@ -562,12 +566,16 @@
address->last_send = priv->tx_head;
++priv->tx_head;
+ skb_orphan(skb);
if (++priv->tx_outstanding == ipoib_sendq_size) {
ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n");
netif_stop_queue(dev);
}
}
+
+ if (unlikely(priv->tx_outstanding > MAX_SEND_CQE))
+ poll_tx(priv);
}
static void __ipoib_reap_ah(struct net_device *dev)
@@ -714,7 +722,7 @@
struct ipoib_dev_priv *priv = netdev_priv(dev);
int i, n;
do {
- n = ib_poll_cq(priv->cq, IPOIB_NUM_WC, priv->ibwc);
+ n = ib_poll_cq(priv->recv_cq, IPOIB_NUM_WC, priv->ibwc);
for (i = 0; i < n; ++i) {
/*
* Convert any successful completions to flush
@@ -729,14 +737,13 @@
ipoib_cm_handle_rx_wc(dev, priv->ibwc + i);
else
ipoib_ib_handle_rx_wc(dev, priv->ibwc + i);
- } else {
- if (priv->ibwc[i].wr_id & IPOIB_OP_CM)
- ipoib_cm_handle_tx_wc(dev, priv->ibwc + i);
- else
- ipoib_ib_handle_tx_wc(dev, priv->ibwc + i);
- }
+ } else
+ ipoib_cm_handle_tx_wc(dev, priv->ibwc + i);
}
} while (n == IPOIB_NUM_WC);
+
+ while (poll_tx(priv))
+ ; /* nothing */
}
int ipoib_ib_dev_stop(struct net_device *dev, int flush)
@@ -826,7 +833,7 @@
msleep(1);
}
- ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP);
+ ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP);
return 0;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 7a4ed9d..2442090 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -1298,7 +1298,8 @@
ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size);
ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE);
- ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE);
+ ipoib_sendq_size = max(ipoib_sendq_size, max(2 * MAX_SEND_CQE,
+ IPOIB_MIN_QUEUE_SIZE));
#ifdef CONFIG_INFINIBAND_IPOIB_CM
ipoib_max_conn_qp = min(ipoib_max_conn_qp, IPOIB_CM_MAX_CONN_QP);
#endif
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index 07c03f1..c1e7ece 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -171,26 +171,33 @@
goto out_free_pd;
}
- size = ipoib_sendq_size + ipoib_recvq_size + 1;
+ size = ipoib_recvq_size + 1;
ret = ipoib_cm_dev_init(dev);
if (!ret) {
+ size += ipoib_sendq_size;
if (ipoib_cm_has_srq(dev))
size += ipoib_recvq_size + 1; /* 1 extra for rx_drain_qp */
else
size += ipoib_recvq_size * ipoib_max_conn_qp;
}
- priv->cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
- if (IS_ERR(priv->cq)) {
- printk(KERN_WARNING "%s: failed to create CQ\n", ca->name);
+ priv->recv_cq = ib_create_cq(priv->ca, ipoib_ib_completion, NULL, dev, size, 0);
+ if (IS_ERR(priv->recv_cq)) {
+ printk(KERN_WARNING "%s: failed to create receive CQ\n", ca->name);
goto out_free_mr;
}
- if (ib_req_notify_cq(priv->cq, IB_CQ_NEXT_COMP))
- goto out_free_cq;
+ priv->send_cq = ib_create_cq(priv->ca, NULL, NULL, dev, ipoib_sendq_size, 0);
+ if (IS_ERR(priv->send_cq)) {
+ printk(KERN_WARNING "%s: failed to create send CQ\n", ca->name);
+ goto out_free_recv_cq;
+ }
- init_attr.send_cq = priv->cq;
- init_attr.recv_cq = priv->cq;
+ if (ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP))
+ goto out_free_send_cq;
+
+ init_attr.send_cq = priv->send_cq;
+ init_attr.recv_cq = priv->recv_cq;
if (priv->hca_caps & IB_DEVICE_UD_TSO)
init_attr.create_flags = IB_QP_CREATE_IPOIB_UD_LSO;
@@ -201,7 +208,7 @@
priv->qp = ib_create_qp(priv->pd, &init_attr);
if (IS_ERR(priv->qp)) {
printk(KERN_WARNING "%s: failed to create QP\n", ca->name);
- goto out_free_cq;
+ goto out_free_send_cq;
}
priv->dev->dev_addr[1] = (priv->qp->qp_num >> 16) & 0xff;
@@ -230,8 +237,11 @@
return 0;
-out_free_cq:
- ib_destroy_cq(priv->cq);
+out_free_send_cq:
+ ib_destroy_cq(priv->send_cq);
+
+out_free_recv_cq:
+ ib_destroy_cq(priv->recv_cq);
out_free_mr:
ib_dereg_mr(priv->mr);
@@ -254,8 +264,11 @@
clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);
}
- if (ib_destroy_cq(priv->cq))
- ipoib_warn(priv, "ib_cq_destroy failed\n");
+ if (ib_destroy_cq(priv->send_cq))
+ ipoib_warn(priv, "ib_cq_destroy (send) failed\n");
+
+ if (ib_destroy_cq(priv->recv_cq))
+ ipoib_warn(priv, "ib_cq_destroy (recv) failed\n");
ipoib_cm_dev_cleanup(dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
index 431fdea..1cdb5cf 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c
@@ -90,6 +90,9 @@
}
priv->max_ib_mtu = ppriv->max_ib_mtu;
+ /* MTU will be reset when mcast join happens */
+ priv->dev->mtu = IPOIB_UD_MTU(priv->max_ib_mtu);
+ priv->mcast_mtu = priv->admin_mtu = priv->dev->mtu;
set_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags);
priv->pkey = pkey;
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index be1b9fb..aeb58ca 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -473,13 +473,15 @@
stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */
stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
- stats->custom_length = 3;
+ stats->custom_length = 4;
strcpy(stats->custom[0].desc, "qp_tx_queue_full");
stats->custom[0].value = 0; /* TB iser_conn->qp_tx_queue_full; */
strcpy(stats->custom[1].desc, "fmr_map_not_avail");
stats->custom[1].value = 0; /* TB iser_conn->fmr_map_not_avail */;
strcpy(stats->custom[2].desc, "eh_abort_cnt");
stats->custom[2].value = conn->eh_abort_cnt;
+ strcpy(stats->custom[3].desc, "fmr_unalign_cnt");
+ stats->custom[3].value = conn->fmr_unalign_cnt;
}
static int
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 1ee867b..a8c1b30 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -71,6 +71,13 @@
#define iser_dbg(fmt, arg...) \
do { \
+ if (iser_debug_level > 1) \
+ printk(KERN_DEBUG PFX "%s:" fmt,\
+ __func__ , ## arg); \
+ } while (0)
+
+#define iser_warn(fmt, arg...) \
+ do { \
if (iser_debug_level > 0) \
printk(KERN_DEBUG PFX "%s:" fmt,\
__func__ , ## arg); \
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index 4a17743..cac50c4 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -334,8 +334,11 @@
struct scatterlist *sg;
int i;
+ if (iser_debug_level == 0)
+ return;
+
for_each_sg(sgl, sg, data->dma_nents, i)
- iser_err("sg[%d] dma_addr:0x%lX page:0x%p "
+ iser_warn("sg[%d] dma_addr:0x%lX page:0x%p "
"off:0x%x sz:0x%x dma_len:0x%x\n",
i, (unsigned long)ib_sg_dma_address(ibdev, sg),
sg_page(sg), sg->offset,
@@ -420,6 +423,7 @@
int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
enum iser_data_dir cmd_dir)
{
+ struct iscsi_conn *iscsi_conn = iser_ctask->iser_conn->iscsi_conn;
struct iser_conn *ib_conn = iser_ctask->iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
struct ib_device *ibdev = device->ib_device;
@@ -434,7 +438,8 @@
aligned_len = iser_data_buf_aligned_len(mem, ibdev);
if (aligned_len != mem->dma_nents) {
- iser_err("rdma alignment violation %d/%d aligned\n",
+ iscsi_conn->fmr_unalign_cnt++;
+ iser_warn("rdma alignment violation %d/%d aligned\n",
aligned_len, mem->size);
iser_data_buf_dump(mem, ibdev);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index f02c242..27006fc 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -898,30 +898,26 @@
{
struct proc_dir_entry *entry;
- proc_bus_input_dir = proc_mkdir("input", proc_bus);
+ proc_bus_input_dir = proc_mkdir("bus/input", NULL);
if (!proc_bus_input_dir)
return -ENOMEM;
proc_bus_input_dir->owner = THIS_MODULE;
- entry = create_proc_entry("devices", 0, proc_bus_input_dir);
+ entry = proc_create("devices", 0, proc_bus_input_dir,
+ &input_devices_fileops);
if (!entry)
goto fail1;
- entry->owner = THIS_MODULE;
- entry->proc_fops = &input_devices_fileops;
-
- entry = create_proc_entry("handlers", 0, proc_bus_input_dir);
+ entry = proc_create("handlers", 0, proc_bus_input_dir,
+ &input_handlers_fileops);
if (!entry)
goto fail2;
- entry->owner = THIS_MODULE;
- entry->proc_fops = &input_handlers_fileops;
-
return 0;
fail2: remove_proc_entry("devices", proc_bus_input_dir);
- fail1: remove_proc_entry("input", proc_bus);
+ fail1: remove_proc_entry("bus/input", NULL);
return -ENOMEM;
}
@@ -929,7 +925,7 @@
{
remove_proc_entry("devices", proc_bus_input_dir);
remove_proc_entry("handlers", proc_bus_input_dir);
- remove_proc_entry("input", proc_bus);
+ remove_proc_entry("bus/input", NULL);
}
#else /* !CONFIG_PROC_FS */
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index e1a3a79..7ff71ba 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -46,7 +46,7 @@
static int serport_serio_write(struct serio *serio, unsigned char data)
{
struct serport *serport = serio->port_data;
- return -(serport->tty->driver->write(serport->tty, &data, 1) != 1);
+ return -(serport->tty->ops->write(serport->tty, &data, 1) != 1);
}
static int serport_serio_open(struct serio *serio)
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index 1d759f6..55c1134 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -528,9 +528,9 @@
(aiptek->curSetting.pointerMode)) {
aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
} else {
- x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
- y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
- z = le16_to_cpu(get_unaligned((__le16 *) (data + 6)));
+ x = get_unaligned_le16(data + 1);
+ y = get_unaligned_le16(data + 3);
+ z = get_unaligned_le16(data + 6);
dv = (data[5] & 0x01) != 0 ? 1 : 0;
p = (data[5] & 0x02) != 0 ? 1 : 0;
@@ -613,8 +613,8 @@
(aiptek->curSetting.pointerMode)) {
aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
} else {
- x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
- y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
+ x = get_unaligned_le16(data + 1);
+ y = get_unaligned_le16(data + 3);
jitterable = data[5] & 0x1c;
@@ -679,7 +679,7 @@
pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1;
- z = le16_to_cpu(get_unaligned((__le16 *) (data + 4)));
+ z = get_unaligned_le16(data + 4);
if (dv) {
/* If the selected tool changed, reset the old
@@ -757,7 +757,7 @@
* hat switches (which just so happen to be the macroKeys.)
*/
else if (data[0] == 6) {
- macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
+ macro = get_unaligned_le16(data + 1);
if (macro > 0) {
input_report_key(inputdev, macroKeyEvents[macro - 1],
0);
@@ -952,7 +952,7 @@
buf[0], buf[1], buf[2]);
ret = -EIO;
} else {
- ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1)));
+ ret = get_unaligned_le16(buf + 1);
}
kfree(buf);
return ret;
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index f66ca21..c5a8661 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -245,11 +245,11 @@
data = report[i];
break;
case 2:
- data16 = le16_to_cpu(get_unaligned((__le16 *)&report[i]));
+ data16 = get_unaligned_le16(&report[i]);
break;
case 3:
size = 4;
- data32 = le32_to_cpu(get_unaligned((__le32 *)&report[i]));
+ data32 = get_unaligned_le32(&report[i]);
break;
}
@@ -695,10 +695,10 @@
/* Fall thru */
case 1:
/* All reports have X and Y coords in the same place */
- val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
+ val = get_unaligned_le16(&device->buffer[1]);
input_report_abs(inputdev, ABS_X, val);
- val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
+ val = get_unaligned_le16(&device->buffer[3]);
input_report_abs(inputdev, ABS_Y, val);
/* Ditto for proximity bit */
@@ -762,7 +762,7 @@
le_buffer[1] = (u8)(device->buffer[4] >> 1);
le_buffer[1] |= (u8)((device->buffer[5] & 0x1) << 7);
- val = le16_to_cpu(get_unaligned((__le16 *)le_buffer));
+ val = get_unaligned_le16(le_buffer);
input_report_abs(inputdev, ABS_Y, val);
/*
@@ -772,10 +772,10 @@
buttonbyte = device->buffer[5] >> 1;
} else {
- val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[1]));
+ val = get_unaligned_le16(&device->buffer[1]);
input_report_abs(inputdev, ABS_X, val);
- val = le16_to_cpu(get_unaligned((__le16 *)&device->buffer[3]));
+ val = get_unaligned_le16(&device->buffer[3]);
input_report_abs(inputdev, ABS_Y, val);
buttonbyte = device->buffer[5];
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index 1182fc1..f23f5a9 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -63,8 +63,8 @@
goto exit;
}
- kbtab->x = le16_to_cpu(get_unaligned((__le16 *) &data[1]));
- kbtab->y = le16_to_cpu(get_unaligned((__le16 *) &data[3]));
+ kbtab->x = get_unaligned_le16(&data[1]);
+ kbtab->y = get_unaligned_le16(&data[3]);
kbtab->pressure = (data[5]);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 24c6b7c..6ca0bb9 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1111,11 +1111,12 @@
return count;
}
-static void capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
+static int capinc_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
struct capiminor *mp = (struct capiminor *)tty->driver_data;
struct sk_buff *skb;
unsigned long flags;
+ int ret = 1;
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_put_char(%u)\n", ch);
@@ -1125,7 +1126,7 @@
#ifdef _DEBUG_TTYFUNCS
printk(KERN_DEBUG "capinc_tty_put_char: mp or mp->ncci NULL\n");
#endif
- return;
+ return 0;
}
spin_lock_irqsave(&workaround_lock, flags);
@@ -1134,7 +1135,7 @@
if (skb_tailroom(skb) > 0) {
*(skb_put(skb, 1)) = ch;
spin_unlock_irqrestore(&workaround_lock, flags);
- return;
+ return 1;
}
mp->ttyskb = NULL;
skb_queue_tail(&mp->outqueue, skb);
@@ -1148,8 +1149,10 @@
mp->ttyskb = skb;
} else {
printk(KERN_ERR "capinc_put_char: char %u lost\n", ch);
+ ret = 0;
}
spin_unlock_irqrestore(&workaround_lock, flags);
+ return ret;
}
static void capinc_tty_flush_chars(struct tty_struct *tty)
diff --git a/drivers/isdn/capi/kcapi_proc.c b/drivers/isdn/capi/kcapi_proc.c
index 845a797..c29208b 100644
--- a/drivers/isdn/capi/kcapi_proc.c
+++ b/drivers/isdn/capi/kcapi_proc.c
@@ -114,6 +114,7 @@
}
static const struct file_operations proc_controller_ops = {
+ .owner = THIS_MODULE,
.open = seq_controller_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -121,6 +122,7 @@
};
static const struct file_operations proc_contrstats_ops = {
+ .owner = THIS_MODULE,
.open = seq_contrstats_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -219,6 +221,7 @@
}
static const struct file_operations proc_applications_ops = {
+ .owner = THIS_MODULE,
.open = seq_applications_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -226,21 +229,13 @@
};
static const struct file_operations proc_applstats_ops = {
+ .owner = THIS_MODULE,
.open = seq_applstats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
-static void
-create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
-{
- struct proc_dir_entry *entry;
- entry = create_proc_entry(name, mode, NULL);
- if (entry)
- entry->proc_fops = f;
-}
-
// ---------------------------------------------------------------------------
static void *capi_driver_start(struct seq_file *seq, loff_t *pos)
@@ -283,6 +278,7 @@
}
static const struct file_operations proc_driver_ops = {
+ .owner = THIS_MODULE,
.open = seq_capi_driver_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -296,11 +292,11 @@
{
proc_mkdir("capi", NULL);
proc_mkdir("capi/controllers", NULL);
- create_seq_entry("capi/controller", 0, &proc_controller_ops);
- create_seq_entry("capi/contrstats", 0, &proc_contrstats_ops);
- create_seq_entry("capi/applications", 0, &proc_applications_ops);
- create_seq_entry("capi/applstats", 0, &proc_applstats_ops);
- create_seq_entry("capi/driver", 0, &proc_driver_ops);
+ proc_create("capi/controller", 0, NULL, &proc_controller_ops);
+ proc_create("capi/contrstats", 0, NULL, &proc_contrstats_ops);
+ proc_create("capi/applications", 0, NULL, &proc_applications_ops);
+ proc_create("capi/applstats", 0, NULL, &proc_applstats_ops);
+ proc_create("capi/driver", 0, NULL, &proc_driver_ops);
}
void __exit
diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c
index 4fd4c468..8b256a6 100644
--- a/drivers/isdn/divert/divert_procfs.c
+++ b/drivers/isdn/divert/divert_procfs.c
@@ -288,13 +288,12 @@
isdn_proc_entry = proc_mkdir("isdn", init_net.proc_net);
if (!isdn_proc_entry)
return (-1);
- isdn_divert_entry = create_proc_entry("divert", S_IFREG | S_IRUGO, isdn_proc_entry);
+ isdn_divert_entry = proc_create("divert", S_IFREG | S_IRUGO,
+ isdn_proc_entry, &isdn_fops);
if (!isdn_divert_entry) {
remove_proc_entry("isdn", init_net.proc_net);
return (-1);
}
- isdn_divert_entry->proc_fops = &isdn_fops;
- isdn_divert_entry->owner = THIS_MODULE;
#endif /* CONFIG_PROC_FS */
return (0);
diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c
index fceeb1d..45d1ee9 100644
--- a/drivers/isdn/gigaset/ser-gigaset.c
+++ b/drivers/isdn/gigaset/ser-gigaset.c
@@ -68,10 +68,10 @@
struct tty_struct *tty = cs->hw.ser->tty;
struct bc_state *bcs = &cs->bcs[0]; /* only one channel */
struct sk_buff *skb = bcs->tx_skb;
- int sent;
+ int sent = -EOPNOTSUPP;
if (!tty || !tty->driver || !skb)
- return -EFAULT;
+ return -EINVAL;
if (!skb->len) {
dev_kfree_skb_any(skb);
@@ -80,7 +80,8 @@
}
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, skb->data, skb->len);
+ if (tty->ops->write)
+ sent = tty->ops->write(tty, skb->data, skb->len);
gig_dbg(DEBUG_OUTPUT, "write_modem: sent %d", sent);
if (sent < 0) {
/* error */
@@ -120,7 +121,7 @@
if (cb->len) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, cb->buf + cb->offset, cb->len);
+ sent = tty->ops->write(tty, cb->buf + cb->offset, cb->len);
if (sent < 0) {
/* error */
gig_dbg(DEBUG_OUTPUT, "send_cb: write error %d", sent);
@@ -440,14 +441,14 @@
struct tty_struct *tty = cs->hw.ser->tty;
unsigned int set, clear;
- if (!tty || !tty->driver || !tty->driver->tiocmset)
- return -EFAULT;
+ if (!tty || !tty->driver || !tty->ops->tiocmset)
+ return -EINVAL;
set = new_state & ~old_state;
clear = old_state & ~new_state;
if (!set && !clear)
return 0;
gig_dbg(DEBUG_IF, "tiocmset set %x clear %x", set, clear);
- return tty->driver->tiocmset(tty, NULL, set, clear);
+ return tty->ops->tiocmset(tty, NULL, set, clear);
}
static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c
index 0632a26..fae8958 100644
--- a/drivers/isdn/hardware/eicon/divasproc.c
+++ b/drivers/isdn/hardware/eicon/divasproc.c
@@ -125,15 +125,11 @@
int create_divas_proc(void)
{
- divas_proc_entry = create_proc_entry(divas_proc_name,
- S_IFREG | S_IRUGO,
- proc_net_eicon);
+ proc_create(divas_proc_name, S_IFREG | S_IRUGO, proc_net_eicon,
+ &divas_fops);
if (!divas_proc_entry)
return (0);
- divas_proc_entry->proc_fops = &divas_fops;
- divas_proc_entry->owner = THIS_MODULE;
-
return (1);
}
diff --git a/drivers/isdn/hysdn/hysdn_procconf.c b/drivers/isdn/hysdn/hysdn_procconf.c
index 27d890b..15906d0 100644
--- a/drivers/isdn/hysdn/hysdn_procconf.c
+++ b/drivers/isdn/hysdn/hysdn_procconf.c
@@ -370,6 +370,7 @@
/******************************************************/
static const struct file_operations conf_fops =
{
+ .owner = THIS_MODULE,
.llseek = no_llseek,
.read = hysdn_conf_read,
.write = hysdn_conf_write,
@@ -402,11 +403,10 @@
while (card) {
sprintf(conf_name, "%s%d", PROC_CONF_BASENAME, card->myid);
- if ((card->procconf = (void *) create_proc_entry(conf_name,
- S_IFREG | S_IRUGO | S_IWUSR,
- hysdn_proc_entry)) != NULL) {
- ((struct proc_dir_entry *) card->procconf)->proc_fops = &conf_fops;
- ((struct proc_dir_entry *) card->procconf)->owner = THIS_MODULE;
+ if ((card->procconf = (void *) proc_create(conf_name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ hysdn_proc_entry,
+ &conf_fops)) != NULL) {
hysdn_proclog_init(card); /* init the log file entry */
}
card = card->next; /* next entry */
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 27b3991..8991d2c 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -380,6 +380,7 @@
/**************************************************/
static const struct file_operations log_fops =
{
+ .owner = THIS_MODULE,
.llseek = no_llseek,
.read = hysdn_log_read,
.write = hysdn_log_write,
@@ -402,10 +403,9 @@
if ((pd = kzalloc(sizeof(struct procdata), GFP_KERNEL)) != NULL) {
sprintf(pd->log_name, "%s%d", PROC_LOG_BASENAME, card->myid);
- if ((pd->log = create_proc_entry(pd->log_name, S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry)) != NULL) {
- pd->log->proc_fops = &log_fops;
- pd->log->owner = THIS_MODULE;
- }
+ pd->log = proc_create(pd->log_name,
+ S_IFREG | S_IRUGO | S_IWUSR, hysdn_proc_entry,
+ &log_fops);
init_waitqueue_head(&(pd->rd_queue));
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 8af0df1..1a2222c 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1352,12 +1352,14 @@
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
+ lock_kernel();
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCMGET\n", info->line);
#endif
control = info->mcr;
status = info->msr;
+ unlock_kernel();
return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
| ((status & UART_MSR_DCD) ? TIOCM_CAR : 0)
@@ -1381,6 +1383,7 @@
printk(KERN_DEBUG "ttyI%d ioctl TIOCMxxx: %x %x\n", info->line, set, clear);
#endif
+ lock_kernel();
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
if (set & TIOCM_DTR) {
@@ -1402,6 +1405,7 @@
isdn_tty_modem_hup(info, 1);
}
}
+ unlock_kernel();
return 0;
}
@@ -1435,21 +1439,6 @@
return retval;
tty_wait_until_sent(tty, 0);
return 0;
- case TIOCGSOFTCAR:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCGSOFTCAR\n", info->line);
-#endif
- return put_user(C_CLOCAL(tty) ? 1 : 0, (ulong __user *) arg);
- case TIOCSSOFTCAR:
-#ifdef ISDN_DEBUG_MODEM_IOCTL
- printk(KERN_DEBUG "ttyI%d ioctl TIOCSSOFTCAR\n", info->line);
-#endif
- if (get_user(arg, (ulong __user *) arg))
- return -EFAULT;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCSERGETLSR: /* Get line status register */
#ifdef ISDN_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "ttyI%d ioctl TIOCSERGETLSR\n", info->line);
@@ -1472,13 +1461,14 @@
if (!old_termios)
isdn_tty_change_speed(info);
else {
- if (tty->termios->c_cflag == old_termios->c_cflag)
+ if (tty->termios->c_cflag == old_termios->c_cflag &&
+ tty->termios->c_ispeed == old_termios->c_ispeed &&
+ tty->termios->c_ospeed == old_termios->c_ospeed)
return;
isdn_tty_change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
+ !(tty->termios->c_cflag & CRTSCTS))
tty->hw_stopped = 0;
- }
}
}
@@ -1718,9 +1708,7 @@
}
dev->modempoll--;
isdn_tty_shutdown(info);
-
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ isdn_tty_flush_buffer(tty);
tty_ldisc_flush(tty);
info->tty = NULL;
info->ncarrier = 0;
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index ac05a92..b3c54be 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -105,7 +105,7 @@
led_cdev->dev = device_create(leds_class, parent, 0, "%s",
led_cdev->name);
- if (unlikely(IS_ERR(led_cdev->dev)))
+ if (IS_ERR(led_cdev->dev))
return PTR_ERR(led_cdev->dev);
dev_set_drvdata(led_cdev->dev, led_cdev);
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index 2bc9bf7..8080249 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -85,27 +85,34 @@
+ desc->config_len;
}
-/* This tests (and acknowleges) a feature bit. */
-static bool lg_feature(struct virtio_device *vdev, unsigned fbit)
+/* This gets the device's feature bits. */
+static u32 lg_get_features(struct virtio_device *vdev)
{
+ unsigned int i;
+ u32 features = 0;
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
- u8 *features;
+ u8 *in_features = lg_features(desc);
- /* Obviously if they ask for a feature off the end of our feature
- * bitmap, it's not set. */
- if (fbit / 8 > desc->feature_len)
- return false;
+ /* We do this the slow but generic way. */
+ for (i = 0; i < min(desc->feature_len * 8, 32); i++)
+ if (in_features[i / 8] & (1 << (i % 8)))
+ features |= (1 << i);
- /* The feature bitmap comes after the virtqueues. */
- features = lg_features(desc);
- if (!(features[fbit / 8] & (1 << (fbit % 8))))
- return false;
+ return features;
+}
- /* We set the matching bit in the other half of the bitmap to tell the
- * Host we want to use this feature. We don't use this yet, but we
- * could in future. */
- features[desc->feature_len + fbit / 8] |= (1 << (fbit % 8));
- return true;
+static void lg_set_features(struct virtio_device *vdev, u32 features)
+{
+ unsigned int i;
+ struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
+ /* Second half of bitmap is features we accept. */
+ u8 *out_features = lg_features(desc) + desc->feature_len;
+
+ memset(out_features, 0, desc->feature_len);
+ for (i = 0; i < min(desc->feature_len * 8, 32); i++) {
+ if (features & (1 << i))
+ out_features[i / 8] |= (1 << (i % 8));
+ }
}
/* Once they've found a field, getting a copy of it is easy. */
@@ -137,22 +144,28 @@
return to_lgdev(vdev)->desc->status;
}
-static void lg_set_status(struct virtio_device *vdev, u8 status)
-{
- BUG_ON(!status);
- to_lgdev(vdev)->desc->status = status;
-}
-
-/* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor
- * address of the device. The Host will zero the status and all the
- * features. */
-static void lg_reset(struct virtio_device *vdev)
+/* To notify on status updates, we (ab)use the NOTIFY hypercall, with the
+ * descriptor address of the device. A zero status means "reset". */
+static void set_status(struct virtio_device *vdev, u8 status)
{
unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
+ /* We set the status. */
+ to_lgdev(vdev)->desc->status = status;
hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0);
}
+static void lg_set_status(struct virtio_device *vdev, u8 status)
+{
+ BUG_ON(!status);
+ set_status(vdev, status);
+}
+
+static void lg_reset(struct virtio_device *vdev)
+{
+ set_status(vdev, 0);
+}
+
/*
* Virtqueues
*
@@ -286,7 +299,8 @@
/* The ops structure which hooks everything together. */
static struct virtio_config_ops lguest_config_ops = {
- .feature = lg_feature,
+ .get_features = lg_get_features,
+ .set_features = lg_set_features,
.get = lg_get,
.set = lg_set,
.get_status = lg_get_status,
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 645e6e0..e73a000 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -102,7 +102,7 @@
static int lg_cpu_start(struct lg_cpu *cpu, unsigned id, unsigned long start_ip)
{
/* We have a limited number the number of CPUs in the lguest struct. */
- if (id >= NR_CPUS)
+ if (id >= ARRAY_SIZE(cpu->lg->cpus))
return -EINVAL;
/* Set up this CPU's id, and pointer back to the lguest struct. */
@@ -251,8 +251,6 @@
if (!lg || (cpu_id >= lg->nr_cpus))
return -EINVAL;
cpu = &lg->cpus[cpu_id];
- if (!cpu)
- return -EINVAL;
/* Once the Guest is dead, you can only read() why it died. */
if (lg->dead)
diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c
index 0c7bfa7..494f0c2 100644
--- a/drivers/mca/mca-legacy.c
+++ b/drivers/mca/mca-legacy.c
@@ -282,24 +282,6 @@
EXPORT_SYMBOL(mca_set_adapter_name);
/**
- * mca_is_adapter_used - check if claimed by driver
- * @slot: slot to check
- *
- * Returns 1 if the slot has been claimed by a driver
- */
-
-int mca_is_adapter_used(int slot)
-{
- struct mca_device *mca_dev = mca_find_device_by_slot(slot);
-
- if(!mca_dev)
- return 0;
-
- return mca_device_claimed(mca_dev);
-}
-EXPORT_SYMBOL(mca_is_adapter_used);
-
-/**
* mca_mark_as_used - claim an MCA device
* @slot: slot to claim
* FIXME: should we make this threadsafe
diff --git a/drivers/mca/mca-proc.c b/drivers/mca/mca-proc.c
index 33d5e08..81ea0d3 100644
--- a/drivers/mca/mca-proc.c
+++ b/drivers/mca/mca-proc.c
@@ -183,7 +183,7 @@
struct proc_dir_entry* node = NULL;
struct mca_device *mca_dev;
- proc_mca = proc_mkdir("mca", &proc_root);
+ proc_mca = proc_mkdir("mca", NULL);
create_proc_read_entry("pos",0,proc_mca,get_mca_info,NULL);
create_proc_read_entry("machine",0,proc_mca,get_mca_machine_info,NULL);
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index 6b91b9a..3ea5ad4 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -110,8 +110,6 @@
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;
- memset(&rq->cmd, 0, BLK_MAX_CDB);
-
rq->timeout = EMC_FAILOVER_TIMEOUT;
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
diff --git a/drivers/md/dm-mpath-hp-sw.c b/drivers/md/dm-mpath-hp-sw.c
index 204bf42..b63a0ab 100644
--- a/drivers/md/dm-mpath-hp-sw.c
+++ b/drivers/md/dm-mpath-hp-sw.c
@@ -137,7 +137,6 @@
req->sense = h->sense;
memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE);
- memset(&req->cmd, 0, BLK_MAX_CDB);
req->cmd[0] = START_STOP;
req->cmd[4] = 1;
req->cmd_len = COMMAND_SIZE(req->cmd[0]);
diff --git a/drivers/md/dm-mpath-rdac.c b/drivers/md/dm-mpath-rdac.c
index e04eb5c..95e7773 100644
--- a/drivers/md/dm-mpath-rdac.c
+++ b/drivers/md/dm-mpath-rdac.c
@@ -284,7 +284,6 @@
return NULL;
}
- memset(&rq->cmd, 0, BLK_MAX_CDB);
rq->sense = h->sense;
memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE);
rq->sense_len = 0;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 51be533..94116ea 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -873,10 +873,11 @@
q->max_hw_sectors = t->limits.max_hw_sectors;
q->seg_boundary_mask = t->limits.seg_boundary_mask;
q->bounce_pfn = t->limits.bounce_pfn;
+
if (t->limits.no_cluster)
- q->queue_flags &= ~(1 << QUEUE_FLAG_CLUSTER);
+ queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
else
- q->queue_flags |= (1 << QUEUE_FLAG_CLUSTER);
+ queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, q);
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 87620b7..83eb78b 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -276,13 +276,15 @@
init_waitqueue_head(&new->sb_wait);
new->reshape_position = MaxSector;
new->resync_max = MaxSector;
+ new->level = LEVEL_NONE;
new->queue = blk_alloc_queue(GFP_KERNEL);
if (!new->queue) {
kfree(new);
return NULL;
}
- set_bit(QUEUE_FLAG_CLUSTER, &new->queue->queue_flags);
+ /* Can be unlocked because the queue is new: no concurrency */
+ queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, new->queue);
blk_queue_make_request(new->queue, md_fail_request);
@@ -1368,6 +1370,11 @@
MD_BUG();
return -EINVAL;
}
+
+ /* prevent duplicates */
+ if (find_rdev(mddev, rdev->bdev->bd_dev))
+ return -EEXIST;
+
/* make sure rdev->size exceeds mddev->size */
if (rdev->size && (mddev->size == 0 || rdev->size < mddev->size)) {
if (mddev->pers) {
@@ -1651,6 +1658,8 @@
int sync_req;
int nospares = 0;
+ if (mddev->external)
+ return;
repeat:
spin_lock_irq(&mddev->write_lock);
@@ -1819,6 +1828,10 @@
len += sprintf(page+len, "%swrite_mostly",sep);
sep = ",";
}
+ if (test_bit(Blocked, &rdev->flags)) {
+ len += sprintf(page+len, "%sblocked", sep);
+ sep = ",";
+ }
if (!test_bit(Faulty, &rdev->flags) &&
!test_bit(In_sync, &rdev->flags)) {
len += sprintf(page+len, "%sspare", sep);
@@ -1835,6 +1848,8 @@
* remove - disconnects the device
* writemostly - sets write_mostly
* -writemostly - clears write_mostly
+ * blocked - sets the Blocked flag
+ * -blocked - clears the Blocked flag
*/
int err = -EINVAL;
if (cmd_match(buf, "faulty") && rdev->mddev->pers) {
@@ -1857,6 +1872,16 @@
} else if (cmd_match(buf, "-writemostly")) {
clear_bit(WriteMostly, &rdev->flags);
err = 0;
+ } else if (cmd_match(buf, "blocked")) {
+ set_bit(Blocked, &rdev->flags);
+ err = 0;
+ } else if (cmd_match(buf, "-blocked")) {
+ clear_bit(Blocked, &rdev->flags);
+ wake_up(&rdev->blocked_wait);
+ set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery);
+ md_wakeup_thread(rdev->mddev->thread);
+
+ err = 0;
}
return err ? err : len;
}
@@ -2096,7 +2121,7 @@
rv = -EBUSY;
else
rv = entry->store(rdev, page, length);
- mddev_unlock(rdev->mddev);
+ mddev_unlock(mddev);
}
return rv;
}
@@ -2185,7 +2210,9 @@
goto abort_free;
}
}
+
INIT_LIST_HEAD(&rdev->same_set);
+ init_waitqueue_head(&rdev->blocked_wait);
return rdev;
@@ -2456,7 +2483,6 @@
static ssize_t
resync_start_store(mddev_t *mddev, const char *buf, size_t len)
{
- /* can only set chunk_size if array is not yet active */
char *e;
unsigned long long n = simple_strtoull(buf, &e, 10);
@@ -2590,15 +2616,20 @@
err = do_md_stop(mddev, 1);
else {
mddev->ro = 1;
+ set_disk_ro(mddev->gendisk, 1);
err = do_md_run(mddev);
}
break;
case read_auto:
- /* stopping an active array */
if (mddev->pers) {
- err = do_md_stop(mddev, 1);
- if (err == 0)
- mddev->ro = 2; /* FIXME mark devices writable */
+ if (mddev->ro != 1)
+ err = do_md_stop(mddev, 1);
+ else
+ err = restart_array(mddev);
+ if (err == 0) {
+ mddev->ro = 2;
+ set_disk_ro(mddev->gendisk, 0);
+ }
} else {
mddev->ro = 2;
err = do_md_run(mddev);
@@ -2611,6 +2642,8 @@
if (atomic_read(&mddev->writes_pending) == 0) {
if (mddev->in_sync == 0) {
mddev->in_sync = 1;
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
if (mddev->persistent)
set_bit(MD_CHANGE_CLEAN,
&mddev->flags);
@@ -2634,6 +2667,7 @@
err = 0;
} else {
mddev->ro = 0;
+ set_disk_ro(mddev->gendisk, 0);
err = do_md_run(mddev);
}
break;
@@ -3711,6 +3745,30 @@
mddev->reshape_position = MaxSector;
mddev->external = 0;
mddev->persistent = 0;
+ mddev->level = LEVEL_NONE;
+ mddev->clevel[0] = 0;
+ mddev->flags = 0;
+ mddev->ro = 0;
+ mddev->metadata_type[0] = 0;
+ mddev->chunk_size = 0;
+ mddev->ctime = mddev->utime = 0;
+ mddev->layout = 0;
+ mddev->max_disks = 0;
+ mddev->events = 0;
+ mddev->delta_disks = 0;
+ mddev->new_level = LEVEL_NONE;
+ mddev->new_layout = 0;
+ mddev->new_chunk = 0;
+ mddev->curr_resync = 0;
+ mddev->resync_mismatches = 0;
+ mddev->suspend_lo = mddev->suspend_hi = 0;
+ mddev->sync_speed_min = mddev->sync_speed_max = 0;
+ mddev->recovery = 0;
+ mddev->in_sync = 0;
+ mddev->changed = 0;
+ mddev->degraded = 0;
+ mddev->barriers_work = 0;
+ mddev->safemode = 0;
} else if (mddev->pers)
printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -4918,6 +4976,9 @@
if (!rdev || test_bit(Faulty, &rdev->flags))
return;
+
+ if (mddev->external)
+ set_bit(Blocked, &rdev->flags);
/*
dprintk("md_error dev:%s, rdev:(%d:%d), (caller: %p,%p,%p,%p).\n",
mdname(mddev),
@@ -5364,6 +5425,8 @@
md_wakeup_thread(mddev->sync_thread);
}
atomic_inc(&mddev->writes_pending);
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
if (mddev->in_sync) {
spin_lock_irq(&mddev->write_lock);
if (mddev->in_sync) {
@@ -5718,7 +5781,7 @@
rdev_for_each(rdev, rtmp, mddev)
if (rdev->raid_disk >= 0 &&
- !mddev->external &&
+ !test_bit(Blocked, &rdev->flags) &&
(test_bit(Faulty, &rdev->flags) ||
! test_bit(In_sync, &rdev->flags)) &&
atomic_read(&rdev->nr_pending)==0) {
@@ -5788,7 +5851,7 @@
return;
if (signal_pending(current)) {
- if (mddev->pers->sync_request) {
+ if (mddev->pers->sync_request && !mddev->external) {
printk(KERN_INFO "md: %s in immediate safe mode\n",
mdname(mddev));
mddev->safemode = 2;
@@ -5800,7 +5863,7 @@
(mddev->flags && !mddev->external) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
- (mddev->safemode == 1) ||
+ (mddev->external == 0 && mddev->safemode == 1) ||
(mddev->safemode == 2 && ! atomic_read(&mddev->writes_pending)
&& !mddev->in_sync && mddev->recovery_cp == MaxSector)
))
@@ -5809,16 +5872,20 @@
if (mddev_trylock(mddev)) {
int spares = 0;
- spin_lock_irq(&mddev->write_lock);
- if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
- !mddev->in_sync && mddev->recovery_cp == MaxSector) {
- mddev->in_sync = 1;
- if (mddev->persistent)
- set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ if (!mddev->external) {
+ spin_lock_irq(&mddev->write_lock);
+ if (mddev->safemode &&
+ !atomic_read(&mddev->writes_pending) &&
+ !mddev->in_sync &&
+ mddev->recovery_cp == MaxSector) {
+ mddev->in_sync = 1;
+ if (mddev->persistent)
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ }
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
+ spin_unlock_irq(&mddev->write_lock);
}
- if (mddev->safemode == 1)
- mddev->safemode = 0;
- spin_unlock_irq(&mddev->write_lock);
if (mddev->flags)
md_update_sb(mddev, 0);
@@ -5913,6 +5980,16 @@
}
}
+void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev)
+{
+ sysfs_notify(&rdev->kobj, NULL, "state");
+ wait_event_timeout(rdev->blocked_wait,
+ !test_bit(Blocked, &rdev->flags),
+ msecs_to_jiffies(5000));
+ rdev_dec_pending(rdev, mddev);
+}
+EXPORT_SYMBOL(md_wait_for_blocked_rdev);
+
static int md_notify_reboot(struct notifier_block *this,
unsigned long code, void *x)
{
@@ -5947,13 +6024,9 @@
static void md_geninit(void)
{
- struct proc_dir_entry *p;
-
dprintk("md: sizeof(mdp_super_t) = %d\n", (int)sizeof(mdp_super_t));
- p = create_proc_entry("mdstat", S_IRUGO, NULL);
- if (p)
- p->proc_fops = &md_seq_fops;
+ proc_create("mdstat", S_IRUGO, NULL, &md_seq_fops);
}
static int __init md_init(void)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 9fd473a..6778b7c 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -773,7 +773,6 @@
r1bio_t *r1_bio;
struct bio *read_bio;
int i, targets = 0, disks;
- mdk_rdev_t *rdev;
struct bitmap *bitmap = mddev->bitmap;
unsigned long flags;
struct bio_list bl;
@@ -781,6 +780,7 @@
const int rw = bio_data_dir(bio);
const int do_sync = bio_sync(bio);
int do_barriers;
+ mdk_rdev_t *blocked_rdev;
/*
* Register the new request and wait if the reconstruction
@@ -862,10 +862,17 @@
first = 0;
}
#endif
+ retry_write:
+ blocked_rdev = NULL;
rcu_read_lock();
for (i = 0; i < disks; i++) {
- if ((rdev=rcu_dereference(conf->mirrors[i].rdev)) != NULL &&
- !test_bit(Faulty, &rdev->flags)) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ atomic_inc(&rdev->nr_pending);
+ blocked_rdev = rdev;
+ break;
+ }
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
if (test_bit(Faulty, &rdev->flags)) {
rdev_dec_pending(rdev, mddev);
@@ -878,6 +885,20 @@
}
rcu_read_unlock();
+ if (unlikely(blocked_rdev)) {
+ /* Wait for this device to become unblocked */
+ int j;
+
+ for (j = 0; j < i; j++)
+ if (r1_bio->bios[j])
+ rdev_dec_pending(conf->mirrors[j].rdev, mddev);
+
+ allow_barrier(conf);
+ md_wait_for_blocked_rdev(blocked_rdev, mddev);
+ wait_barrier(conf);
+ goto retry_write;
+ }
+
BUG_ON(targets == 0); /* we never fail the last device */
if (targets < conf->raid_disks) {
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 1e96aa3..5938fa9 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -790,6 +790,7 @@
const int do_sync = bio_sync(bio);
struct bio_list bl;
unsigned long flags;
+ mdk_rdev_t *blocked_rdev;
if (unlikely(bio_barrier(bio))) {
bio_endio(bio, -EOPNOTSUPP);
@@ -879,17 +880,23 @@
/*
* WRITE:
*/
- /* first select target devices under spinlock and
+ /* first select target devices under rcu_lock and
* inc refcount on their rdev. Record them by setting
* bios[x] to bio
*/
raid10_find_phys(conf, r10_bio);
+ retry_write:
+ blocked_rdev = 0;
rcu_read_lock();
for (i = 0; i < conf->copies; i++) {
int d = r10_bio->devs[i].devnum;
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[d].rdev);
- if (rdev &&
- !test_bit(Faulty, &rdev->flags)) {
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ atomic_inc(&rdev->nr_pending);
+ blocked_rdev = rdev;
+ break;
+ }
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
atomic_inc(&rdev->nr_pending);
r10_bio->devs[i].bio = bio;
} else {
@@ -899,6 +906,22 @@
}
rcu_read_unlock();
+ if (unlikely(blocked_rdev)) {
+ /* Have to wait for this device to get unblocked, then retry */
+ int j;
+ int d;
+
+ for (j = 0; j < i; j++)
+ if (r10_bio->devs[j].bio) {
+ d = r10_bio->devs[j].devnum;
+ rdev_dec_pending(conf->mirrors[d].rdev, mddev);
+ }
+ allow_barrier(conf);
+ md_wait_for_blocked_rdev(blocked_rdev, mddev);
+ wait_barrier(conf);
+ goto retry_write;
+ }
+
atomic_set(&r10_bio->remaining, 0);
bio_list_init(&bl);
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 968daca..087eee0 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -2607,6 +2607,7 @@
}
}
+
/*
* handle_stripe - do things to a stripe.
*
@@ -2632,6 +2633,7 @@
struct stripe_head_state s;
struct r5dev *dev;
unsigned long pending = 0;
+ mdk_rdev_t *blocked_rdev = NULL;
memset(&s, 0, sizeof(s));
pr_debug("handling stripe %llu, state=%#lx cnt=%d, pd_idx=%d "
@@ -2691,6 +2693,11 @@
if (dev->written)
s.written++;
rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ blocked_rdev = rdev;
+ atomic_inc(&rdev->nr_pending);
+ break;
+ }
if (!rdev || !test_bit(In_sync, &rdev->flags)) {
/* The ReadError flag will just be confusing now */
clear_bit(R5_ReadError, &dev->flags);
@@ -2705,6 +2712,11 @@
}
rcu_read_unlock();
+ if (unlikely(blocked_rdev)) {
+ set_bit(STRIPE_HANDLE, &sh->state);
+ goto unlock;
+ }
+
if (s.to_fill && !test_and_set_bit(STRIPE_OP_BIOFILL, &sh->ops.pending))
sh->ops.count++;
@@ -2894,8 +2906,13 @@
if (sh->ops.count)
pending = get_stripe_work(sh);
+ unlock:
spin_unlock(&sh->lock);
+ /* wait for this device to become unblocked */
+ if (unlikely(blocked_rdev))
+ md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
+
if (pending)
raid5_run_ops(sh, pending);
@@ -2912,6 +2929,7 @@
struct stripe_head_state s;
struct r6_state r6s;
struct r5dev *dev, *pdev, *qdev;
+ mdk_rdev_t *blocked_rdev = NULL;
r6s.qd_idx = raid6_next_disk(pd_idx, disks);
pr_debug("handling stripe %llu, state=%#lx cnt=%d, "
@@ -2975,6 +2993,11 @@
if (dev->written)
s.written++;
rdev = rcu_dereference(conf->disks[i].rdev);
+ if (rdev && unlikely(test_bit(Blocked, &rdev->flags))) {
+ blocked_rdev = rdev;
+ atomic_inc(&rdev->nr_pending);
+ break;
+ }
if (!rdev || !test_bit(In_sync, &rdev->flags)) {
/* The ReadError flag will just be confusing now */
clear_bit(R5_ReadError, &dev->flags);
@@ -2989,6 +3012,11 @@
set_bit(R5_Insync, &dev->flags);
}
rcu_read_unlock();
+
+ if (unlikely(blocked_rdev)) {
+ set_bit(STRIPE_HANDLE, &sh->state);
+ goto unlock;
+ }
pr_debug("locked=%d uptodate=%d to_read=%d"
" to_write=%d failed=%d failed_num=%d,%d\n",
s.locked, s.uptodate, s.to_read, s.to_write, s.failed,
@@ -3094,8 +3122,13 @@
!test_bit(STRIPE_OP_COMPUTE_BLK, &sh->ops.pending))
handle_stripe_expansion(conf, sh, &r6s);
+ unlock:
spin_unlock(&sh->lock);
+ /* wait for this device to become unblocked */
+ if (unlikely(blocked_rdev))
+ md_wait_for_blocked_rdev(blocked_rdev, conf->mddev);
+
return_io(return_bi);
for (i=disks; i-- ;) {
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 128bb9c..ddf57e1 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -5,16 +5,20 @@
menu "Multimedia devices"
depends on HAS_IOMEM
+comment "Multimedia core support"
+
+#
+# V4L core and enabled API's
+#
+
config VIDEO_DEV
tristate "Video For Linux"
---help---
- Support for audio/video capture and overlay devices and FM radio
- cards. The exact capabilities of each device vary.
+ V4L core support for video capture and overlay devices, webcams and
+ AM/FM radio cards.
This kernel includes support for the new Video for Linux Two API,
- (V4L2) as well as the original system. Drivers and applications
- need to be rewritten to use V4L2, but drivers for popular cards
- and applications for most video capture functions already exist.
+ (V4L2).
Additional info and docs are available on the web at
<http://linuxtv.org>
@@ -36,8 +40,11 @@
default VIDEO_DEV && VIDEO_V4L2_COMMON
select VIDEO_V4L1_COMPAT
---help---
- Enables a compatibility API used by most V4L2 devices to allow
- its usage with legacy applications that supports only V4L1 api.
+ Enables drivers based on the legacy V4L1 API.
+
+ This api were developed to be used at Kernel 2.2 and 2.4, but
+ lacks support for several video standards. There are several
+ drivers at kernel that still depends on it.
If you are unsure as to whether this is required, answer Y.
@@ -46,9 +53,8 @@
depends on VIDEO_DEV
default VIDEO_DEV
---help---
- This api were developed to be used at Kernel 2.2 and 2.4, but
- lacks support for several video standards. There are several
- drivers at kernel that still depends on it.
+ Enables a compatibility API used by most V4L2 devices to allow
+ its usage with legacy applications that supports only V4L1 api.
Documentation for the original API is included in the file
<Documentation/video4linux/API.html>.
@@ -58,136 +64,58 @@
If you are unsure as to whether this is required, answer Y.
-config VIDEO_V4L2
- tristate
- depends on VIDEO_DEV && VIDEO_V4L2_COMMON
- default VIDEO_DEV && VIDEO_V4L2_COMMON
+#
+# DVB Core
+#
-config VIDEO_V4L1
+config DVB_CORE
+ tristate "DVB for Linux"
+ depends on NET && INET
+ select CRC32
+ help
+ DVB core utility functions for device handling, software fallbacks etc.
+
+ Enable this if you own a DVB/ATSC adapter and want to use it or if
+ you compile Linux for a digital SetTopBox.
+
+ Say Y when you have a DVB or an ATSC card and want to use it.
+
+ API specs and user tools are available from <http://www.linuxtv.org/>.
+
+ Please report problems regarding this support to the LinuxDVB
+ mailing list.
+
+ If unsure say N.
+
+config VIDEO_MEDIA
tristate
- depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
- default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+ default DVB_CORE || VIDEO_DEV
+ depends on DVB_CORE || VIDEO_DEV
+
+comment "Multimedia drivers"
+
+source "drivers/media/common/Kconfig"
+
+#
+# Tuner drivers for DVB and V4L
+#
+
+source "drivers/media/common/tuners/Kconfig"
+
+#
+# Video/Radio/Hybrid adapters
+#
source "drivers/media/video/Kconfig"
source "drivers/media/radio/Kconfig"
+#
+# DVB adapters
+#
+
source "drivers/media/dvb/Kconfig"
-source "drivers/media/common/Kconfig"
-
-config VIDEO_TUNER
- tristate
- depends on I2C
- select TUNER_XC2028 if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_MT20XX if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_TDA8290 if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_TEA5761 if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_TEA5767 if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_SIMPLE if !VIDEO_TUNER_CUSTOMIZE
- select TUNER_TDA9887 if !VIDEO_TUNER_CUSTOMIZE
-
-menuconfig VIDEO_TUNER_CUSTOMIZE
- bool "Customize analog tuner modules to build"
- depends on VIDEO_TUNER
- help
- This allows the user to deselect tuner drivers unnecessary
- for their hardware from the build. Use this option with care
- as deselecting tuner drivers which are in fact necessary will
- result in V4L devices which cannot be tuned due to lack of
- driver support
-
- If unsure say N.
-
-if VIDEO_TUNER_CUSTOMIZE
-
-config TUNER_XC2028
- tristate "XCeive xc2028/xc3028 tuners"
- depends on I2C && FW_LOADER
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for the xc2028/xc3028 tuners.
-
-config TUNER_MT20XX
- tristate "Microtune 2032 / 2050 tuners"
- depends on I2C
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for the MT2032 / MT2050 tuner.
-
-config TUNER_TDA8290
- tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
- depends on I2C
- select DVB_TDA827X
- select DVB_TDA18271
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for Philips TDA8290+8275(a) tuner.
-
-config TUNER_TEA5761
- tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
- depends on I2C && EXPERIMENTAL
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for the Philips TEA5761 radio tuner.
-
-config TUNER_TEA5767
- tristate "TEA 5767 radio tuner"
- depends on I2C
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for the Philips TEA5767 radio tuner.
-
-config TUNER_SIMPLE
- tristate "Simple tuner support"
- depends on I2C
- select TUNER_TDA9887
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for various simple tuners.
-
-config TUNER_TDA9887
- tristate "TDA 9885/6/7 analog IF demodulator"
- depends on I2C
- default m if VIDEO_TUNER_CUSTOMIZE
- help
- Say Y here to include support for Philips TDA9885/6/7
- analog IF demodulator.
-
-endif # VIDEO_TUNER_CUSTOMIZE
-
-config VIDEOBUF_GEN
- tristate
-
-config VIDEOBUF_DMA_SG
- depends on HAS_DMA
- select VIDEOBUF_GEN
- tristate
-
-config VIDEOBUF_VMALLOC
- select VIDEOBUF_GEN
- tristate
-
-config VIDEOBUF_DVB
- tristate
- select VIDEOBUF_GEN
- select VIDEOBUF_DMA_SG
-
-config VIDEO_BTCX
- tristate
-
-config VIDEO_IR_I2C
- tristate
-
-config VIDEO_IR
- tristate
- depends on INPUT
- select VIDEO_IR_I2C if I2C
-
-config VIDEO_TVEEPROM
- tristate
- depends on I2C
-
config DAB
boolean "DAB adapters"
---help---
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 7b8bb69..73f742c 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,10 +2,10 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := common/
-obj-y += video/
+obj-$(CONFIG_VIDEO_MEDIA) += common/
+
+# Since hybrid devices are here, should be compiled if DVB and/or V4L
+obj-$(CONFIG_VIDEO_MEDIA) += video/
+
obj-$(CONFIG_VIDEO_DEV) += radio/
obj-$(CONFIG_DVB_CORE) += dvb/
-ifeq ($(CONFIG_DVB_CORE),)
- obj-$(CONFIG_VIDEO_TUNER) += dvb/frontends/
-endif
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index 8e74482..351b98b 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -2,6 +2,7 @@
saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
ir-common-objs := ir-functions.o ir-keymaps.o
+obj-y += tuners/
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o
obj-$(CONFIG_VIDEO_IR) += ir-common.o
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
new file mode 100644
index 0000000..5be85ff
--- /dev/null
+++ b/drivers/media/common/tuners/Kconfig
@@ -0,0 +1,151 @@
+config MEDIA_ATTACH
+ bool "Load and attach frontend and tuner driver modules as needed"
+ depends on DVB_CORE
+ depends on MODULES
+ help
+ Remove the static dependency of DVB card drivers on all
+ frontend modules for all possible card variants. Instead,
+ allow the card drivers to only load the frontend modules
+ they require.
+
+ Also, tuner module will automatically load a tuner driver
+ when needed, for analog mode.
+
+ This saves several KBytes of memory.
+
+ Note: You will need module-init-tools v3.2 or later for this feature.
+
+ If unsure say Y.
+
+config MEDIA_TUNER
+ tristate
+ default DVB_CORE || VIDEO_DEV
+ depends on DVB_CORE || VIDEO_DEV
+ select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMIZE
+ select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMIZE
+
+menuconfig MEDIA_TUNER_CUSTOMIZE
+ bool "Customize analog and hybrid tuner modules to build"
+ depends on MEDIA_TUNER
+ help
+ This allows the user to deselect tuner drivers unnecessary
+ for their hardware from the build. Use this option with care
+ as deselecting tuner drivers which are in fact necessary will
+ result in V4L/DVB devices which cannot be tuned due to lack of
+ driver support
+
+ If unsure say N.
+
+if MEDIA_TUNER_CUSTOMIZE
+
+config MEDIA_TUNER_SIMPLE
+ tristate "Simple tuner support"
+ depends on I2C
+ select MEDIA_TUNER_TDA9887
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for various simple tuners.
+
+config MEDIA_TUNER_TDA8290
+ tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo"
+ depends on I2C
+ select MEDIA_TUNER_TDA827X
+ select MEDIA_TUNER_TDA18271
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for Philips TDA8290+8275(a) tuner.
+
+config MEDIA_TUNER_TDA827X
+ tristate "Philips TDA827X silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T silicon tuner module. Say Y when you want to support this tuner.
+
+config MEDIA_TUNER_TDA18271
+ tristate "NXP TDA18271 silicon tuner"
+ depends on I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A silicon tuner module. Say Y when you want to support this tuner.
+
+config MEDIA_TUNER_TDA9887
+ tristate "TDA 9885/6/7 analog IF demodulator"
+ depends on I2C
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for Philips TDA9885/6/7
+ analog IF demodulator.
+
+config MEDIA_TUNER_TEA5761
+ tristate "TEA 5761 radio tuner (EXPERIMENTAL)"
+ depends on I2C && EXPERIMENTAL
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the Philips TEA5761 radio tuner.
+
+config MEDIA_TUNER_TEA5767
+ tristate "TEA 5767 radio tuner"
+ depends on I2C
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the Philips TEA5767 radio tuner.
+
+config MEDIA_TUNER_MT20XX
+ tristate "Microtune 2032 / 2050 tuners"
+ depends on I2C
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the MT2032 / MT2050 tuner.
+
+config MEDIA_TUNER_MT2060
+ tristate "Microtune MT2060 silicon IF tuner"
+ depends on I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon IF tuner MT2060 from Microtune.
+
+config MEDIA_TUNER_MT2266
+ tristate "Microtune MT2266 silicon tuner"
+ depends on I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner MT2266 from Microtune.
+
+config MEDIA_TUNER_MT2131
+ tristate "Microtune MT2131 silicon tuner"
+ depends on I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon baseband tuner MT2131 from Microtune.
+
+config MEDIA_TUNER_QT1010
+ tristate "Quantek QT1010 silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon tuner QT1010 from Quantek.
+
+config MEDIA_TUNER_XC2028
+ tristate "XCeive xc2028/xc3028 tuners"
+ depends on I2C && FW_LOADER
+ default m if MEDIA_TUNER_CUSTOMIZE
+ help
+ Say Y here to include support for the xc2028/xc3028 tuners.
+
+config MEDIA_TUNER_XC5000
+ tristate "Xceive XC5000 silicon tuner"
+ depends on I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for the silicon tuner XC5000 from Xceive.
+ This device is only used inside a SiP called togther with a
+ demodulator for now.
+
+endif # MEDIA_TUNER_CUSTOMIZE
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
new file mode 100644
index 0000000..236d9932
--- /dev/null
+++ b/drivers/media/common/tuners/Makefile
@@ -0,0 +1,25 @@
+#
+# Makefile for common V4L/DVB tuners
+#
+
+tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o
+
+obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o
+obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o
+# tuner-types will be merged into tuner-simple, in the future
+obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o
+obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o
+obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o
+obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o
+obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o
+obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o
+obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o
+obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
+obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
+obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o
+obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/common/tuners/mt2060.c
similarity index 100%
rename from drivers/media/dvb/frontends/mt2060.c
rename to drivers/media/common/tuners/mt2060.c
diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/common/tuners/mt2060.h
similarity index 90%
rename from drivers/media/dvb/frontends/mt2060.h
rename to drivers/media/common/tuners/mt2060.h
index acba005..cb60caf 100644
--- a/drivers/media/dvb/frontends/mt2060.h
+++ b/drivers/media/common/tuners/mt2060.h
@@ -30,7 +30,7 @@
u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
};
-#if defined(CONFIG_DVB_TUNER_MT2060) || (defined(CONFIG_DVB_TUNER_MT2060_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE))
extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
#else
static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
@@ -38,6 +38,6 @@
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TUNER_MT2060
+#endif // CONFIG_MEDIA_TUNER_MT2060
#endif
diff --git a/drivers/media/dvb/frontends/mt2060_priv.h b/drivers/media/common/tuners/mt2060_priv.h
similarity index 100%
rename from drivers/media/dvb/frontends/mt2060_priv.h
rename to drivers/media/common/tuners/mt2060_priv.h
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/common/tuners/mt20xx.c
similarity index 100%
rename from drivers/media/video/mt20xx.c
rename to drivers/media/common/tuners/mt20xx.c
diff --git a/drivers/media/video/mt20xx.h b/drivers/media/common/tuners/mt20xx.h
similarity index 91%
rename from drivers/media/video/mt20xx.h
rename to drivers/media/common/tuners/mt20xx.h
index aa848e1..259553a 100644
--- a/drivers/media/video/mt20xx.h
+++ b/drivers/media/common/tuners/mt20xx.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_TUNER_MT20XX) || (defined(CONFIG_TUNER_MT20XX_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE))
extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
struct i2c_adapter* i2c_adap,
u8 i2c_addr);
diff --git a/drivers/media/dvb/frontends/mt2131.c b/drivers/media/common/tuners/mt2131.c
similarity index 100%
rename from drivers/media/dvb/frontends/mt2131.c
rename to drivers/media/common/tuners/mt2131.c
diff --git a/drivers/media/dvb/frontends/mt2131.h b/drivers/media/common/tuners/mt2131.h
similarity index 91%
rename from drivers/media/dvb/frontends/mt2131.h
rename to drivers/media/common/tuners/mt2131.h
index 606d857..cd8376f 100644
--- a/drivers/media/dvb/frontends/mt2131.h
+++ b/drivers/media/common/tuners/mt2131.h
@@ -30,7 +30,7 @@
u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
};
-#if defined(CONFIG_DVB_TUNER_MT2131) || (defined(CONFIG_DVB_TUNER_MT2131_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE))
extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct mt2131_config *cfg,
@@ -44,7 +44,7 @@
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif /* CONFIG_DVB_TUNER_MT2131 */
+#endif /* CONFIG_MEDIA_TUNER_MT2131 */
#endif /* __MT2131_H__ */
diff --git a/drivers/media/dvb/frontends/mt2131_priv.h b/drivers/media/common/tuners/mt2131_priv.h
similarity index 100%
rename from drivers/media/dvb/frontends/mt2131_priv.h
rename to drivers/media/common/tuners/mt2131_priv.h
diff --git a/drivers/media/dvb/frontends/mt2266.c b/drivers/media/common/tuners/mt2266.c
similarity index 100%
rename from drivers/media/dvb/frontends/mt2266.c
rename to drivers/media/common/tuners/mt2266.c
diff --git a/drivers/media/dvb/frontends/mt2266.h b/drivers/media/common/tuners/mt2266.h
similarity index 88%
rename from drivers/media/dvb/frontends/mt2266.h
rename to drivers/media/common/tuners/mt2266.h
index c5113ef..4d08388 100644
--- a/drivers/media/dvb/frontends/mt2266.h
+++ b/drivers/media/common/tuners/mt2266.h
@@ -24,7 +24,7 @@
u8 i2c_address;
};
-#if defined(CONFIG_DVB_TUNER_MT2266) || (defined(CONFIG_DVB_TUNER_MT2266_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE))
extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg);
#else
static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg)
@@ -32,6 +32,6 @@
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TUNER_MT2266
+#endif // CONFIG_MEDIA_TUNER_MT2266
#endif
diff --git a/drivers/media/dvb/frontends/qt1010.c b/drivers/media/common/tuners/qt1010.c
similarity index 100%
rename from drivers/media/dvb/frontends/qt1010.c
rename to drivers/media/common/tuners/qt1010.c
diff --git a/drivers/media/dvb/frontends/qt1010.h b/drivers/media/common/tuners/qt1010.h
similarity index 91%
rename from drivers/media/dvb/frontends/qt1010.h
rename to drivers/media/common/tuners/qt1010.h
index cff6a7c..807fb7b 100644
--- a/drivers/media/dvb/frontends/qt1010.h
+++ b/drivers/media/common/tuners/qt1010.h
@@ -36,7 +36,7 @@
* @param cfg tuner hw based configuration
* @return fe pointer on success, NULL on failure
*/
-#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE))
extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct qt1010_config *cfg);
@@ -48,6 +48,6 @@
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TUNER_QT1010
+#endif // CONFIG_MEDIA_TUNER_QT1010
#endif
diff --git a/drivers/media/dvb/frontends/qt1010_priv.h b/drivers/media/common/tuners/qt1010_priv.h
similarity index 100%
rename from drivers/media/dvb/frontends/qt1010_priv.h
rename to drivers/media/common/tuners/qt1010_priv.h
diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
similarity index 100%
rename from drivers/media/dvb/frontends/tda18271-common.c
rename to drivers/media/common/tuners/tda18271-common.c
diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
similarity index 100%
rename from drivers/media/dvb/frontends/tda18271-fe.c
rename to drivers/media/common/tuners/tda18271-fe.c
diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/common/tuners/tda18271-maps.c
similarity index 100%
rename from drivers/media/dvb/frontends/tda18271-tables.c
rename to drivers/media/common/tuners/tda18271-maps.c
diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/common/tuners/tda18271-priv.h
similarity index 100%
rename from drivers/media/dvb/frontends/tda18271-priv.h
rename to drivers/media/common/tuners/tda18271-priv.h
diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/common/tuners/tda18271.h
similarity index 95%
rename from drivers/media/dvb/frontends/tda18271.h
rename to drivers/media/common/tuners/tda18271.h
index 0e7af8d05..7db9831 100644
--- a/drivers/media/dvb/frontends/tda18271.h
+++ b/drivers/media/common/tuners/tda18271.h
@@ -81,7 +81,7 @@
unsigned int small_i2c:1;
};
-#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE))
extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
struct i2c_adapter *i2c,
struct tda18271_config *cfg);
diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/common/tuners/tda827x.c
similarity index 100%
rename from drivers/media/dvb/frontends/tda827x.c
rename to drivers/media/common/tuners/tda827x.c
diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/common/tuners/tda827x.h
similarity index 92%
rename from drivers/media/dvb/frontends/tda827x.h
rename to drivers/media/common/tuners/tda827x.h
index b73c235..7850a9a 100644
--- a/drivers/media/dvb/frontends/tda827x.h
+++ b/drivers/media/common/tuners/tda827x.h
@@ -51,7 +51,7 @@
* @param cfg optional callback function pointers.
* @return FE pointer on success, NULL on failure.
*/
-#if defined(CONFIG_DVB_TDA827X) || (defined(CONFIG_DVB_TDA827X_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE))
extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr,
struct i2c_adapter *i2c,
struct tda827x_config *cfg);
@@ -64,6 +64,6 @@
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TDA827X
+#endif // CONFIG_MEDIA_TUNER_TDA827X
#endif // __DVB_TDA827X_H__
diff --git a/drivers/media/video/tda8290.c b/drivers/media/common/tuners/tda8290.c
similarity index 98%
rename from drivers/media/video/tda8290.c
rename to drivers/media/common/tuners/tda8290.c
index 0ebb5b5..91204d3 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -578,16 +578,16 @@
if ((data == 0x83) || (data == 0x84)) {
priv->ver |= TDA18271;
- tda18271_attach(fe, priv->tda827x_addr,
- priv->i2c_props.adap,
- &tda829x_tda18271_config);
+ dvb_attach(tda18271_attach, fe, priv->tda827x_addr,
+ priv->i2c_props.adap, &tda829x_tda18271_config);
} else {
if ((data & 0x3c) == 0)
priv->ver |= TDA8275;
else
priv->ver |= TDA8275A;
- tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg);
+ dvb_attach(tda827x_attach, fe, priv->tda827x_addr,
+ priv->i2c_props.adap, &priv->cfg);
priv->cfg.switch_addr = priv->i2c_props.addr;
}
if (fe->ops.tuner_ops.init)
diff --git a/drivers/media/video/tda8290.h b/drivers/media/common/tuners/tda8290.h
similarity index 93%
rename from drivers/media/video/tda8290.h
rename to drivers/media/common/tuners/tda8290.h
index d3bbf27..aa074f3 100644
--- a/drivers/media/video/tda8290.h
+++ b/drivers/media/common/tuners/tda8290.h
@@ -29,7 +29,7 @@
#define TDA829X_DONT_PROBE 1
};
-#if defined(CONFIG_TUNER_TDA8290) || (defined(CONFIG_TUNER_TDA8290_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE))
extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/video/tda9887.c b/drivers/media/common/tuners/tda9887.c
similarity index 100%
rename from drivers/media/video/tda9887.c
rename to drivers/media/common/tuners/tda9887.c
diff --git a/drivers/media/video/tda9887.h b/drivers/media/common/tuners/tda9887.h
similarity index 91%
rename from drivers/media/video/tda9887.h
rename to drivers/media/common/tuners/tda9887.h
index be49dcb..acc419e 100644
--- a/drivers/media/video/tda9887.h
+++ b/drivers/media/common/tuners/tda9887.h
@@ -21,7 +21,7 @@
#include "dvb_frontend.h"
/* ------------------------------------------------------------------------ */
-#if defined(CONFIG_TUNER_TDA9887) || (defined(CONFIG_TUNER_TDA9887_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE))
extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr);
diff --git a/drivers/media/video/tea5761.c b/drivers/media/common/tuners/tea5761.c
similarity index 100%
rename from drivers/media/video/tea5761.c
rename to drivers/media/common/tuners/tea5761.c
diff --git a/drivers/media/video/tea5761.h b/drivers/media/common/tuners/tea5761.h
similarity index 92%
rename from drivers/media/video/tea5761.h
rename to drivers/media/common/tuners/tea5761.h
index 8eb6272..2e2ff82 100644
--- a/drivers/media/video/tea5761.h
+++ b/drivers/media/common/tuners/tea5761.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/video/tea5767.c b/drivers/media/common/tuners/tea5767.c
similarity index 100%
rename from drivers/media/video/tea5767.c
rename to drivers/media/common/tuners/tea5767.c
diff --git a/drivers/media/video/tea5767.h b/drivers/media/common/tuners/tea5767.h
similarity index 94%
rename from drivers/media/video/tea5767.h
rename to drivers/media/common/tuners/tea5767.h
index 7b547c0..d30ab1b 100644
--- a/drivers/media/video/tea5767.h
+++ b/drivers/media/common/tuners/tea5767.h
@@ -39,7 +39,7 @@
enum tea5767_xtal xtal_freq;
};
-#if defined(CONFIG_TUNER_TEA5767) || (defined(CONFIG_TUNER_TEA5767_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE))
extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr);
extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/common/tuners/tuner-i2c.h
similarity index 100%
rename from drivers/media/video/tuner-i2c.h
rename to drivers/media/common/tuners/tuner-i2c.h
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
similarity index 100%
rename from drivers/media/video/tuner-simple.c
rename to drivers/media/common/tuners/tuner-simple.c
diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/common/tuners/tuner-simple.h
similarity index 92%
rename from drivers/media/video/tuner-simple.h
rename to drivers/media/common/tuners/tuner-simple.h
index e46cf01..381fa5d 100644
--- a/drivers/media/video/tuner-simple.h
+++ b/drivers/media/common/tuners/tuner-simple.h
@@ -20,7 +20,7 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE))
extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr,
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
similarity index 100%
rename from drivers/media/video/tuner-types.c
rename to drivers/media/common/tuners/tuner-types.c
diff --git a/drivers/media/video/tuner-xc2028-types.h b/drivers/media/common/tuners/tuner-xc2028-types.h
similarity index 100%
rename from drivers/media/video/tuner-xc2028-types.h
rename to drivers/media/common/tuners/tuner-xc2028-types.h
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/common/tuners/tuner-xc2028.c
similarity index 100%
rename from drivers/media/video/tuner-xc2028.c
rename to drivers/media/common/tuners/tuner-xc2028.c
diff --git a/drivers/media/video/tuner-xc2028.h b/drivers/media/common/tuners/tuner-xc2028.h
similarity index 93%
rename from drivers/media/video/tuner-xc2028.h
rename to drivers/media/common/tuners/tuner-xc2028.h
index fc2f132..216025c 100644
--- a/drivers/media/video/tuner-xc2028.h
+++ b/drivers/media/common/tuners/tuner-xc2028.h
@@ -47,7 +47,7 @@
#define XC2028_TUNER_RESET 0
#define XC2028_RESET_CLK 1
-#if defined(CONFIG_TUNER_XC2028) || (defined(CONFIG_TUNER_XC2028_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE))
extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
struct xc2028_config *cfg);
#else
diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/common/tuners/xc5000.c
similarity index 100%
rename from drivers/media/dvb/frontends/xc5000.c
rename to drivers/media/common/tuners/xc5000.c
diff --git a/drivers/media/dvb/frontends/xc5000.h b/drivers/media/common/tuners/xc5000.h
similarity index 92%
rename from drivers/media/dvb/frontends/xc5000.h
rename to drivers/media/common/tuners/xc5000.h
index b890883..0ee80f9 100644
--- a/drivers/media/dvb/frontends/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -45,8 +45,8 @@
/* xc5000 callback command */
#define XC5000_TUNER_RESET 0
-#if defined(CONFIG_DVB_TUNER_XC5000) || \
- (defined(CONFIG_DVB_TUNER_XC5000_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_XC5000) || \
+ (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
extern struct dvb_frontend* xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct xc5000_config *cfg);
@@ -58,6 +58,6 @@
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-#endif // CONFIG_DVB_TUNER_XC5000
+#endif // CONFIG_MEDIA_TUNER_XC5000
#endif // __XC5000_H__
diff --git a/drivers/media/dvb/frontends/xc5000_priv.h b/drivers/media/common/tuners/xc5000_priv.h
similarity index 100%
rename from drivers/media/dvb/frontends/xc5000_priv.h
rename to drivers/media/common/tuners/xc5000_priv.h
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 03ef88a..7b21b49 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -1,9 +1,7 @@
#
-# Multimedia device configuration
+# DVB device configuration
#
-source "drivers/media/dvb/dvb-core/Kconfig"
-
menuconfig DVB_CAPTURE_DRIVERS
bool "DVB/ATSC adapters"
depends on DVB_CORE
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 6ec5afb..73dc2ee 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -9,7 +9,7 @@
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_BCM3510 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select DVB_S5H1420 if !DVB_FE_CUSTOMISE
select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index 870e284..d9db066 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -14,4 +14,4 @@
obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
-EXTRA_CFLAGS += -Idrivers/media/video/
+EXTRA_CFLAGS += -Idrivers/media/common/tuners/
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index 902c762..d1239b8 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -8,7 +8,7 @@
select DVB_OR51211 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select FW_LOADER
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index 9d3e68b..d98f1d4 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -3,4 +3,4 @@
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
EXTRA_CFLAGS += -Idrivers/media/video/bt8xx
-EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 75711bd..a763756 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1714,7 +1714,7 @@
struct dst_state *state = fe->demodulator_priv;
if (state->dst_ca) {
dvb_unregister_device(state->dst_ca);
-#ifdef CONFIG_DVB_CORE_ATTACH
+#ifdef CONFIG_MEDIA_ATTACH
symbol_put(dst_ca_attach);
#endif
}
diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig
deleted file mode 100644
index e3e6839..0000000
--- a/drivers/media/dvb/dvb-core/Kconfig
+++ /dev/null
@@ -1,34 +0,0 @@
-config DVB_CORE
- tristate "DVB for Linux"
- depends on NET && INET
- select CRC32
- help
- Support Digital Video Broadcasting hardware. Enable this if you
- own a DVB adapter and want to use it or if you compile Linux for
- a digital SetTopBox.
-
- DVB core utility functions for device handling, software fallbacks etc.
- Say Y when you have a DVB card and want to use it. Say Y if your want
- to build your drivers outside the kernel, but need the DVB core. All
- in-kernel drivers will select this automatically if needed.
-
- API specs and user tools are available from <http://www.linuxtv.org/>.
-
- Please report problems regarding this driver to the LinuxDVB
- mailing list.
-
- If unsure say N.
-
-config DVB_CORE_ATTACH
- bool "Load and attach frontend modules as needed"
- depends on DVB_CORE
- depends on MODULES
- help
- Remove the static dependency of DVB card drivers on all
- frontend modules for all possible card variants. Instead,
- allow the card drivers to only load the frontend modules
- they require. This saves several KBytes of memory.
-
- Note: You will need module-init-tools v3.2 or later for this feature.
-
- If unsure say Y.
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 2dddd08..8cbdb21 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -1189,7 +1189,7 @@
}
EXPORT_SYMBOL(dvb_unregister_frontend);
-#ifdef CONFIG_DVB_CORE_ATTACH
+#ifdef CONFIG_MEDIA_ATTACH
void dvb_frontend_detach(struct dvb_frontend* fe)
{
void *ptr;
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 5f9a737..89d12dc 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -115,7 +115,7 @@
unsigned int cmd, void *arg));
/** generic DVB attach function. */
-#ifdef CONFIG_DVB_CORE_ATTACH
+#ifdef CONFIG_MEDIA_ATTACH
#define dvb_attach(FUNCTION, ARGS...) ({ \
void *__r = NULL; \
typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 3c8493d..4c1cff9 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -25,7 +25,7 @@
tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
depends on DVB_USB
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
@@ -35,7 +35,7 @@
depends on DVB_USB
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MB
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
@@ -56,7 +56,7 @@
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
depends on DVB_USB
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
Support for USB2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
@@ -73,8 +73,8 @@
select DVB_DIB7000P
select DVB_DIB7000M
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_MT2266 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2266 if !DVB_FE_CUSTOMISE
select DVB_TUNER_DIB0070
help
Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
@@ -93,7 +93,7 @@
depends on DVB_USB
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
help
Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
@@ -105,7 +105,7 @@
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
@@ -118,7 +118,7 @@
tristate "Uli m920x DVB-T USB2.0 support"
depends on DVB_USB
select DVB_MT352 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
help
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
Currently, only devices with a product id of
@@ -129,7 +129,7 @@
tristate "Genesys Logic GL861 USB2.0 support"
depends on DVB_USB
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
help
Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
receiver with USB ID 0db0:5581.
@@ -138,7 +138,7 @@
tristate "Alcor Micro AU6610 USB2.0 support"
depends on DVB_USB
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
help
Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
@@ -190,7 +190,7 @@
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
depends on DVB_USB
select DVB_DIB3000MC
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
select DVB_PLL if !DVB_FE_CUSTOMISE
help
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
@@ -227,8 +227,8 @@
config DVB_USB_AF9005
tristate "Afatech AF9005 DVB-T USB1.1 support"
depends on DVB_USB && EXPERIMENTAL
- select DVB_TUNER_MT2060 if !DVB_FE_CUSTOMISE
- select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2060 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_QT1010 if !DVB_FE_CUSTOMISE
help
Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver
and the TerraTec Cinergy T USB XE (Rev.1)
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 60a9100..c6511a6 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -63,5 +63,5 @@
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
-EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index f5fceb3..6d23846 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -15,13 +15,6 @@
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
-config DVB_STV0299
- tristate "ST STV0299 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S tuner module. Say Y when you want to support this frontend.
-
config DVB_CX24110
tristate "Conexant CX24110 based"
depends on DVB_CORE && I2C
@@ -36,13 +29,6 @@
help
A DVB-S tuner module. Say Y when you want to support this frontend.
-config DVB_TDA8083
- tristate "Philips TDA8083 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S tuner module. Say Y when you want to support this frontend.
-
config DVB_MT312
tristate "Zarlink VP310/MT312 based"
depends on DVB_CORE && I2C
@@ -50,13 +36,6 @@
help
A DVB-S tuner module. Say Y when you want to support this frontend.
-config DVB_VES1X93
- tristate "VLSI VES1893 or VES1993 based"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S tuner module. Say Y when you want to support this frontend.
-
config DVB_S5H1420
tristate "Samsung S5H1420 based"
depends on DVB_CORE && I2C
@@ -64,6 +43,20 @@
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+config DVB_STV0299
+ tristate "ST STV0299 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA8083
+ tristate "Philips TDA8083 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
config DVB_TDA10086
tristate "Philips TDA10086 based"
depends on DVB_CORE && I2C
@@ -71,6 +64,34 @@
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+config DVB_VES1X93
+ tristate "VLSI VES1893 or VES1993 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TUNER_ITD1000
+ tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA826X
+ tristate "Philips TDA826X silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_TUA6100
+ tristate "Infineon TUA6100 PLL"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S PLL chip.
+
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
@@ -315,7 +336,7 @@
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
-comment "Tuners/PLL support"
+comment "Digital terrestrial only tuners/PLL"
depends on DVB_CORE
config DVB_PLL
@@ -326,55 +347,6 @@
This module drives a number of tuners based on PLL chips with a
common I2C interface. Say Y when you want to support these tuners.
-config DVB_TDA826X
- tristate "Philips TDA826X silicon tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-S silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_TDA827X
- tristate "Philips TDA827X silicon tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVB-T silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_TDA18271
- tristate "NXP TDA18271 silicon tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A silicon tuner module. Say Y when you want to support this tuner.
-
-config DVB_TUNER_QT1010
- tristate "Quantek QT1010 silicon tuner"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon tuner QT1010 from Quantek.
-
-config DVB_TUNER_MT2060
- tristate "Microtune MT2060 silicon IF tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon IF tuner MT2060 from Microtune.
-
-config DVB_TUNER_MT2266
- tristate "Microtune MT2266 silicon tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon baseband tuner MT2266 from Microtune.
-
-config DVB_TUNER_MT2131
- tristate "Microtune MT2131 silicon tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon baseband tuner MT2131 from Microtune.
-
config DVB_TUNER_DIB0070
tristate "DiBcom DiB0070 silicon base-band tuner"
depends on I2C
@@ -384,21 +356,7 @@
This device is only used inside a SiP called togther with a
demodulator for now.
-config DVB_TUNER_XC5000
- tristate "Xceive XC5000 silicon tuner"
- depends on I2C
- default m if DVB_FE_CUSTOMISE
- help
- A driver for the silicon tuner XC5000 from Xceive.
- This device is only used inside a SiP called togther with a
- demodulator for now.
-
-config DVB_TUNER_ITD1000
- tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
-
-comment "Miscellaneous devices"
+comment "SEC control devices for DVB-S"
depends on DVB_CORE
config DVB_LNBP21
@@ -422,11 +380,4 @@
help
An SEC control chip.
-config DVB_TUA6100
- tristate "TUA6100 PLL"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- A DVBS PLL chip.
-
endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 9747c73..a89dc0f 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -3,9 +3,7 @@
#
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
-EXTRA_CFLAGS += -Idrivers/media/video/
-
-tda18271-objs := tda18271-tables.o tda18271-common.o tda18271-fe.o
+EXTRA_CFLAGS += -Idrivers/media/common/tuners/
obj-$(CONFIG_DVB_PLL) += dvb-pll.o
obj-$(CONFIG_DVB_STV0299) += stv0299.o
@@ -42,16 +40,9 @@
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
-obj-$(CONFIG_DVB_TDA827X) += tda827x.o
-obj-$(CONFIG_DVB_TDA18271) += tda18271.o
-obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
-obj-$(CONFIG_DVB_TUNER_MT2266) += mt2266.o
obj-$(CONFIG_DVB_TUNER_DIB0070) += dib0070.o
-obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
-obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
-obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
obj-$(CONFIG_DVB_AU8522) += au8522.o
obj-$(CONFIG_DVB_TDA10048) += tda10048.o
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 281e1cb..720ed9f 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -481,7 +481,7 @@
val *= 2;
do_div(val, (state->fclk / 1000));
- dprintk("symbol rate register: %06llx\n", val);
+ dprintk("symbol rate register: %06llx\n", (unsigned long long)val);
v = s5h1420_readreg(state, Loop01);
s5h1420_writereg(state, Loop01, v & 0x7f);
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index fe9a4cc..fe743aa 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -1,4 +1,50 @@
#
+# Generic video config states
+#
+
+config VIDEO_V4L2
+ tristate
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON
+ default VIDEO_DEV && VIDEO_V4L2_COMMON
+
+config VIDEO_V4L1
+ tristate
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+ default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+
+config VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_DMA_SG
+ depends on HAS_DMA
+ select VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_VMALLOC
+ select VIDEOBUF_GEN
+ tristate
+
+config VIDEOBUF_DVB
+ tristate
+ select VIDEOBUF_GEN
+ select VIDEOBUF_DMA_SG
+
+config VIDEO_BTCX
+ tristate
+
+config VIDEO_IR_I2C
+ tristate
+
+config VIDEO_IR
+ tristate
+ depends on INPUT
+ select VIDEO_IR_I2C if I2C
+
+config VIDEO_TVEEPROM
+ tristate
+ depends on I2C
+
+#
# Multimedia Video device configuration
#
@@ -644,7 +690,7 @@
tristate "Siemens-Nixdorf 'Multimedia eXtension Board'"
depends on PCI && VIDEO_V4L1 && I2C
select VIDEO_SAA7146_VV
- select VIDEO_TUNER
+ select MEDIA_TUNER
select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
@@ -702,6 +748,8 @@
source "drivers/media/video/ivtv/Kconfig"
+source "drivers/media/video/cx18/Kconfig"
+
config VIDEO_M32R_AR
tristate "AR devices"
depends on M32R && VIDEO_V4L1
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index be14227..a352c6e 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -84,17 +84,7 @@
obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o
-
-obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
-obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
-# tuner-types will be merged into tuner-simple, in the future
-obj-$(CONFIG_TUNER_SIMPLE) += tuner-types.o
-obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
-obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
-obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
-obj-$(CONFIG_TUNER_TEA5761) += tea5761.o
-obj-$(CONFIG_TUNER_TDA9887) += tda9887.o
+obj-$(CONFIG_MEDIA_TUNER) += tuner.o
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -134,6 +124,7 @@
obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
+obj-$(CONFIG_VIDEO_CX18) += cx18/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
@@ -147,3 +138,4 @@
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
index 4170826..cab277f 100644
--- a/drivers/media/video/au0828/Kconfig
+++ b/drivers/media/video/au0828/Kconfig
@@ -4,7 +4,7 @@
depends on VIDEO_DEV && I2C && INPUT && DVB_CORE
select I2C_ALGOBIT
select DVB_AU8522 if !DVB_FE_CUSTOMIZE
- select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
---help---
This is a video4linux driver for Auvitek's USB device.
diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile
index 9f4f572..cd2c582 100644
--- a/drivers/media/video/au0828/Makefile
+++ b/drivers/media/video/au0828/Makefile
@@ -2,7 +2,7 @@
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
-EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index cfc822bb..7431ef6 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -6,7 +6,7 @@
select VIDEO_BTCX
select VIDEOBUF_DMA_SG
select VIDEO_IR
- select VIDEO_TUNER
+ select MEDIA_TUNER
select VIDEO_TVEEPROM
select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
diff --git a/drivers/media/video/bt8xx/Makefile b/drivers/media/video/bt8xx/Makefile
index 924d216..e415f6f 100644
--- a/drivers/media/video/bt8xx/Makefile
+++ b/drivers/media/video/bt8xx/Makefile
@@ -9,4 +9,5 @@
obj-$(CONFIG_VIDEO_BT848) += bttv.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 03816b7..27da7b4 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -81,8 +81,6 @@
/* Limits scaled width, which must be a multiple of 4. */
#define MAX_HACTIVE (0x3FF & -4)
-#define clamp(x, low, high) min (max (low, x), high)
-
#define BTTV_NORMS (\
V4L2_STD_PAL | V4L2_STD_PAL_N | \
V4L2_STD_PAL_Nc | V4L2_STD_SECAM | \
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
index fae469c..2a429f9 100644
--- a/drivers/media/video/cs5345.c
+++ b/drivers/media/video/cs5345.c
@@ -142,7 +142,8 @@
/* ----------------------------------------------------------------------- */
-static int cs5345_probe(struct i2c_client *client)
+static int cs5345_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
/* Check if the adapter supports the needed features */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index f41bfde..2dfd0af 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -135,7 +135,8 @@
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int cs53l32a_probe(struct i2c_client *client)
+static int cs53l32a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int i;
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
new file mode 100644
index 0000000..acc4b47
--- /dev/null
+++ b/drivers/media/video/cx18/Kconfig
@@ -0,0 +1,20 @@
+config VIDEO_CX18
+ tristate "Conexant cx23418 MPEG encoder support"
+ depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
+ select I2C_ALGOBIT
+ select FW_LOADER
+ select VIDEO_IR
+ select MEDIA_TUNER
+ select VIDEO_TVEEPROM
+ select VIDEO_CX2341X
+ select VIDEO_CS5345
+ select DVB_S5H1409
+ ---help---
+ This is a video4linux driver for Conexant cx23418 based
+ PCI combo video recorder devices.
+
+ This is used in devices such as the Hauppauge HVR-1600
+ cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx18.
diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile
new file mode 100644
index 0000000..b23d2e2
--- /dev/null
+++ b/drivers/media/video/cx18/Makefile
@@ -0,0 +1,11 @@
+cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \
+ cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \
+ cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
+ cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
+ cx18-dvb.o
+
+obj-$(CONFIG_VIDEO_CX18) += cx18.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c
new file mode 100644
index 0000000..1adc404
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-audio.c
@@ -0,0 +1,73 @@
+/*
+ * cx18 audio-related functions
+ *
+ * Derived from ivtv-audio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-i2c.h"
+#include "cx18-cards.h"
+#include "cx18-audio.h"
+
+/* Selects the audio input and output according to the current
+ settings. */
+int cx18_audio_set_io(struct cx18 *cx)
+{
+ struct v4l2_routing route;
+ u32 audio_input;
+ int mux_input;
+
+ /* Determine which input to use */
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ audio_input = cx->card->radio_input.audio_input;
+ mux_input = cx->card->radio_input.muxer_input;
+ } else {
+ audio_input =
+ cx->card->audio_inputs[cx->audio_input].audio_input;
+ mux_input =
+ cx->card->audio_inputs[cx->audio_input].muxer_input;
+ }
+
+ /* handle muxer chips */
+ route.input = mux_input;
+ route.output = 0;
+ cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+
+ route.input = audio_input;
+ return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+ VIDIOC_INT_S_AUDIO_ROUTING, &route);
+}
+
+void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
+{
+ cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
+ VIDIOC_INT_S_AUDIO_ROUTING, route);
+}
+
+void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq)
+{
+ static u32 freqs[3] = { 44100, 48000, 32000 };
+
+ /* The audio clock of the digitizer must match the codec sample
+ rate otherwise you get some very strange effects. */
+ if (freq > 2)
+ return;
+ cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
+}
diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h
new file mode 100644
index 0000000..cb569a6
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-audio.h
@@ -0,0 +1,26 @@
+/*
+ * cx18 audio-related functions
+ *
+ * Derived from ivtv-audio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_audio_set_io(struct cx18 *cx);
+void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route);
+void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq);
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c
new file mode 100644
index 0000000..2dc3a5d
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-audio.c
@@ -0,0 +1,361 @@
+/*
+ * cx18 ADEC audio functions
+ *
+ * Derived from cx25840-audio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "cx18-driver.h"
+
+static int set_audclk_freq(struct cx18 *cx, u32 freq)
+{
+ struct cx18_av_state *state = &cx->av_state;
+
+ if (freq != 32000 && freq != 44100 && freq != 48000)
+ return -EINVAL;
+
+ /* common for all inputs and rates */
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
+ cx18_av_write(cx, 0x127, 0x50);
+
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ switch (freq) {
+ case 32000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1006040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x01bb39ee);
+
+ /* src3/4/6_ctl = 0x0801f77f */
+ cx18_av_write4(cx, 0x900, 0x0801f77f);
+ cx18_av_write4(cx, 0x904, 0x0801f77f);
+ cx18_av_write4(cx, 0x90c, 0x0801f77f);
+ break;
+
+ case 44100:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1009040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x00ec6bd6);
+
+ /* src3/4/6_ctl = 0x08016d59 */
+ cx18_av_write4(cx, 0x900, 0x08016d59);
+ cx18_av_write4(cx, 0x904, 0x08016d59);
+ cx18_av_write4(cx, 0x90c, 0x08016d59);
+ break;
+
+ case 48000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x100a040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x0098d6e5);
+
+ /* src3/4/6_ctl = 0x08014faa */
+ cx18_av_write4(cx, 0x900, 0x08014faa);
+ cx18_av_write4(cx, 0x904, 0x08014faa);
+ cx18_av_write4(cx, 0x90c, 0x08014faa);
+ break;
+ }
+ } else {
+ switch (freq) {
+ case 32000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1e08040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x012a0869);
+
+ /* src1_ctl = 0x08010000 */
+ cx18_av_write4(cx, 0x8f8, 0x08010000);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx18_av_write4(cx, 0x900, 0x08020000);
+ cx18_av_write4(cx, 0x904, 0x08020000);
+ cx18_av_write4(cx, 0x90c, 0x08020000);
+
+ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
+ cx18_av_write(cx, 0x127, 0x54);
+ break;
+
+ case 44100:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x1809040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x00ec6bd6);
+
+ /* src1_ctl = 0x08010000 */
+ cx18_av_write4(cx, 0x8f8, 0x080160cd);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx18_av_write4(cx, 0x900, 0x08017385);
+ cx18_av_write4(cx, 0x904, 0x08017385);
+ cx18_av_write4(cx, 0x90c, 0x08017385);
+ break;
+
+ case 48000:
+ /* VID_PLL and AUX_PLL */
+ cx18_av_write4(cx, 0x108, 0x180a040f);
+
+ /* AUX_PLL_FRAC */
+ cx18_av_write4(cx, 0x110, 0x0098d6e5);
+
+ /* src1_ctl = 0x08010000 */
+ cx18_av_write4(cx, 0x8f8, 0x08018000);
+
+ /* src3/4/6_ctl = 0x08020000 */
+ cx18_av_write4(cx, 0x900, 0x08015555);
+ cx18_av_write4(cx, 0x904, 0x08015555);
+ cx18_av_write4(cx, 0x90c, 0x08015555);
+ break;
+ }
+ }
+
+ state->audclk_freq = freq;
+
+ return 0;
+}
+
+void cx18_av_audio_set_path(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+
+ /* stop microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0);
+
+ /* assert soft reset */
+ cx18_av_and_or(cx, 0x810, ~0x1, 0x01);
+
+ /* Mute everything to prevent the PFFT! */
+ cx18_av_write(cx, 0x8d3, 0x1f);
+
+ if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
+ /* Set Path1 to Serial Audio Input */
+ cx18_av_write4(cx, 0x8d0, 0x01011012);
+
+ /* The microcontroller should not be started for the
+ * non-tuner inputs: autodetection is specific for
+ * TV audio. */
+ } else {
+ /* Set Path1 to Analog Demod Main Channel */
+ cx18_av_write4(cx, 0x8d0, 0x1f063870);
+ }
+
+ set_audclk_freq(cx, state->audclk_freq);
+
+ /* deassert soft reset */
+ cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
+
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ /* When the microcontroller detects the
+ * audio format, it will unmute the lines */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ }
+}
+
+static int get_volume(struct cx18 *cx)
+{
+ /* Volume runs +18dB to -96dB in 1/2dB steps
+ * change to fit the msp3400 -114dB to +12dB range */
+
+ /* check PATH1_VOLUME */
+ int vol = 228 - cx18_av_read(cx, 0x8d4);
+ vol = (vol / 2) + 23;
+ return vol << 9;
+}
+
+static void set_volume(struct cx18 *cx, int volume)
+{
+ /* First convert the volume to msp3400 values (0-127) */
+ int vol = volume >> 9;
+ /* now scale it up to cx18_av values
+ * -114dB to -96dB maps to 0
+ * this should be 19, but in my testing that was 4dB too loud */
+ if (vol <= 23)
+ vol = 0;
+ else
+ vol -= 23;
+
+ /* PATH1_VOLUME */
+ cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
+}
+
+static int get_bass(struct cx18 *cx)
+{
+ /* bass is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_BASS_VOL */
+ int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
+ bass = (((48 - bass) * 0xffff) + 47) / 48;
+ return bass;
+}
+
+static void set_bass(struct cx18 *cx, int bass)
+{
+ /* PATH1_EQ_BASS_VOL */
+ cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
+}
+
+static int get_treble(struct cx18 *cx)
+{
+ /* treble is 49 steps +12dB to -12dB */
+
+ /* check PATH1_EQ_TREBLE_VOL */
+ int treble = cx18_av_read(cx, 0x8db) & 0x3f;
+ treble = (((48 - treble) * 0xffff) + 47) / 48;
+ return treble;
+}
+
+static void set_treble(struct cx18 *cx, int treble)
+{
+ /* PATH1_EQ_TREBLE_VOL */
+ cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
+}
+
+static int get_balance(struct cx18 *cx)
+{
+ /* balance is 7 bit, 0 to -96dB */
+
+ /* check PATH1_BAL_LEVEL */
+ int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
+ /* check PATH1_BAL_LEFT */
+ if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
+ balance = 0x80 - balance;
+ else
+ balance = 0x80 + balance;
+ return balance << 8;
+}
+
+static void set_balance(struct cx18 *cx, int balance)
+{
+ int bal = balance >> 8;
+ if (bal > 0x80) {
+ /* PATH1_BAL_LEFT */
+ cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80);
+ /* PATH1_BAL_LEVEL */
+ cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f);
+ } else {
+ /* PATH1_BAL_LEFT */
+ cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00);
+ /* PATH1_BAL_LEVEL */
+ cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal);
+ }
+}
+
+static int get_mute(struct cx18 *cx)
+{
+ /* check SRC1_MUTE_EN */
+ return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
+}
+
+static void set_mute(struct cx18 *cx, int mute)
+{
+ struct cx18_av_state *state = &cx->av_state;
+
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ /* Must turn off microcontroller in order to mute sound.
+ * Not sure if this is the best method, but it does work.
+ * If the microcontroller is running, then it will undo any
+ * changes to the mute register. */
+ if (mute) {
+ /* disable microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
+ cx18_av_write(cx, 0x8d3, 0x1f);
+ } else {
+ /* enable microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ }
+ } else {
+ /* SRC1_MUTE_EN */
+ cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
+ }
+}
+
+int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_control *ctrl = arg;
+ int retval;
+
+ switch (cmd) {
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
+ cx18_av_and_or(cx, 0x803, ~0x10, 0);
+ cx18_av_write(cx, 0x8d3, 0x1f);
+ }
+ cx18_av_and_or(cx, 0x810, ~0x1, 1);
+ retval = set_audclk_freq(cx, *(u32 *)arg);
+ cx18_av_and_or(cx, 0x810, ~0x1, 0);
+ if (state->aud_input != CX18_AV_AUDIO_SERIAL)
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ return retval;
+
+ case VIDIOC_G_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = get_volume(cx);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ ctrl->value = get_bass(cx);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ ctrl->value = get_treble(cx);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ ctrl->value = get_balance(cx);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = get_mute(cx);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case VIDIOC_S_CTRL:
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ set_volume(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BASS:
+ set_bass(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_TREBLE:
+ set_treble(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_BALANCE:
+ set_balance(cx, ctrl->value);
+ break;
+ case V4L2_CID_AUDIO_MUTE:
+ set_mute(cx, ctrl->value);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
new file mode 100644
index 0000000..6686490
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -0,0 +1,879 @@
+/*
+ * cx18 ADEC audio functions
+ *
+ * Derived from cx25840-core.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "cx18-driver.h"
+
+int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
+{
+ u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+ u32 mask = 0xff;
+ int shift = (addr & 3) * 8;
+
+ x = (x & ~(mask << shift)) | ((u32)value << shift);
+ writel(x, cx->reg_mem + 0xc40000 + (addr & ~3));
+ return 0;
+}
+
+int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
+{
+ writel(value, cx->reg_mem + 0xc40000 + addr);
+ return 0;
+}
+
+u8 cx18_av_read(struct cx18 *cx, u16 addr)
+{
+ u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
+ int shift = (addr & 3) * 8;
+
+ return (x >> shift) & 0xff;
+}
+
+u32 cx18_av_read4(struct cx18 *cx, u16 addr)
+{
+ return readl(cx->reg_mem + 0xc40000 + addr);
+}
+
+int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask,
+ u8 or_value)
+{
+ return cx18_av_write(cx, addr,
+ (cx18_av_read(cx, addr) & and_mask) |
+ or_value);
+}
+
+int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
+ u32 or_value)
+{
+ return cx18_av_write4(cx, addr,
+ (cx18_av_read4(cx, addr) & and_mask) |
+ or_value);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ enum cx18_av_audio_input aud_input);
+static void log_audio_status(struct cx18 *cx);
+static void log_video_status(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+
+static void cx18_av_initialize(struct cx18 *cx)
+{
+ u32 v;
+
+ cx18_av_loadfw(cx);
+ /* Stop 8051 code execution */
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000);
+
+ /* initallize the PLL by toggling sleep bit */
+ v = cx18_av_read4(cx, CXADEC_HOST_REG1);
+ /* enable sleep mode */
+ cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1);
+ /* disable sleep mode */
+ cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe);
+
+ /* initialize DLLs */
+ v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF;
+ /* disable FLD */
+ cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v);
+ /* enable FLD */
+ cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100);
+
+ v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF;
+ /* disable FLD */
+ cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v);
+ /* enable FLD */
+ cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100);
+
+ /* set analog bias currents. Set Vreg to 1.20V. */
+ cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802);
+
+ v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1;
+ /* enable TUNE_FIL_RST */
+ cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v);
+ /* disable TUNE_FIL_RST */
+ cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE);
+
+ /* enable 656 output */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00);
+
+ /* video output drive strength */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2);
+
+ /* reset video */
+ cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
+ cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
+
+ /* set video to auto-detect */
+ /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */
+ /* set the comb notch = 1 */
+ cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800);
+
+ /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */
+ /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */
+ cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000);
+
+ /* Set VGA_TRACK_RANGE to 0x20 */
+ cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
+
+ /* Enable VBI capture */
+ cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F);
+ /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */
+
+ /* Set the video input.
+ The setting in MODE_CTRL gets lost when we do the above setup */
+ /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
+ /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
+
+ v = cx18_av_read4(cx, CXADEC_AFE_CTRL);
+ v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */
+ v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */
+ v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */
+ /* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */
+ cx18_av_write4(cx, CXADEC_AFE_CTRL, v);
+
+/* if(dwEnable && dw3DCombAvailable) { */
+/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
+/* } else { */
+/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
+/* } */
+ cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void input_change(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ v4l2_std_id std = state->std;
+
+ /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
+ if (std & V4L2_STD_SECAM)
+ cx18_av_write(cx, 0x402, 0);
+ else {
+ cx18_av_write(cx, 0x402, 0x04);
+ cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
+ }
+ cx18_av_and_or(cx, 0x401, ~0x60, 0);
+ cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
+
+ if (std & V4L2_STD_525_60) {
+ if (std == V4L2_STD_NTSC_M_JP) {
+ /* Japan uses EIAJ audio standard */
+ cx18_av_write(cx, 0x808, 0xf7);
+ } else if (std == V4L2_STD_NTSC_M_KR) {
+ /* South Korea uses A2 audio standard */
+ cx18_av_write(cx, 0x808, 0xf8);
+ } else {
+ /* Others use the BTSC audio standard */
+ cx18_av_write(cx, 0x808, 0xf6);
+ }
+ cx18_av_write(cx, 0x80b, 0x00);
+ } else if (std & V4L2_STD_PAL) {
+ /* Follow tuner change procedure for PAL */
+ cx18_av_write(cx, 0x808, 0xff);
+ cx18_av_write(cx, 0x80b, 0x03);
+ } else if (std & V4L2_STD_SECAM) {
+ /* Select autodetect for SECAM */
+ cx18_av_write(cx, 0x808, 0xff);
+ cx18_av_write(cx, 0x80b, 0x03);
+ }
+
+ if (cx18_av_read(cx, 0x803) & 0x10) {
+ /* restart audio decoder microcontroller */
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
+ cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
+ }
+}
+
+static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
+ enum cx18_av_audio_input aud_input)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
+ vid_input <= CX18_AV_COMPOSITE8);
+ u8 reg;
+
+ CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n",
+ vid_input, aud_input);
+
+ if (is_composite) {
+ reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
+ } else {
+ int luma = vid_input & 0xf0;
+ int chroma = vid_input & 0xf00;
+
+ if ((vid_input & ~0xff0) ||
+ luma < CX18_AV_SVIDEO_LUMA1 ||
+ luma > CX18_AV_SVIDEO_LUMA4 ||
+ chroma < CX18_AV_SVIDEO_CHROMA4 ||
+ chroma > CX18_AV_SVIDEO_CHROMA8) {
+ CX18_ERR("0x%04x is not a valid video input!\n",
+ vid_input);
+ return -EINVAL;
+ }
+ reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
+ if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
+ reg &= 0x3f;
+ reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
+ } else {
+ reg &= 0xcf;
+ reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
+ }
+ }
+
+ switch (aud_input) {
+ case CX18_AV_AUDIO_SERIAL:
+ /* do nothing, use serial audio input */
+ break;
+ case CX18_AV_AUDIO4: reg &= ~0x30; break;
+ case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
+ case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
+ case CX18_AV_AUDIO7: reg &= ~0xc0; break;
+ case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
+
+ default:
+ CX18_ERR("0x%04x is not a valid audio input!\n", aud_input);
+ return -EINVAL;
+ }
+
+ cx18_av_write(cx, 0x103, reg);
+ /* Set INPUT_MODE to Composite (0) or S-Video (1) */
+ cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
+ /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
+ cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
+ /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
+ if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
+ cx18_av_and_or(cx, 0x102, ~0x4, 4);
+ else
+ cx18_av_and_or(cx, 0x102, ~0x4, 0);
+ /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
+
+ state->vid_input = vid_input;
+ state->aud_input = aud_input;
+ cx18_av_audio_set_path(cx);
+ input_change(cx);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lstd(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ u8 fmt = 0; /* zero is autodetect */
+ u8 pal_m = 0;
+
+ /* First tests should be against specific std */
+ if (state->std == V4L2_STD_NTSC_M_JP) {
+ fmt = 0x2;
+ } else if (state->std == V4L2_STD_NTSC_443) {
+ fmt = 0x3;
+ } else if (state->std == V4L2_STD_PAL_M) {
+ pal_m = 1;
+ fmt = 0x5;
+ } else if (state->std == V4L2_STD_PAL_N) {
+ fmt = 0x6;
+ } else if (state->std == V4L2_STD_PAL_Nc) {
+ fmt = 0x7;
+ } else if (state->std == V4L2_STD_PAL_60) {
+ fmt = 0x8;
+ } else {
+ /* Then, test against generic ones */
+ if (state->std & V4L2_STD_NTSC)
+ fmt = 0x1;
+ else if (state->std & V4L2_STD_PAL)
+ fmt = 0x4;
+ else if (state->std & V4L2_STD_SECAM)
+ fmt = 0xc;
+ }
+
+ CX18_DEBUG_INFO("changing video std to fmt %i\n", fmt);
+
+ /* Follow step 9 of section 3.16 in the cx18_av datasheet.
+ Without this PAL may display a vertical ghosting effect.
+ This happens for example with the Yuan MPC622. */
+ if (fmt >= 4 && fmt < 8) {
+ /* Set format to NTSC-M */
+ cx18_av_and_or(cx, 0x400, ~0xf, 1);
+ /* Turn off LCOMB */
+ cx18_av_and_or(cx, 0x47b, ~6, 0);
+ }
+ cx18_av_and_or(cx, 0x400, ~0xf, fmt);
+ cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
+ cx18_av_vbi_setup(cx);
+ input_change(cx);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ CX18_ERR("invalid brightness setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x414, ctrl->value - 128);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ CX18_ERR("invalid contrast setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x415, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ CX18_ERR("invalid saturation setting %d\n",
+ ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x420, ctrl->value << 1);
+ cx18_av_write(cx, 0x421, ctrl->value << 1);
+ break;
+
+ case V4L2_CID_HUE:
+ if (ctrl->value < -127 || ctrl->value > 127) {
+ CX18_ERR("invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ cx18_av_write(cx, 0x422, ctrl->value);
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx18_av_audio(cx, VIDIOC_S_CTRL, ctrl);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = cx18_av_read(cx, 0x415) >> 1;
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = cx18_av_read(cx, 0x420) >> 1;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = (s8)cx18_av_read(cx, 0x422);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_MUTE:
+ return cx18_av_audio(cx, VIDIOC_G_CTRL, ctrl);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+{
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_pix_format *pix;
+ int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
+ int is_50Hz = !(state->std & V4L2_STD_525_60);
+
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ pix = &(fmt->fmt.pix);
+
+ Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4;
+
+ Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
+
+ Vlines = pix->height + (is_50Hz ? 4 : 7);
+
+ if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ CX18_ERR("%dx%d is not a valid size!\n",
+ pix->width, pix->height);
+ return -ERANGE;
+ }
+
+ HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
+ VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+ VSC &= 0x1fff;
+
+ if (pix->width >= 385)
+ filter = 0;
+ else if (pix->width > 192)
+ filter = 1;
+ else if (pix->width > 96)
+ filter = 2;
+ else
+ filter = 3;
+
+ CX18_DEBUG_INFO("decoder set size %dx%d -> scale %ux%u\n",
+ pix->width, pix->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx18_av_write(cx, 0x418, HSC & 0xff);
+ cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff);
+ cx18_av_write(cx, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx18_av_write(cx, 0x41c, VSC & 0xff);
+ cx18_av_write(cx, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx18_av_write(cx, 0x41e, 0x8 | filter);
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_tuner *vt = arg;
+ struct v4l2_routing *route = arg;
+
+ /* ignore these commands */
+ switch (cmd) {
+ case TUNER_SET_TYPE_ADDR:
+ return 0;
+ }
+
+ if (!state->is_initialized) {
+ CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd);
+ /* initialize on first use */
+ state->is_initialized = 1;
+ cx18_av_initialize(cx);
+ }
+
+ switch (cmd) {
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ return cx18_av_vbi(cx, cmd, arg);
+
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return cx18_av_audio(cx, cmd, arg);
+
+ case VIDIOC_STREAMON:
+ CX18_DEBUG_INFO("enable output\n");
+ cx18_av_write(cx, 0x115, 0x8c);
+ cx18_av_write(cx, 0x116, 0x07);
+ break;
+
+ case VIDIOC_STREAMOFF:
+ CX18_DEBUG_INFO("disable output\n");
+ cx18_av_write(cx, 0x115, 0x00);
+ cx18_av_write(cx, 0x116, 0x00);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ log_video_status(cx);
+ log_audio_status(cx);
+ break;
+
+ case VIDIOC_G_CTRL:
+ return get_v4lctrl(cx, (struct v4l2_control *)arg);
+
+ case VIDIOC_S_CTRL:
+ return set_v4lctrl(cx, (struct v4l2_control *)arg);
+
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
+
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_STD:
+ *(v4l2_std_id *)arg = state->std;
+ break;
+
+ case VIDIOC_S_STD:
+ if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
+ return 0;
+ state->radio = 0;
+ state->std = *(v4l2_std_id *)arg;
+ return set_v4lstd(cx);
+
+ case AUDC_SET_RADIO:
+ state->radio = 1;
+ break;
+
+ case VIDIOC_INT_G_VIDEO_ROUTING:
+ route->input = state->vid_input;
+ route->output = 0;
+ break;
+
+ case VIDIOC_INT_S_VIDEO_ROUTING:
+ return set_input(cx, route->input, state->aud_input);
+
+ case VIDIOC_INT_G_AUDIO_ROUTING:
+ route->input = state->aud_input;
+ route->output = 0;
+ break;
+
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ return set_input(cx, state->vid_input, route->input);
+
+ case VIDIOC_S_FREQUENCY:
+ input_change(cx);
+ break;
+
+ case VIDIOC_G_TUNER:
+ {
+ u8 vpres = cx18_av_read(cx, 0x40e) & 0x20;
+ u8 mode;
+ int val = 0;
+
+ if (state->radio)
+ break;
+
+ vt->signal = vpres ? 0xffff : 0x0;
+
+ vt->capability |=
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
+ V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
+
+ mode = cx18_av_read(cx, 0x804);
+
+ /* get rxsubchans and audmode */
+ if ((mode & 0xf) == 1)
+ val |= V4L2_TUNER_SUB_STEREO;
+ else
+ val |= V4L2_TUNER_SUB_MONO;
+
+ if (mode == 2 || mode == 4)
+ val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+
+ if (mode & 0x10)
+ val |= V4L2_TUNER_SUB_SAP;
+
+ vt->rxsubchans = val;
+ vt->audmode = state->audmode;
+ break;
+ }
+
+ case VIDIOC_S_TUNER:
+ if (state->radio)
+ break;
+
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ /* mono -> mono
+ stereo -> mono
+ bilingual -> lang1 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x00);
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ case V4L2_TUNER_MODE_LANG1:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang1 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x04);
+ break;
+ case V4L2_TUNER_MODE_LANG1_LANG2:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang1/lang2 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x07);
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ /* mono -> mono
+ stereo -> stereo
+ bilingual -> lang2 */
+ cx18_av_and_or(cx, 0x809, ~0xf, 0x01);
+ break;
+ default:
+ return -EINVAL;
+ }
+ state->audmode = vt->audmode;
+ break;
+
+ case VIDIOC_G_FMT:
+ return get_v4lfmt(cx, (struct v4l2_format *)arg);
+
+ case VIDIOC_S_FMT:
+ return set_v4lfmt(cx, (struct v4l2_format *)arg);
+
+ case VIDIOC_INT_RESET:
+ cx18_av_initialize(cx);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------- */
+
+static void log_video_status(struct cx18 *cx)
+{
+ static const char *const fmt_strs[] = {
+ "0x0",
+ "NTSC-M", "NTSC-J", "NTSC-4.43",
+ "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
+ "0x9", "0xA", "0xB",
+ "SECAM",
+ "0xD", "0xE", "0xF"
+ };
+
+ struct cx18_av_state *state = &cx->av_state;
+ u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf;
+ u8 gen_stat1 = cx18_av_read(cx, 0x40d);
+ u8 gen_stat2 = cx18_av_read(cx, 0x40e);
+ int vid_input = state->vid_input;
+
+ CX18_INFO("Video signal: %spresent\n",
+ (gen_stat2 & 0x20) ? "" : "not ");
+ CX18_INFO("Detected format: %s\n",
+ fmt_strs[gen_stat1 & 0xf]);
+
+ CX18_INFO("Specified standard: %s\n",
+ vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+ if (vid_input >= CX18_AV_COMPOSITE1 &&
+ vid_input <= CX18_AV_COMPOSITE8) {
+ CX18_INFO("Specified video input: Composite %d\n",
+ vid_input - CX18_AV_COMPOSITE1 + 1);
+ } else {
+ CX18_INFO("Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
+ (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+ }
+
+ CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ u8 download_ctl = cx18_av_read(cx, 0x803);
+ u8 mod_det_stat0 = cx18_av_read(cx, 0x805);
+ u8 mod_det_stat1 = cx18_av_read(cx, 0x804);
+ u8 audio_config = cx18_av_read(cx, 0x808);
+ u8 pref_mode = cx18_av_read(cx, 0x809);
+ u8 afc0 = cx18_av_read(cx, 0x80b);
+ u8 mute_ctl = cx18_av_read(cx, 0x8d3);
+ int aud_input = state->aud_input;
+ char *p;
+
+ switch (mod_det_stat0) {
+ case 0x00: p = "mono"; break;
+ case 0x01: p = "stereo"; break;
+ case 0x02: p = "dual"; break;
+ case 0x04: p = "tri"; break;
+ case 0x10: p = "mono with SAP"; break;
+ case 0x11: p = "stereo with SAP"; break;
+ case 0x12: p = "dual with SAP"; break;
+ case 0x14: p = "tri with SAP"; break;
+ case 0xfe: p = "forced mode"; break;
+ default: p = "not defined";
+ }
+ CX18_INFO("Detected audio mode: %s\n", p);
+
+ switch (mod_det_stat1) {
+ case 0x00: p = "BTSC"; break;
+ case 0x01: p = "EIAJ"; break;
+ case 0x02: p = "A2-M"; break;
+ case 0x03: p = "A2-BG"; break;
+ case 0x04: p = "A2-DK1"; break;
+ case 0x05: p = "A2-DK2"; break;
+ case 0x06: p = "A2-DK3"; break;
+ case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x08: p = "AM-L"; break;
+ case 0x09: p = "NICAM-BG"; break;
+ case 0x0a: p = "NICAM-DK"; break;
+ case 0x0b: p = "NICAM-I"; break;
+ case 0x0c: p = "NICAM-L"; break;
+ case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
+ case 0xff: p = "no detected audio standard"; break;
+ default: p = "not defined";
+ }
+ CX18_INFO("Detected audio standard: %s\n", p);
+ CX18_INFO("Audio muted: %s\n",
+ (mute_ctl & 0x2) ? "yes" : "no");
+ CX18_INFO("Audio microcontroller: %s\n",
+ (download_ctl & 0x10) ? "running" : "stopped");
+
+ switch (audio_config >> 4) {
+ case 0x00: p = "BTSC"; break;
+ case 0x01: p = "EIAJ"; break;
+ case 0x02: p = "A2-M"; break;
+ case 0x03: p = "A2-BG"; break;
+ case 0x04: p = "A2-DK1"; break;
+ case 0x05: p = "A2-DK2"; break;
+ case 0x06: p = "A2-DK3"; break;
+ case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
+ case 0x08: p = "AM-L"; break;
+ case 0x09: p = "NICAM-BG"; break;
+ case 0x0a: p = "NICAM-DK"; break;
+ case 0x0b: p = "NICAM-I"; break;
+ case 0x0c: p = "NICAM-L"; break;
+ case 0x0d: p = "FM radio"; break;
+ case 0x0f: p = "automatic detection"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Configured audio standard: %s\n", p);
+
+ if ((audio_config >> 4) < 0xF) {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
+ case 0x01: p = "MONO2 (LANGUAGE B)"; break;
+ case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
+ case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
+ case 0x04: p = "STEREO"; break;
+ case 0x05: p = "DUAL1 (AB)"; break;
+ case 0x06: p = "DUAL2 (AC) (FM)"; break;
+ case 0x07: p = "DUAL3 (BC) (FM)"; break;
+ case 0x08: p = "DUAL4 (AC) (AM)"; break;
+ case 0x09: p = "DUAL5 (BC) (AM)"; break;
+ case 0x0a: p = "SAP"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Configured audio mode: %s\n", p);
+ } else {
+ switch (audio_config & 0xF) {
+ case 0x00: p = "BG"; break;
+ case 0x01: p = "DK1"; break;
+ case 0x02: p = "DK2"; break;
+ case 0x03: p = "DK3"; break;
+ case 0x04: p = "I"; break;
+ case 0x05: p = "L"; break;
+ case 0x06: p = "BTSC"; break;
+ case 0x07: p = "EIAJ"; break;
+ case 0x08: p = "A2-M"; break;
+ case 0x09: p = "FM Radio"; break;
+ case 0x0f: p = "automatic standard and mode detection"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Configured audio system: %s\n", p);
+ }
+
+ if (aud_input)
+ CX18_INFO("Specified audio input: Tuner (In%d)\n",
+ aud_input);
+ else
+ CX18_INFO("Specified audio input: External\n");
+
+ switch (pref_mode & 0xf) {
+ case 0: p = "mono/language A"; break;
+ case 1: p = "language B"; break;
+ case 2: p = "language C"; break;
+ case 3: p = "analog fallback"; break;
+ case 4: p = "stereo"; break;
+ case 5: p = "language AC"; break;
+ case 6: p = "language BC"; break;
+ case 7: p = "language AB"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Preferred audio mode: %s\n", p);
+
+ if ((audio_config & 0xf) == 0xf) {
+ switch ((afc0 >> 2) & 0x1) {
+ case 0: p = "system DK"; break;
+ case 1: p = "system L"; break;
+ }
+ CX18_INFO("Selected 65 MHz format: %s\n", p);
+
+ switch (afc0 & 0x3) {
+ case 0: p = "BTSC"; break;
+ case 1: p = "EIAJ"; break;
+ case 2: p = "A2-M"; break;
+ default: p = "undefined";
+ }
+ CX18_INFO("Selected 45 MHz format: %s\n", p);
+ }
+}
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
new file mode 100644
index 0000000..786901d
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -0,0 +1,318 @@
+/*
+ * cx18 ADEC header
+ *
+ * Derived from cx25840-core.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef _CX18_AV_CORE_H_
+#define _CX18_AV_CORE_H_
+
+struct cx18;
+
+enum cx18_av_video_input {
+ /* Composite video inputs In1-In8 */
+ CX18_AV_COMPOSITE1 = 1,
+ CX18_AV_COMPOSITE2,
+ CX18_AV_COMPOSITE3,
+ CX18_AV_COMPOSITE4,
+ CX18_AV_COMPOSITE5,
+ CX18_AV_COMPOSITE6,
+ CX18_AV_COMPOSITE7,
+ CX18_AV_COMPOSITE8,
+
+ /* S-Video inputs consist of one luma input (In1-In4) ORed with one
+ chroma input (In5-In8) */
+ CX18_AV_SVIDEO_LUMA1 = 0x10,
+ CX18_AV_SVIDEO_LUMA2 = 0x20,
+ CX18_AV_SVIDEO_LUMA3 = 0x30,
+ CX18_AV_SVIDEO_LUMA4 = 0x40,
+ CX18_AV_SVIDEO_CHROMA4 = 0x400,
+ CX18_AV_SVIDEO_CHROMA5 = 0x500,
+ CX18_AV_SVIDEO_CHROMA6 = 0x600,
+ CX18_AV_SVIDEO_CHROMA7 = 0x700,
+ CX18_AV_SVIDEO_CHROMA8 = 0x800,
+
+ /* S-Video aliases for common luma/chroma combinations */
+ CX18_AV_SVIDEO1 = 0x510,
+ CX18_AV_SVIDEO2 = 0x620,
+ CX18_AV_SVIDEO3 = 0x730,
+ CX18_AV_SVIDEO4 = 0x840,
+};
+
+enum cx18_av_audio_input {
+ /* Audio inputs: serial or In4-In8 */
+ CX18_AV_AUDIO_SERIAL,
+ CX18_AV_AUDIO4 = 4,
+ CX18_AV_AUDIO5,
+ CX18_AV_AUDIO6,
+ CX18_AV_AUDIO7,
+ CX18_AV_AUDIO8,
+};
+
+struct cx18_av_state {
+ int radio;
+ v4l2_std_id std;
+ enum cx18_av_video_input vid_input;
+ enum cx18_av_audio_input aud_input;
+ u32 audclk_freq;
+ int audmode;
+ int vbi_line_offset;
+ u32 id;
+ u32 rev;
+ int is_initialized;
+};
+
+
+/* Registers */
+#define CXADEC_CHIP_TYPE_TIGER 0x837
+#define CXADEC_CHIP_TYPE_MAKO 0x843
+
+#define CXADEC_HOST_REG1 0x000
+#define CXADEC_HOST_REG2 0x001
+
+#define CXADEC_CHIP_CTRL 0x100
+#define CXADEC_AFE_CTRL 0x104
+#define CXADEC_PLL_CTRL1 0x108
+#define CXADEC_VID_PLL_FRAC 0x10C
+#define CXADEC_AUX_PLL_FRAC 0x110
+#define CXADEC_PIN_CTRL1 0x114
+#define CXADEC_PIN_CTRL2 0x118
+#define CXADEC_PIN_CFG1 0x11C
+#define CXADEC_PIN_CFG2 0x120
+
+#define CXADEC_PIN_CFG3 0x124
+#define CXADEC_I2S_MCLK 0x127
+
+#define CXADEC_AUD_LOCK1 0x128
+#define CXADEC_AUD_LOCK2 0x12C
+#define CXADEC_POWER_CTRL 0x130
+#define CXADEC_AFE_DIAG_CTRL1 0x134
+#define CXADEC_AFE_DIAG_CTRL2 0x138
+#define CXADEC_AFE_DIAG_CTRL3 0x13C
+#define CXADEC_PLL_DIAG_CTRL 0x140
+#define CXADEC_TEST_CTRL1 0x144
+#define CXADEC_TEST_CTRL2 0x148
+#define CXADEC_BIST_STAT 0x14C
+#define CXADEC_DLL1_DIAG_CTRL 0x158
+#define CXADEC_DLL2_DIAG_CTRL 0x15C
+
+/* IR registers */
+#define CXADEC_IR_CTRL_REG 0x200
+#define CXADEC_IR_TXCLK_REG 0x204
+#define CXADEC_IR_RXCLK_REG 0x208
+#define CXADEC_IR_CDUTY_REG 0x20C
+#define CXADEC_IR_STAT_REG 0x210
+#define CXADEC_IR_IRQEN_REG 0x214
+#define CXADEC_IR_FILTER_REG 0x218
+#define CXADEC_IR_FIFO_REG 0x21C
+
+/* Video Registers */
+#define CXADEC_MODE_CTRL 0x400
+#define CXADEC_OUT_CTRL1 0x404
+#define CXADEC_OUT_CTRL2 0x408
+#define CXADEC_GEN_STAT 0x40C
+#define CXADEC_INT_STAT_MASK 0x410
+#define CXADEC_LUMA_CTRL 0x414
+
+#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414
+#define CXADEC_CONTRAST_CTRL_BYTE 0x415
+#define CXADEC_LUMA_CTRL_BYTE_3 0x416
+
+#define CXADEC_HSCALE_CTRL 0x418
+#define CXADEC_VSCALE_CTRL 0x41C
+
+#define CXADEC_CHROMA_CTRL 0x420
+
+#define CXADEC_USAT_CTRL_BYTE 0x420
+#define CXADEC_VSAT_CTRL_BYTE 0x421
+#define CXADEC_HUE_CTRL_BYTE 0x422
+
+#define CXADEC_VBI_LINE_CTRL1 0x424
+#define CXADEC_VBI_LINE_CTRL2 0x428
+#define CXADEC_VBI_LINE_CTRL3 0x42C
+#define CXADEC_VBI_LINE_CTRL4 0x430
+#define CXADEC_VBI_LINE_CTRL5 0x434
+#define CXADEC_VBI_FC_CFG 0x438
+#define CXADEC_VBI_MISC_CFG1 0x43C
+#define CXADEC_VBI_MISC_CFG2 0x440
+#define CXADEC_VBI_PAY1 0x444
+#define CXADEC_VBI_PAY2 0x448
+#define CXADEC_VBI_CUST1_CFG1 0x44C
+#define CXADEC_VBI_CUST1_CFG2 0x450
+#define CXADEC_VBI_CUST1_CFG3 0x454
+#define CXADEC_VBI_CUST2_CFG1 0x458
+#define CXADEC_VBI_CUST2_CFG2 0x45C
+#define CXADEC_VBI_CUST2_CFG3 0x460
+#define CXADEC_VBI_CUST3_CFG1 0x464
+#define CXADEC_VBI_CUST3_CFG2 0x468
+#define CXADEC_VBI_CUST3_CFG3 0x46C
+#define CXADEC_HORIZ_TIM_CTRL 0x470
+#define CXADEC_VERT_TIM_CTRL 0x474
+#define CXADEC_SRC_COMB_CFG 0x478
+#define CXADEC_CHROMA_VBIOFF_CFG 0x47C
+#define CXADEC_FIELD_COUNT 0x480
+#define CXADEC_MISC_TIM_CTRL 0x484
+#define CXADEC_DFE_CTRL1 0x488
+#define CXADEC_DFE_CTRL2 0x48C
+#define CXADEC_DFE_CTRL3 0x490
+#define CXADEC_PLL_CTRL2 0x494
+#define CXADEC_HTL_CTRL 0x498
+#define CXADEC_COMB_CTRL 0x49C
+#define CXADEC_CRUSH_CTRL 0x4A0
+#define CXADEC_SOFT_RST_CTRL 0x4A4
+#define CXADEC_MV_DT_CTRL2 0x4A8
+#define CXADEC_MV_DT_CTRL3 0x4AC
+#define CXADEC_MISC_DIAG_CTRL 0x4B8
+
+#define CXADEC_DL_CTL 0x800
+#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */
+#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */
+#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */
+#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */
+
+#define CXADEC_STD_DET_STATUS 0x804
+
+#define CXADEC_STD_DET_CTL 0x808
+#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */
+#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */
+
+#define CXADEC_DW8051_INT 0x80C
+#define CXADEC_GENERAL_CTL 0x810
+#define CXADEC_AAGC_CTL 0x814
+#define CXADEC_IF_SRC_CTL 0x818
+#define CXADEC_ANLOG_DEMOD_CTL 0x81C
+#define CXADEC_ROT_FREQ_CTL 0x820
+#define CXADEC_FM1_CTL 0x824
+#define CXADEC_PDF_CTL 0x828
+#define CXADEC_DFT1_CTL1 0x82C
+#define CXADEC_DFT1_CTL2 0x830
+#define CXADEC_DFT_STATUS 0x834
+#define CXADEC_DFT2_CTL1 0x838
+#define CXADEC_DFT2_CTL2 0x83C
+#define CXADEC_DFT2_STATUS 0x840
+#define CXADEC_DFT3_CTL1 0x844
+#define CXADEC_DFT3_CTL2 0x848
+#define CXADEC_DFT3_STATUS 0x84C
+#define CXADEC_DFT4_CTL1 0x850
+#define CXADEC_DFT4_CTL2 0x854
+#define CXADEC_DFT4_STATUS 0x858
+#define CXADEC_AM_MTS_DET 0x85C
+#define CXADEC_ANALOG_MUX_CTL 0x860
+#define CXADEC_DIG_PLL_CTL1 0x864
+#define CXADEC_DIG_PLL_CTL2 0x868
+#define CXADEC_DIG_PLL_CTL3 0x86C
+#define CXADEC_DIG_PLL_CTL4 0x870
+#define CXADEC_DIG_PLL_CTL5 0x874
+#define CXADEC_DEEMPH_GAIN_CTL 0x878
+#define CXADEC_DEEMPH_COEF1 0x87C
+#define CXADEC_DEEMPH_COEF2 0x880
+#define CXADEC_DBX1_CTL1 0x884
+#define CXADEC_DBX1_CTL2 0x888
+#define CXADEC_DBX1_STATUS 0x88C
+#define CXADEC_DBX2_CTL1 0x890
+#define CXADEC_DBX2_CTL2 0x894
+#define CXADEC_DBX2_STATUS 0x898
+#define CXADEC_AM_FM_DIFF 0x89C
+
+/* NICAM registers go here */
+#define CXADEC_NICAM_STATUS 0x8C8
+#define CXADEC_DEMATRIX_CTL 0x8CC
+
+#define CXADEC_PATH1_CTL1 0x8D0
+#define CXADEC_PATH1_VOL_CTL 0x8D4
+#define CXADEC_PATH1_EQ_CTL 0x8D8
+#define CXADEC_PATH1_SC_CTL 0x8DC
+
+#define CXADEC_PATH2_CTL1 0x8E0
+#define CXADEC_PATH2_VOL_CTL 0x8E4
+#define CXADEC_PATH2_EQ_CTL 0x8E8
+#define CXADEC_PATH2_SC_CTL 0x8EC
+
+#define CXADEC_SRC_CTL 0x8F0
+#define CXADEC_SRC_LF_COEF 0x8F4
+#define CXADEC_SRC1_CTL 0x8F8
+#define CXADEC_SRC2_CTL 0x8FC
+#define CXADEC_SRC3_CTL 0x900
+#define CXADEC_SRC4_CTL 0x904
+#define CXADEC_SRC5_CTL 0x908
+#define CXADEC_SRC6_CTL 0x90C
+
+#define CXADEC_BASEBAND_OUT_SEL 0x910
+#define CXADEC_I2S_IN_CTL 0x914
+#define CXADEC_I2S_OUT_CTL 0x918
+#define CXADEC_AC97_CTL 0x91C
+#define CXADEC_QAM_PDF 0x920
+#define CXADEC_QAM_CONST_DEC 0x924
+#define CXADEC_QAM_ROTATOR_FREQ 0x948
+
+/* Bit defintions / settings used in Mako Audio */
+#define CXADEC_PREF_MODE_MONO_LANGA 0
+#define CXADEC_PREF_MODE_MONO_LANGB 1
+#define CXADEC_PREF_MODE_MONO_LANGC 2
+#define CXADEC_PREF_MODE_FALLBACK 3
+#define CXADEC_PREF_MODE_STEREO 4
+#define CXADEC_PREF_MODE_DUAL_LANG_AC 5
+#define CXADEC_PREF_MODE_DUAL_LANG_BC 6
+#define CXADEC_PREF_MODE_DUAL_LANG_AB 7
+
+
+#define CXADEC_DETECT_STEREO 1
+#define CXADEC_DETECT_DUAL 2
+#define CXADEC_DETECT_TRI 4
+#define CXADEC_DETECT_SAP 0x10
+#define CXADEC_DETECT_NO_SIGNAL 0xFF
+
+#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */
+#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */
+#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2
+#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3
+#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */
+#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */
+#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6
+#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7
+#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */
+#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */
+#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-core.c */
+int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
+int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
+u8 cx18_av_read(struct cx18 *cx, u16 addr);
+u32 cx18_av_read4(struct cx18 *cx, u16 addr);
+int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
+int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
+int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-firmware.c */
+int cx18_av_loadfw(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-audio.c */
+int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg);
+void cx18_av_audio_set_path(struct cx18 *cx);
+
+/* ----------------------------------------------------------------------- */
+/* cx18_av-vbi.c */
+void cx18_av_vbi_setup(struct cx18 *cx);
+int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
+
+#endif
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
new file mode 100644
index 0000000..526e142
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -0,0 +1,120 @@
+/*
+ * cx18 ADEC firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "cx18-driver.h"
+#include <linux/firmware.h>
+
+#define FWFILE "v4l-cx23418-dig.fw"
+
+int cx18_av_loadfw(struct cx18 *cx)
+{
+ const struct firmware *fw = NULL;
+ u32 size;
+ u32 v;
+ u8 *ptr;
+ int i;
+
+ if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
+ CX18_ERR("unable to open firmware %s\n", FWFILE);
+ return -EINVAL;
+ }
+
+ cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
+ cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
+
+ /* Reset the Mako core (Register is undocumented.) */
+ cx18_av_write4(cx, 0x8100, 0x00010000);
+
+ /* Put the 8051 in reset and enable firmware upload */
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
+
+ ptr = fw->data;
+ size = fw->size;
+
+ for (i = 0; i < size; i++) {
+ u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
+ u32 value = 0;
+ int retries;
+
+ for (retries = 0; retries < 5; retries++) {
+ cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
+ value = cx18_av_read4(cx, CXADEC_DL_CTL);
+ if ((value & 0x3F00) == (dl_control & 0x3F00))
+ break;
+ }
+ if (retries >= 5) {
+ CX18_ERR("unable to load firmware %s\n", FWFILE);
+ release_firmware(fw);
+ return -EIO;
+ }
+ }
+
+ cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
+
+ /* Output to the 416 */
+ cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
+
+ /* Audio input control 1 set to Sony mode */
+ /* Audio output input 2 is 0 for slave operation input */
+ /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+ /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+ after WS transition for first bit of audio word. */
+ cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0);
+
+ /* Audio output control 1 is set to Sony mode */
+ /* Audio output control 2 is set to 1 for master mode */
+ /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
+ /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
+ after WS transition for first bit of audio word. */
+ /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT
+ are generated) */
+ cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0);
+
+ /* set alt I2s master clock to /16 and enable alt divider i2s
+ passthrough */
+ cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687);
+
+ cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6);
+ /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
+
+ /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
+ /* Register 0x09CC is defined by the Merlin firmware, and doesn't
+ have a name in the spec. */
+ cx18_av_write4(cx, 0x09CC, 1);
+
+#define CX18_AUDIO_ENABLE 0xc72014
+ v = read_reg(CX18_AUDIO_ENABLE);
+ /* If bit 11 is 1 */
+ if (v & 0x800)
+ write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */
+
+ /* Enable WW auto audio standard detection */
+ v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
+ v |= 0xFF; /* Auto by default */
+ v |= 0x400; /* Stereo by default */
+ v |= 0x14000000;
+ cx18_av_write4(cx, CXADEC_STD_DET_CTL, v);
+
+ release_firmware(fw);
+
+ CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size);
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c
new file mode 100644
index 0000000..d09f1da
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-vbi.c
@@ -0,0 +1,413 @@
+/*
+ * cx18 ADEC VBI functions
+ *
+ * Derived from cx25840-vbi.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+
+#include "cx18-driver.h"
+
+static int odd_parity(u8 c)
+{
+ c ^= (c >> 4);
+ c ^= (c >> 2);
+ c ^= (c >> 1);
+
+ return c & 1;
+}
+
+static int decode_vps(u8 *dst, u8 *p)
+{
+ static const u8 biphase_tbl[] = {
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
+ 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
+ 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
+ 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
+ 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
+ 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
+ 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
+ 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
+ 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
+ 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
+ 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
+ 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
+ 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
+ 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
+ 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
+ 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
+ };
+
+ u8 c, err = 0;
+ int i;
+
+ for (i = 0; i < 2 * 13; i += 2) {
+ err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
+ c = (biphase_tbl[p[i + 1]] & 0xf) |
+ ((biphase_tbl[p[i]] & 0xf) << 4);
+ dst[i / 2] = c;
+ }
+
+ return err & 0xf0;
+}
+
+void cx18_av_vbi_setup(struct cx18 *cx)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ v4l2_std_id std = state->std;
+ int hblank, hactive, burst, vblank, vactive, sc;
+ int vblank656, src_decimation;
+ int luma_lpf, uv_lpf, comb;
+ u32 pll_int, pll_frac, pll_post;
+
+ /* datasheet startup, step 8d */
+ if (std & ~V4L2_STD_NTSC)
+ cx18_av_write(cx, 0x49f, 0x11);
+ else
+ cx18_av_write(cx, 0x49f, 0x14);
+
+ if (std & V4L2_STD_625_50) {
+ hblank = 0x084;
+ hactive = 0x2d0;
+ burst = 0x5d;
+ vblank = 0x024;
+ vactive = 0x244;
+ vblank656 = 0x28;
+ src_decimation = 0x21f;
+
+ luma_lpf = 2;
+ if (std & V4L2_STD_SECAM) {
+ uv_lpf = 0;
+ comb = 0;
+ sc = 0x0a425f;
+ } else if (std == V4L2_STD_PAL_Nc) {
+ uv_lpf = 1;
+ comb = 0x20;
+ sc = 556453;
+ } else {
+ uv_lpf = 1;
+ comb = 0x20;
+ sc = 0x0a8263;
+ }
+ } else {
+ hactive = 720;
+ hblank = 122;
+ vactive = 487;
+ luma_lpf = 1;
+ uv_lpf = 1;
+
+ src_decimation = 0x21f;
+ if (std == V4L2_STD_PAL_60) {
+ vblank = 26;
+ vblank656 = 26;
+ burst = 0x5b;
+ luma_lpf = 2;
+ comb = 0x20;
+ sc = 0x0a8263;
+ } else if (std == V4L2_STD_PAL_M) {
+ vblank = 20;
+ vblank656 = 24;
+ burst = 0x61;
+ comb = 0x20;
+
+ sc = 555452;
+ } else {
+ vblank = 26;
+ vblank656 = 26;
+ burst = 0x5b;
+ comb = 0x66;
+ sc = 556063;
+ }
+ }
+
+ /* DEBUG: Displays configured PLL frequency */
+ pll_int = cx18_av_read(cx, 0x108);
+ pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
+ pll_post = cx18_av_read(cx, 0x109);
+ CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
+ pll_int, pll_frac, pll_post);
+
+ if (pll_post) {
+ int fin, fsc;
+ int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
+
+ pll >>= 25;
+ pll /= pll_post;
+ CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
+ pll / 1000000, pll % 1000000);
+ CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
+ pll / 8000000, (pll / 8) % 1000000);
+
+ fin = ((u64)src_decimation * pll) >> 12;
+ CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
+ fin / 1000000, fin % 1000000);
+
+ fsc = (((u64)sc) * pll) >> 24L;
+ CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
+ fsc / 1000000, fsc % 1000000);
+
+ CX18_DEBUG_INFO("hblank %i, hactive %i, "
+ "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+ "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+ " sc 0x%06x\n",
+ hblank, hactive, vblank, vactive, vblank656,
+ src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ }
+
+ /* Sets horizontal blanking delay and active lines */
+ cx18_av_write(cx, 0x470, hblank);
+ cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
+ (hactive << 4)));
+ cx18_av_write(cx, 0x472, hactive >> 4);
+
+ /* Sets burst gate delay */
+ cx18_av_write(cx, 0x473, burst);
+
+ /* Sets vertical blanking delay and active duration */
+ cx18_av_write(cx, 0x474, vblank);
+ cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
+ (vactive << 4)));
+ cx18_av_write(cx, 0x476, vactive >> 4);
+ cx18_av_write(cx, 0x477, vblank656);
+
+ /* Sets src decimation rate */
+ cx18_av_write(cx, 0x478, 0xff & src_decimation);
+ cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
+
+ /* Sets Luma and UV Low pass filters */
+ cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
+
+ /* Enables comb filters */
+ cx18_av_write(cx, 0x47b, comb);
+
+ /* Sets SC Step*/
+ cx18_av_write(cx, 0x47c, sc);
+ cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
+ cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
+
+ /* Sets VBI parameters */
+ if (std & V4L2_STD_625_50) {
+ cx18_av_write(cx, 0x47f, 0x01);
+ state->vbi_line_offset = 5;
+ } else {
+ cx18_av_write(cx, 0x47f, 0x00);
+ state->vbi_line_offset = 8;
+ }
+}
+
+int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct cx18_av_state *state = &cx->av_state;
+ struct v4l2_format *fmt;
+ struct v4l2_sliced_vbi_format *svbi;
+
+ switch (cmd) {
+ case VIDIOC_G_FMT:
+ {
+ static u16 lcr2vbi[] = {
+ 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
+ 0, V4L2_SLICED_WSS_625, 0, /* 4 */
+ V4L2_SLICED_CAPTION_525, /* 6 */
+ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
+ 0, 0, 0, 0
+ };
+ int is_pal = !(state->std & V4L2_STD_525_60);
+ int i;
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ memset(svbi, 0, sizeof(*svbi));
+ /* we're done if raw VBI is active */
+ if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
+ break;
+
+ if (is_pal) {
+ for (i = 7; i <= 23; i++) {
+ u8 v = cx18_av_read(cx, 0x424 + i - 7);
+
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |= svbi->service_lines[0][i] |
+ svbi->service_lines[1][i];
+ }
+ } else {
+ for (i = 10; i <= 21; i++) {
+ u8 v = cx18_av_read(cx, 0x424 + i - 10);
+
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |= svbi->service_lines[0][i] |
+ svbi->service_lines[1][i];
+ }
+ }
+ break;
+ }
+
+ case VIDIOC_S_FMT:
+ {
+ int is_pal = !(state->std & V4L2_STD_525_60);
+ int vbi_offset = is_pal ? 1 : 0;
+ int i, x;
+ u8 lcr[24];
+
+ fmt = arg;
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+ svbi = &fmt->fmt.sliced;
+ if (svbi->service_set == 0) {
+ /* raw VBI */
+ memset(svbi, 0, sizeof(*svbi));
+
+ /* Setup VBI */
+ cx18_av_vbi_setup(cx);
+
+ /* VBI Offset */
+ cx18_av_write(cx, 0x47f, vbi_offset);
+ cx18_av_write(cx, 0x404, 0x2e);
+ break;
+ }
+
+ for (x = 0; x <= 23; x++)
+ lcr[x] = 0x00;
+
+ /* Setup VBI */
+ cx18_av_vbi_setup(cx);
+
+ /* Sliced VBI */
+ cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
+ cx18_av_write(cx, 0x406, 0x13);
+ cx18_av_write(cx, 0x47f, vbi_offset);
+
+ if (is_pal) {
+ for (i = 0; i <= 6; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ } else {
+ for (i = 0; i <= 9; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+
+ for (i = 22; i <= 23; i++)
+ svbi->service_lines[0][i] =
+ svbi->service_lines[1][i] = 0;
+ }
+
+ for (i = 7; i <= 23; i++) {
+ for (x = 0; x <= 1; x++) {
+ switch (svbi->service_lines[1-x][i]) {
+ case V4L2_SLICED_TELETEXT_B:
+ lcr[i] |= 1 << (4 * x);
+ break;
+ case V4L2_SLICED_WSS_625:
+ lcr[i] |= 4 << (4 * x);
+ break;
+ case V4L2_SLICED_CAPTION_525:
+ lcr[i] |= 6 << (4 * x);
+ break;
+ case V4L2_SLICED_VPS:
+ lcr[i] |= 9 << (4 * x);
+ break;
+ }
+ }
+ }
+
+ if (is_pal) {
+ for (x = 1, i = 0x424; i <= 0x434; i++, x++)
+ cx18_av_write(cx, i, lcr[6 + x]);
+ } else {
+ for (x = 1, i = 0x424; i <= 0x430; i++, x++)
+ cx18_av_write(cx, i, lcr[9 + x]);
+ for (i = 0x431; i <= 0x434; i++)
+ cx18_av_write(cx, i, 0);
+ }
+
+ cx18_av_write(cx, 0x43c, 0x16);
+ cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22);
+ break;
+ }
+
+ case VIDIOC_INT_DECODE_VBI_LINE:
+ {
+ struct v4l2_decode_vbi_line *vbi = arg;
+ u8 *p = vbi->p;
+ int id1, id2, l, err = 0;
+
+ if (p[0] || p[1] != 0xff || p[2] != 0xff ||
+ (p[3] != 0x55 && p[3] != 0x91)) {
+ vbi->line = vbi->type = 0;
+ break;
+ }
+
+ p += 4;
+ id1 = p[-1];
+ id2 = p[0] & 0xf;
+ l = p[2] & 0x3f;
+ l += state->vbi_line_offset;
+ p += 4;
+
+ switch (id2) {
+ case 1:
+ id2 = V4L2_SLICED_TELETEXT_B;
+ break;
+ case 4:
+ id2 = V4L2_SLICED_WSS_625;
+ break;
+ case 6:
+ id2 = V4L2_SLICED_CAPTION_525;
+ err = !odd_parity(p[0]) || !odd_parity(p[1]);
+ break;
+ case 9:
+ id2 = V4L2_SLICED_VPS;
+ if (decode_vps(p, p) != 0)
+ err = 1;
+ break;
+ default:
+ id2 = 0;
+ err = 1;
+ break;
+ }
+
+ vbi->type = err ? 0 : id2;
+ vbi->line = err ? 0 : l;
+ vbi->is_second_field = err ? 0 : (id1 == 0x55);
+ vbi->p = p;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
new file mode 100644
index 0000000..f5e3ba1
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -0,0 +1,277 @@
+/*
+ * cx18 functions to query card hardware
+ *
+ * Derived from ivtv-cards.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-i2c.h"
+#include <media/cs5345.h>
+
+/********************** card configuration *******************************/
+
+/* usual i2c tuner addresses to probe */
+static struct cx18_card_tuner_i2c cx18_i2c_std = {
+ .radio = { I2C_CLIENT_END },
+ .demod = { 0x43, I2C_CLIENT_END },
+ .tv = { 0x61, 0x60, I2C_CLIENT_END },
+};
+
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
+ This keeps the PCI ID database up to date. Note that the entries
+ must be added under vendor 0x4444 (Conexant) as subsystem IDs.
+ New vendor IDs should still be added to the vendor ID list. */
+
+/* Hauppauge HVR-1600 cards */
+
+/* Note: for Hauppauge cards the tveeprom information is used instead
+ of PCI IDs */
+static const struct cx18_card cx18_card_hvr1600_esmt = {
+ .type = CX18_CARD_HVR_1600_ESMT,
+ .name = "Hauppauge HVR-1600",
+ .comment = "DVB & VBI are not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_muxer = CX18_HW_CS5345,
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ { CX18_CARD_INPUT_LINE_IN2,
+ CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO_SERIAL, 0 },
+ .ddr = {
+ /* ESMT M13S128324A-5B memory */
+ .chip_config = 0x003,
+ .refresh = 0x30c,
+ .timing1 = 0x44220e82,
+ .timing2 = 0x08,
+ .tune_lane = 0,
+ .initial_emrs = 0,
+ },
+ .gpio_init.initial_value = 0x3001,
+ .gpio_init.direction = 0x3001,
+ .i2c = &cx18_i2c_std,
+};
+
+static const struct cx18_card cx18_card_hvr1600_samsung = {
+ .type = CX18_CARD_HVR_1600_SAMSUNG,
+ .name = "Hauppauge HVR-1600 (Preproduction)",
+ .comment = "DVB & VBI are not yet supported\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_muxer = CX18_HW_CS5345,
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+ { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ { CX18_CARD_INPUT_LINE_IN2,
+ CX23418_AUDIO_SERIAL, CS5345_IN_2 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO_SERIAL, 0 },
+ .ddr = {
+ /* Samsung K4D263238G-VC33 memory */
+ .chip_config = 0x003,
+ .refresh = 0x30c,
+ .timing1 = 0x23230b73,
+ .timing2 = 0x08,
+ .tune_lane = 0,
+ .initial_emrs = 2,
+ },
+ .gpio_init.initial_value = 0x3001,
+ .gpio_init.direction = 0x3001,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Compro VideoMate H900: not working at the moment! */
+
+static const struct cx18_card_pci_info cx18_pci_h900[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_h900 = {
+ .type = CX18_CARD_COMPRO_H900,
+ .name = "Compro VideoMate H900",
+ .comment = "Not yet supported!\n",
+ .v4l2_capabilities = 0,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_all = CX18_HW_TUNER,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO8, 0 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX23418_AUDIO_SERIAL, 0 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO_SERIAL, 0 },
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .ddr = {
+ /* EtronTech EM6A9160TS-5G memory */
+ .chip_config = 0x50003,
+ .refresh = 0x753,
+ .timing1 = 0x24330e84,
+ .timing2 = 0x1f,
+ .tune_lane = 0,
+ .initial_emrs = 0,
+ },
+ .pci_list = cx18_pci_h900,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Yuan MPC718: not working at the moment! */
+
+static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_mpc718 = {
+ .type = CX18_CARD_YUAN_MPC718,
+ .name = "Yuan MPC718",
+ .comment = "Not yet supported!\n",
+ .v4l2_capabilities = 0,
+ .hw_audio_ctrl = CX18_HW_CX23418,
+ .hw_all = CX18_HW_TUNER,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
+ { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO8, 0 },
+ { CX18_CARD_INPUT_LINE_IN1,
+ CX23418_AUDIO_SERIAL, 0 },
+ },
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
+ CX23418_AUDIO_SERIAL, 0 },
+ .tuners = {
+ /* XC3028 tuner */
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ /* tuner reset */
+ .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 },
+ .ddr = {
+ /* Probably Samsung K4D263238G-VC33 memory */
+ .chip_config = 0x003,
+ .refresh = 0x30c,
+ .timing1 = 0x23230b73,
+ .timing2 = 0x08,
+ .tune_lane = 0,
+ .initial_emrs = 2,
+ },
+ .pci_list = cx18_pci_mpc718,
+ .i2c = &cx18_i2c_std,
+};
+
+static const struct cx18_card *cx18_card_list[] = {
+ &cx18_card_hvr1600_esmt,
+ &cx18_card_hvr1600_samsung,
+ &cx18_card_h900,
+ &cx18_card_mpc718,
+};
+
+const struct cx18_card *cx18_get_card(u16 index)
+{
+ if (index >= ARRAY_SIZE(cx18_card_list))
+ return NULL;
+ return cx18_card_list[index];
+}
+
+int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input)
+{
+ const struct cx18_card_video_input *card_input =
+ cx->card->video_inputs + index;
+ static const char * const input_strs[] = {
+ "Tuner 1",
+ "S-Video 1",
+ "S-Video 2",
+ "Composite 1",
+ "Composite 2",
+ "Composite 3"
+ };
+
+ memset(input, 0, sizeof(*input));
+ if (index >= cx->nof_inputs)
+ return -EINVAL;
+ input->index = index;
+ strlcpy(input->name, input_strs[card_input->video_type - 1],
+ sizeof(input->name));
+ input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ?
+ V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
+ input->audioset = (1 << cx->nof_audio_inputs) - 1;
+ input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ?
+ cx->tuner_std : V4L2_STD_ALL;
+ return 0;
+}
+
+int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio)
+{
+ const struct cx18_card_audio_input *aud_input =
+ cx->card->audio_inputs + index;
+ static const char * const input_strs[] = {
+ "Tuner 1",
+ "Line In 1",
+ "Line In 2"
+ };
+
+ memset(audio, 0, sizeof(*audio));
+ if (index >= cx->nof_audio_inputs)
+ return -EINVAL;
+ strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
+ sizeof(audio->name));
+ audio->index = index;
+ audio->capability = V4L2_AUDCAP_STEREO;
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
new file mode 100644
index 0000000..bca249b
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -0,0 +1,170 @@
+/*
+ * cx18 functions to query card hardware
+ *
+ * Derived from ivtv-cards.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* hardware flags */
+#define CX18_HW_TUNER (1 << 0)
+#define CX18_HW_TVEEPROM (1 << 1)
+#define CX18_HW_CS5345 (1 << 2)
+#define CX18_HW_GPIO (1 << 3)
+#define CX18_HW_CX23418 (1 << 4)
+#define CX18_HW_DVB (1 << 5)
+
+/* video inputs */
+#define CX18_CARD_INPUT_VID_TUNER 1
+#define CX18_CARD_INPUT_SVIDEO1 2
+#define CX18_CARD_INPUT_SVIDEO2 3
+#define CX18_CARD_INPUT_COMPOSITE1 4
+#define CX18_CARD_INPUT_COMPOSITE2 5
+#define CX18_CARD_INPUT_COMPOSITE3 6
+
+enum cx34180_video_input {
+ /* Composite video inputs In1-In8 */
+ CX23418_COMPOSITE1 = 1,
+ CX23418_COMPOSITE2,
+ CX23418_COMPOSITE3,
+ CX23418_COMPOSITE4,
+ CX23418_COMPOSITE5,
+ CX23418_COMPOSITE6,
+ CX23418_COMPOSITE7,
+ CX23418_COMPOSITE8,
+
+ /* S-Video inputs consist of one luma input (In1-In4) ORed with one
+ chroma input (In5-In8) */
+ CX23418_SVIDEO_LUMA1 = 0x10,
+ CX23418_SVIDEO_LUMA2 = 0x20,
+ CX23418_SVIDEO_LUMA3 = 0x30,
+ CX23418_SVIDEO_LUMA4 = 0x40,
+ CX23418_SVIDEO_CHROMA4 = 0x400,
+ CX23418_SVIDEO_CHROMA5 = 0x500,
+ CX23418_SVIDEO_CHROMA6 = 0x600,
+ CX23418_SVIDEO_CHROMA7 = 0x700,
+ CX23418_SVIDEO_CHROMA8 = 0x800,
+
+ /* S-Video aliases for common luma/chroma combinations */
+ CX23418_SVIDEO1 = 0x510,
+ CX23418_SVIDEO2 = 0x620,
+ CX23418_SVIDEO3 = 0x730,
+ CX23418_SVIDEO4 = 0x840,
+};
+
+/* audio inputs */
+#define CX18_CARD_INPUT_AUD_TUNER 1
+#define CX18_CARD_INPUT_LINE_IN1 2
+#define CX18_CARD_INPUT_LINE_IN2 3
+
+#define CX18_CARD_MAX_VIDEO_INPUTS 6
+#define CX18_CARD_MAX_AUDIO_INPUTS 3
+#define CX18_CARD_MAX_TUNERS 2
+
+enum cx23418_audio_input {
+ /* Audio inputs: serial or In4-In8 */
+ CX23418_AUDIO_SERIAL,
+ CX23418_AUDIO4 = 4,
+ CX23418_AUDIO5,
+ CX23418_AUDIO6,
+ CX23418_AUDIO7,
+ CX23418_AUDIO8,
+};
+
+/* V4L2 capability aliases */
+#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
+ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
+/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
+
+struct cx18_card_video_input {
+ u8 video_type; /* video input type */
+ u8 audio_index; /* index in cx18_card_audio_input array */
+ u16 video_input; /* hardware video input */
+};
+
+struct cx18_card_audio_input {
+ u8 audio_type; /* audio input type */
+ u32 audio_input; /* hardware audio input */
+ u16 muxer_input; /* hardware muxer input for boards with a
+ multiplexer chip */
+};
+
+struct cx18_card_pci_info {
+ u16 device;
+ u16 subsystem_vendor;
+ u16 subsystem_device;
+};
+
+/* GPIO definitions */
+
+/* The mask is the set of bits used by the operation */
+
+struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
+ u16 direction; /* DIR setting. Leave to 0 if no init is needed */
+ u16 initial_value;
+};
+
+struct cx18_card_tuner {
+ v4l2_std_id std; /* standard for which the tuner is suitable */
+ int tuner; /* tuner ID (from tuner.h) */
+};
+
+struct cx18_card_tuner_i2c {
+ unsigned short radio[2];/* radio tuner i2c address to probe */
+ unsigned short demod[2];/* demodulator i2c address to probe */
+ unsigned short tv[4]; /* tv tuner i2c addresses to probe */
+};
+
+struct cx18_ddr { /* DDR config data */
+ u32 chip_config;
+ u32 refresh;
+ u32 timing1;
+ u32 timing2;
+ u32 tune_lane;
+ u32 initial_emrs;
+};
+
+/* for card information/parameters */
+struct cx18_card {
+ int type;
+ char *name;
+ char *comment;
+ u32 v4l2_capabilities;
+ u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only
+ 1 dev allowed) */
+ u32 hw_muxer; /* hardware used to multiplex audio input */
+ u32 hw_all; /* all hardware used by the board */
+ struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS];
+ struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS];
+ struct cx18_card_audio_input radio_input;
+
+ /* GPIO card-specific settings */
+ struct cx18_gpio_init gpio_init;
+
+ struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
+ struct cx18_card_tuner_i2c *i2c;
+
+ struct cx18_ddr ddr;
+
+ /* list of device and subsystem vendor/devices that
+ correspond to this card type. */
+ const struct cx18_card_pci_info *pci_list;
+};
+
+int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input);
+int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input);
+const struct cx18_card *cx18_get_card(u16 index);
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
new file mode 100644
index 0000000..2bdac5e
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -0,0 +1,306 @@
+/*
+ * cx18 ioctl control functions
+ *
+ * Derived from ivtv-controls.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-av-core.h"
+#include "cx18-cards.h"
+#include "cx18-ioctl.h"
+#include "cx18-audio.h"
+#include "cx18-i2c.h"
+#include "cx18-mailbox.h"
+#include "cx18-controls.h"
+
+static const u32 user_ctrls[] = {
+ V4L2_CID_USER_CLASS,
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_AUDIO_VOLUME,
+ V4L2_CID_AUDIO_BALANCE,
+ V4L2_CID_AUDIO_BASS,
+ V4L2_CID_AUDIO_TREBLE,
+ V4L2_CID_AUDIO_MUTE,
+ V4L2_CID_AUDIO_LOUDNESS,
+ 0
+};
+
+static const u32 *ctrl_classes[] = {
+ user_ctrls,
+ cx2341x_mpeg_ctrls,
+ NULL
+};
+
+static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
+{
+ const char *name;
+
+ CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
+
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+
+ switch (qctrl->id) {
+ /* Standard V4L2 controls */
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+ if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+
+ default:
+ if (cx2341x_ctrl_query(&cx->params, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+ return 0;
+ }
+ strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
+ qctrl->name[sizeof(qctrl->name) - 1] = 0;
+ return 0;
+}
+
+static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+
+ qctrl.id = qmenu->id;
+ cx18_queryctrl(cx, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
+}
+
+static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+{
+ s32 v = vctrl->value;
+
+ CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
+
+ switch (vctrl->id) {
+ /* Standard V4L2 controls */
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+ return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl);
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
+
+ default:
+ CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
+{
+ CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
+
+ switch (vctrl->id) {
+ /* Standard V4L2 controls */
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_HUE:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_CONTRAST:
+ return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl);
+
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
+ default:
+ CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt)
+{
+ if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
+ return -EINVAL;
+ if (atomic_read(&cx->capturing) > 0)
+ return -EBUSY;
+
+ /* First try to allocate sliced VBI buffers if needed. */
+ if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) {
+ int i;
+
+ for (i = 0; i < CX18_VBI_FRAMES; i++) {
+ /* Yuck, hardcoded. Needs to be a define */
+ cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
+ if (cx->vbi.sliced_mpeg_data[i] == NULL) {
+ while (--i >= 0) {
+ kfree(cx->vbi.sliced_mpeg_data[i]);
+ cx->vbi.sliced_mpeg_data[i] = NULL;
+ }
+ return -ENOMEM;
+ }
+ }
+ }
+
+ cx->vbi.insert_mpeg = fmt;
+
+ if (cx->vbi.insert_mpeg == 0)
+ return 0;
+ /* Need sliced data for mpeg insertion */
+ if (cx18_get_service_set(cx->vbi.sliced_in) == 0) {
+ if (cx->is_60hz)
+ cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
+ else
+ cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
+ cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
+ }
+ return 0;
+}
+
+int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct v4l2_control ctrl;
+
+ switch (cmd) {
+ case VIDIOC_QUERYMENU:
+ CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
+ return cx18_querymenu(cx, arg);
+
+ case VIDIOC_QUERYCTRL:
+ return cx18_queryctrl(cx, arg);
+
+ case VIDIOC_S_CTRL:
+ return cx18_s_ctrl(cx, arg);
+
+ case VIDIOC_G_CTRL:
+ return cx18_g_ctrl(cx, arg);
+
+ case VIDIOC_S_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *c = arg;
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_s_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ struct cx2341x_mpeg_params p = cx->params;
+ int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->capturing), arg, cmd);
+
+ if (err)
+ return err;
+
+ if (p.video_encoding != cx->params.video_encoding) {
+ int is_mpeg1 = p.video_encoding ==
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ struct v4l2_format fmt;
+
+ /* fix videodecoder resolution */
+ fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1);
+ fmt.fmt.pix.height = cx->params.height;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
+ }
+ err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
+ if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
+ err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
+ cx->params = p;
+ cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
+ cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
+ return err;
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *c = arg;
+
+ if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
+ int i;
+ int err = 0;
+
+ for (i = 0; i < c->count; i++) {
+ ctrl.id = c->controls[i].id;
+ ctrl.value = c->controls[i].value;
+ err = cx18_g_ctrl(cx, &ctrl);
+ c->controls[i].value = ctrl.value;
+ if (err) {
+ c->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd);
+ return -EINVAL;
+ }
+
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *c = arg;
+
+ CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
+ if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
+ return cx2341x_ext_ctrls(&cx->params,
+ atomic_read(&cx->capturing), arg, cmd);
+ return -EINVAL;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h
new file mode 100644
index 0000000..6e985cf
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-controls.h
@@ -0,0 +1,24 @@
+/*
+ * cx18 ioctl control functions
+ *
+ * Derived from ivtv-controls.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
new file mode 100644
index 0000000..8f5ed9b
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -0,0 +1,971 @@
+/*
+ * cx18 driver initialization and card probing
+ *
+ * Derived from ivtv-driver.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-version.h"
+#include "cx18-cards.h"
+#include "cx18-i2c.h"
+#include "cx18-irq.h"
+#include "cx18-gpio.h"
+#include "cx18-firmware.h"
+#include "cx18-streams.h"
+#include "cx18-av-core.h"
+#include "cx18-scb.h"
+#include "cx18-mailbox.h"
+#include "cx18-ioctl.h"
+#include "tuner-xc2028.h"
+
+#include <media/tveeprom.h>
+
+
+/* var to keep track of the number of array elements in use */
+int cx18_cards_active;
+
+/* If you have already X v4l cards, then set this to X. This way
+ the device numbers stay matched. Example: you have a WinTV card
+ without radio and a Compro H900 with. Normally this would give a
+ video1 device together with a radio0 device for the Compro. By
+ setting this to 1 you ensure that radio0 is now also radio1. */
+int cx18_first_minor;
+
+/* Master variable for all cx18 info */
+struct cx18 *cx18_cards[CX18_MAX_CARDS];
+
+/* Protects cx18_cards_active */
+DEFINE_SPINLOCK(cx18_cards_lock);
+
+/* add your revision and whatnot here */
+static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
+ {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ {0,}
+};
+
+MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
+
+/* Parameter declarations */
+static int cardtype[CX18_MAX_CARDS];
+static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1 };
+
+static int cardtype_c = 1;
+static int tuner_c = 1;
+static int radio_c = 1;
+static char pal[] = "--";
+static char secam[] = "--";
+static char ntsc[] = "-";
+
+/* Buffers */
+static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
+static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
+static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
+static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
+static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
+
+static int cx18_pci_latency = 1;
+
+int cx18_debug;
+
+module_param_array(tuner, int, &tuner_c, 0644);
+module_param_array(radio, bool, &radio_c, 0644);
+module_param_array(cardtype, int, &cardtype_c, 0644);
+module_param_string(pal, pal, sizeof(pal), 0644);
+module_param_string(secam, secam, sizeof(secam), 0644);
+module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
+module_param_named(debug, cx18_debug, int, 0644);
+module_param(cx18_pci_latency, int, 0644);
+module_param(cx18_first_minor, int, 0644);
+
+module_param(enc_mpg_buffers, int, 0644);
+module_param(enc_ts_buffers, int, 0644);
+module_param(enc_yuv_buffers, int, 0644);
+module_param(enc_vbi_buffers, int, 0644);
+module_param(enc_pcm_buffers, int, 0644);
+
+MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
+ "\t\t\tsee tuner.h for values");
+MODULE_PARM_DESC(radio,
+ "Enable or disable the radio. Use only if autodetection\n"
+ "\t\t\tfails. 0 = disable, 1 = enable");
+MODULE_PARM_DESC(cardtype,
+ "Only use this option if your card is not detected properly.\n"
+ "\t\tSpecify card type:\n"
+ "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n"
+ "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
+ "\t\t\t 3 = Compro VideoMate H900\n"
+ "\t\t\t 4 = Yuan MPC718\n"
+ "\t\t\t 0 = Autodetect (default)\n"
+ "\t\t\t-1 = Ignore this card\n\t\t");
+MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
+MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
+MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
+MODULE_PARM_DESC(debug,
+ "Debug level (bitmask). Default: 0\n"
+ "\t\t\t 1/0x0001: warning\n"
+ "\t\t\t 2/0x0002: info\n"
+ "\t\t\t 4/0x0004: mailbox\n"
+ "\t\t\t 8/0x0008: dma\n"
+ "\t\t\t 16/0x0010: ioctl\n"
+ "\t\t\t 32/0x0020: file\n"
+ "\t\t\t 64/0x0040: i2c\n"
+ "\t\t\t128/0x0080: irq\n"
+ "\t\t\t256/0x0100: high volume\n");
+MODULE_PARM_DESC(cx18_pci_latency,
+ "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
+ "\t\t\tDefault: Yes");
+MODULE_PARM_DESC(enc_mpg_buffers,
+ "Encoder MPG Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
+MODULE_PARM_DESC(enc_ts_buffers,
+ "Encoder TS Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
+MODULE_PARM_DESC(enc_yuv_buffers,
+ "Encoder YUV Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
+MODULE_PARM_DESC(enc_vbi_buffers,
+ "Encoder VBI Buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
+MODULE_PARM_DESC(enc_pcm_buffers,
+ "Encoder PCM buffers (in MB)\n"
+ "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
+
+MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card");
+
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_DESCRIPTION("CX23418 driver");
+MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
+MODULE_LICENSE("GPL");
+
+MODULE_VERSION(CX18_VERSION);
+
+int cx18_waitq(wait_queue_head_t *waitq)
+{
+ DEFINE_WAIT(wait);
+
+ prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE);
+ schedule();
+ finish_wait(waitq, &wait);
+ return signal_pending(current) ? -EINTR : 0;
+}
+
+/* Generic utility functions */
+int cx18_msleep_timeout(unsigned int msecs, int intr)
+{
+ int timeout = msecs_to_jiffies(msecs);
+ int sig;
+
+ do {
+ set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
+ timeout = schedule_timeout(timeout);
+ sig = intr ? signal_pending(current) : 0;
+ } while (!sig && timeout);
+ return sig;
+}
+
+/* Release ioremapped memory */
+static void cx18_iounmap(struct cx18 *cx)
+{
+ if (cx == NULL)
+ return;
+
+ /* Release io memory */
+ if (cx->enc_mem != NULL) {
+ CX18_DEBUG_INFO("releasing enc_mem\n");
+ iounmap(cx->enc_mem);
+ cx->enc_mem = NULL;
+ }
+}
+
+/* Hauppauge card? get values from tveeprom */
+void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
+{
+ u8 eedata[256];
+
+ cx->i2c_client[0].addr = 0xA0 >> 1;
+ tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata));
+ tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata);
+}
+
+static void cx18_process_eeprom(struct cx18 *cx)
+{
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+
+ /* Many thanks to Steven Toth from Hauppauge for providing the
+ model numbers */
+ switch (tv.model) {
+ case 74000 ... 74099:
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ break;
+ case 74700 ... 74799:
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_SAMSUNG);
+ break;
+ case 0:
+ CX18_ERR("Invalid EEPROM\n");
+ return;
+ default:
+ CX18_ERR("Unknown model %d, defaulting to HVR-1600\n", tv.model);
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ break;
+ }
+
+ cx->v4l2_cap = cx->card->v4l2_capabilities;
+ cx->card_name = cx->card->name;
+ cx->card_i2c = cx->card->i2c;
+
+ CX18_INFO("Autodetected %s\n", cx->card_name);
+
+ if (tv.tuner_type == TUNER_ABSENT)
+ CX18_ERR("tveeprom cannot autodetect tuner!");
+
+ if (cx->options.tuner == -1)
+ cx->options.tuner = tv.tuner_type;
+ if (cx->options.radio == -1)
+ cx->options.radio = (tv.has_radio != 0);
+
+ if (cx->std != 0)
+ /* user specified tuner standard */
+ return;
+
+ /* autodetect tuner standard */
+ if (tv.tuner_formats & V4L2_STD_PAL) {
+ CX18_DEBUG_INFO("PAL tuner detected\n");
+ cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
+ } else if (tv.tuner_formats & V4L2_STD_NTSC) {
+ CX18_DEBUG_INFO("NTSC tuner detected\n");
+ cx->std |= V4L2_STD_NTSC_M;
+ } else if (tv.tuner_formats & V4L2_STD_SECAM) {
+ CX18_DEBUG_INFO("SECAM tuner detected\n");
+ cx->std |= V4L2_STD_SECAM_L;
+ } else {
+ CX18_INFO("No tuner detected, default to NTSC-M\n");
+ cx->std |= V4L2_STD_NTSC_M;
+ }
+}
+
+static v4l2_std_id cx18_parse_std(struct cx18 *cx)
+{
+ switch (pal[0]) {
+ case '6':
+ return V4L2_STD_PAL_60;
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ return V4L2_STD_PAL_BG;
+ case 'h':
+ case 'H':
+ return V4L2_STD_PAL_H;
+ case 'n':
+ case 'N':
+ if (pal[1] == 'c' || pal[1] == 'C')
+ return V4L2_STD_PAL_Nc;
+ return V4L2_STD_PAL_N;
+ case 'i':
+ case 'I':
+ return V4L2_STD_PAL_I;
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ return V4L2_STD_PAL_DK;
+ case 'M':
+ case 'm':
+ return V4L2_STD_PAL_M;
+ case '-':
+ break;
+ default:
+ CX18_WARN("pal= argument not recognised\n");
+ return 0;
+ }
+
+ switch (secam[0]) {
+ case 'b':
+ case 'B':
+ case 'g':
+ case 'G':
+ case 'h':
+ case 'H':
+ return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ return V4L2_STD_SECAM_DK;
+ case 'l':
+ case 'L':
+ if (secam[1] == 'C' || secam[1] == 'c')
+ return V4L2_STD_SECAM_LC;
+ return V4L2_STD_SECAM_L;
+ case '-':
+ break;
+ default:
+ CX18_WARN("secam= argument not recognised\n");
+ return 0;
+ }
+
+ switch (ntsc[0]) {
+ case 'm':
+ case 'M':
+ return V4L2_STD_NTSC_M;
+ case 'j':
+ case 'J':
+ return V4L2_STD_NTSC_M_JP;
+ case 'k':
+ case 'K':
+ return V4L2_STD_NTSC_M_KR;
+ case '-':
+ break;
+ default:
+ CX18_WARN("ntsc= argument not recognised\n");
+ return 0;
+ }
+
+ /* no match found */
+ return 0;
+}
+
+static void cx18_process_options(struct cx18 *cx)
+{
+ int i, j;
+
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
+ cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
+ cx->options.cardtype = cardtype[cx->num];
+ cx->options.tuner = tuner[cx->num];
+ cx->options.radio = radio[cx->num];
+
+ cx->std = cx18_parse_std(cx);
+ if (cx->options.cardtype == -1) {
+ CX18_INFO("Ignore card\n");
+ return;
+ }
+ cx->card = cx18_get_card(cx->options.cardtype - 1);
+ if (cx->card)
+ CX18_INFO("User specified %s card\n", cx->card->name);
+ else if (cx->options.cardtype != 0)
+ CX18_ERR("Unknown user specified type, trying to autodetect card\n");
+ if (cx->card == NULL) {
+ if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_INFO("Autodetected Hauppauge card\n");
+ }
+ }
+ if (cx->card == NULL) {
+ for (i = 0; (cx->card = cx18_get_card(i)); i++) {
+ if (cx->card->pci_list == NULL)
+ continue;
+ for (j = 0; cx->card->pci_list[j].device; j++) {
+ if (cx->dev->device !=
+ cx->card->pci_list[j].device)
+ continue;
+ if (cx->dev->subsystem_vendor !=
+ cx->card->pci_list[j].subsystem_vendor)
+ continue;
+ if (cx->dev->subsystem_device !=
+ cx->card->pci_list[j].subsystem_device)
+ continue;
+ CX18_INFO("Autodetected %s card\n", cx->card->name);
+ goto done;
+ }
+ }
+ }
+done:
+
+ if (cx->card == NULL) {
+ cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
+ CX18_ERR("Unknown card: vendor/device: %04x/%04x\n",
+ cx->dev->vendor, cx->dev->device);
+ CX18_ERR(" subsystem vendor/device: %04x/%04x\n",
+ cx->dev->subsystem_vendor, cx->dev->subsystem_device);
+ CX18_ERR("Defaulting to %s card\n", cx->card->name);
+ CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
+ CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
+ CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n");
+ }
+ cx->v4l2_cap = cx->card->v4l2_capabilities;
+ cx->card_name = cx->card->name;
+ cx->card_i2c = cx->card->i2c;
+}
+
+/* Precondition: the cx18 structure has been memset to 0. Only
+ the dev and num fields have been filled in.
+ No assumptions on the card type may be made here (see cx18_init_struct2
+ for that).
+ */
+static int __devinit cx18_init_struct1(struct cx18 *cx)
+{
+ cx->base_addr = pci_resource_start(cx->dev, 0);
+
+ mutex_init(&cx->serialize_lock);
+ mutex_init(&cx->i2c_bus_lock[0]);
+ mutex_init(&cx->i2c_bus_lock[1]);
+
+ spin_lock_init(&cx->lock);
+ spin_lock_init(&cx->dma_reg_lock);
+
+ /* start counting open_id at 1 */
+ cx->open_id = 1;
+
+ /* Initial settings */
+ cx2341x_fill_defaults(&cx->params);
+ cx->temporal_strength = cx->params.video_temporal_filter;
+ cx->spatial_strength = cx->params.video_spatial_filter;
+ cx->filter_mode = cx->params.video_spatial_filter_mode |
+ (cx->params.video_temporal_filter_mode << 1) |
+ (cx->params.video_median_filter_type << 2);
+ cx->params.port = CX2341X_PORT_MEMORY;
+ cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+ init_waitqueue_head(&cx->cap_w);
+ init_waitqueue_head(&cx->mb_apu_waitq);
+ init_waitqueue_head(&cx->mb_cpu_waitq);
+ init_waitqueue_head(&cx->mb_epu_waitq);
+ init_waitqueue_head(&cx->mb_hpu_waitq);
+ init_waitqueue_head(&cx->dma_waitq);
+
+ /* VBI */
+ cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
+ cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
+ cx->vbi.raw_size = 1456;
+ cx->vbi.raw_decoder_line_size = 1456;
+ cx->vbi.raw_decoder_sav_odd_field = 0x20;
+ cx->vbi.raw_decoder_sav_even_field = 0x60;
+ cx->vbi.sliced_decoder_line_size = 272;
+ cx->vbi.sliced_decoder_sav_odd_field = 0xB0;
+ cx->vbi.sliced_decoder_sav_even_field = 0xF0;
+ return 0;
+}
+
+/* Second initialization part. Here the card type has been
+ autodetected. */
+static void __devinit cx18_init_struct2(struct cx18 *cx)
+{
+ int i;
+
+ for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++)
+ if (cx->card->video_inputs[i].video_type == 0)
+ break;
+ cx->nof_inputs = i;
+ for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++)
+ if (cx->card->audio_inputs[i].audio_type == 0)
+ break;
+ cx->nof_audio_inputs = i;
+
+ /* Find tuner input */
+ for (i = 0; i < cx->nof_inputs; i++) {
+ if (cx->card->video_inputs[i].video_type ==
+ CX18_CARD_INPUT_VID_TUNER)
+ break;
+ }
+ if (i == cx->nof_inputs)
+ i = 0;
+ cx->active_input = i;
+ cx->audio_input = cx->card->video_inputs[i].audio_index;
+ cx->av_state.vid_input = CX18_AV_COMPOSITE7;
+ cx->av_state.aud_input = CX18_AV_AUDIO8;
+ cx->av_state.audclk_freq = 48000;
+ cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
+ cx->av_state.vbi_line_offset = 8;
+}
+
+static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
+ const struct pci_device_id *pci_id)
+{
+ u16 cmd;
+ unsigned char pci_latency;
+
+ CX18_DEBUG_INFO("Enabling pci device\n");
+
+ if (pci_enable_device(dev)) {
+ CX18_ERR("Can't enable device %d!\n", cx->num);
+ return -EIO;
+ }
+ if (pci_set_dma_mask(dev, 0xffffffff)) {
+ CX18_ERR("No suitable DMA available on card %d.\n", cx->num);
+ return -EIO;
+ }
+ if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
+ CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num);
+ return -EIO;
+ }
+
+ /* Check for bus mastering */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
+ pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+
+ if (pci_latency < 64 && cx18_pci_latency) {
+ CX18_INFO("Unreasonably low latency timer, "
+ "setting to 64 (was %d)\n", pci_latency);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
+ }
+ /* This config space value relates to DMA latencies. The
+ default value 0x8080 is too low however and will lead
+ to DMA errors. 0xffff is the max value which solves
+ these problems. */
+ pci_write_config_dword(dev, 0x40, 0xffff);
+
+ CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
+ "irq: %d, latency: %d, memory: 0x%lx\n",
+ cx->dev->device, cx->card_rev, dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
+ cx->dev->irq, pci_latency, (unsigned long)cx->base_addr);
+
+ return 0;
+}
+
+static u32 cx18_request_module(struct cx18 *cx, u32 hw,
+ const char *name, u32 id)
+{
+ if ((hw & id) == 0)
+ return hw;
+ if (request_module(name) != 0) {
+ CX18_ERR("Failed to load module %s\n", name);
+ return hw & ~id;
+ }
+ CX18_DEBUG_INFO("Loaded module %s\n", name);
+ return hw;
+}
+
+static void cx18_load_and_init_modules(struct cx18 *cx)
+{
+ u32 hw = cx->card->hw_all;
+ int i;
+
+ /* load modules */
+#ifndef CONFIG_MEDIA_TUNER
+ hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER);
+#endif
+#ifndef CONFIG_VIDEO_CS5345
+ hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345);
+#endif
+
+ /* check which i2c devices are actually found */
+ for (i = 0; i < 32; i++) {
+ u32 device = 1 << i;
+
+ if (!(device & hw))
+ continue;
+ if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM ||
+ device == CX18_HW_CX23418 || device == CX18_HW_DVB) {
+ /* These 'devices' do not use i2c probing */
+ cx->hw_flags |= device;
+ continue;
+ }
+ cx18_i2c_register(cx, i);
+ if (cx18_i2c_hw_addr(cx, device) > 0)
+ cx->hw_flags |= device;
+ }
+
+ hw = cx->hw_flags;
+}
+
+static int __devinit cx18_probe(struct pci_dev *dev,
+ const struct pci_device_id *pci_id)
+{
+ int retval = 0;
+ int vbi_buf_size;
+ u32 devtype;
+ struct cx18 *cx;
+
+ spin_lock(&cx18_cards_lock);
+
+ /* Make sure we've got a place for this card */
+ if (cx18_cards_active == CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n",
+ cx18_cards_active);
+ spin_unlock(&cx18_cards_lock);
+ return -ENOMEM;
+ }
+
+ cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
+ if (cx == 0) {
+ spin_unlock(&cx18_cards_lock);
+ return -ENOMEM;
+ }
+ cx18_cards[cx18_cards_active] = cx;
+ cx->dev = dev;
+ cx->num = cx18_cards_active++;
+ snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num);
+ CX18_INFO("Initializing card #%d\n", cx->num);
+
+ spin_unlock(&cx18_cards_lock);
+
+ cx18_process_options(cx);
+ if (cx->options.cardtype == -1) {
+ retval = -ENODEV;
+ goto err;
+ }
+ if (cx18_init_struct1(cx)) {
+ retval = -ENOMEM;
+ goto err;
+ }
+
+ CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
+
+ /* PCI Device Setup */
+ retval = cx18_setup_pci(cx, dev, pci_id);
+ if (retval != 0) {
+ if (retval == -EIO)
+ goto free_workqueue;
+ else if (retval == -ENXIO)
+ goto free_mem;
+ }
+ /* save cx in the pci struct for later use */
+ pci_set_drvdata(dev, cx);
+
+ /* map io memory */
+ CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
+ cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
+ cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
+ CX18_MEM_SIZE);
+ if (!cx->enc_mem) {
+ CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
+ CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ retval = -ENOMEM;
+ goto free_mem;
+ }
+ cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
+ devtype = read_reg(0xC72028);
+ switch (devtype & 0xff000000) {
+ case 0xff000000:
+ CX18_INFO("cx23418 revision %08x (A)\n", devtype);
+ break;
+ case 0x01000000:
+ CX18_INFO("cx23418 revision %08x (B)\n", devtype);
+ break;
+ default:
+ CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype);
+ break;
+ }
+
+ cx18_init_power(cx, 1);
+ cx18_init_memory(cx);
+
+ cx->scb = (struct cx18_scb *)(cx->enc_mem + SCB_OFFSET);
+ cx18_init_scb(cx);
+
+ cx18_gpio_init(cx);
+
+ /* active i2c */
+ CX18_DEBUG_INFO("activating i2c...\n");
+ if (init_cx18_i2c(cx)) {
+ CX18_ERR("Could not initialize i2c\n");
+ goto free_map;
+ }
+
+ CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active);
+
+ if (cx->card->hw_all & CX18_HW_TVEEPROM) {
+ /* Based on the model number the cardtype may be changed.
+ The PCI IDs are not always reliable. */
+ cx18_process_eeprom(cx);
+ }
+ if (cx->card->comment)
+ CX18_INFO("%s", cx->card->comment);
+ if (cx->card->v4l2_capabilities == 0) {
+ retval = -ENODEV;
+ goto free_i2c;
+ }
+ cx18_init_memory(cx);
+
+ /* Register IRQ */
+ retval = request_irq(cx->dev->irq, cx18_irq_handler,
+ IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx);
+ if (retval) {
+ CX18_ERR("Failed to register irq %d\n", retval);
+ goto free_i2c;
+ }
+
+ if (cx->std == 0)
+ cx->std = V4L2_STD_NTSC_M;
+
+ if (cx->options.tuner == -1) {
+ int i;
+
+ for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) {
+ if ((cx->std & cx->card->tuners[i].std) == 0)
+ continue;
+ cx->options.tuner = cx->card->tuners[i].tuner;
+ break;
+ }
+ }
+ /* if no tuner was found, then pick the first tuner in the card list */
+ if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
+ cx->std = cx->card->tuners[0].std;
+ cx->options.tuner = cx->card->tuners[0].tuner;
+ }
+ if (cx->options.radio == -1)
+ cx->options.radio = (cx->card->radio_input.audio_type != 0);
+
+ /* The card is now fully identified, continue with card-specific
+ initialization. */
+ cx18_init_struct2(cx);
+
+ cx18_load_and_init_modules(cx);
+
+ if (cx->std & V4L2_STD_525_60) {
+ cx->is_60hz = 1;
+ cx->is_out_60hz = 1;
+ } else {
+ cx->is_50hz = 1;
+ cx->is_out_50hz = 1;
+ }
+ cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
+
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000;
+ vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
+ cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
+
+ if (cx->options.radio > 0)
+ cx->v4l2_cap |= V4L2_CAP_RADIO;
+
+ retval = cx18_streams_setup(cx);
+ if (retval) {
+ CX18_ERR("Error %d setting up streams\n", retval);
+ goto free_irq;
+ }
+ retval = cx18_streams_register(cx);
+ if (retval) {
+ CX18_ERR("Error %d registering devices\n", retval);
+ goto free_streams;
+ }
+
+ if (cx->options.tuner > -1) {
+ struct tuner_setup setup;
+
+ setup.addr = ADDR_UNSET;
+ setup.type = cx->options.tuner;
+ setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
+ setup.tuner_callback = (setup.type == TUNER_XC2028) ?
+ cx18_reset_tuner_gpio : NULL;
+ cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup);
+ if (setup.type == TUNER_XC2028) {
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ };
+ struct v4l2_priv_tun_config cfg = {
+ .tuner = cx->options.tuner,
+ .priv = &ctrl,
+ };
+ cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg);
+ }
+ }
+
+ /* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
+ are not. */
+ cx->tuner_std = cx->std;
+
+ cx18_init_on_first_open(cx);
+
+ CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name);
+
+ return 0;
+
+free_streams:
+ cx18_streams_cleanup(cx);
+free_irq:
+ free_irq(cx->dev->irq, (void *)cx);
+free_i2c:
+ exit_cx18_i2c(cx);
+free_map:
+ cx18_iounmap(cx);
+free_mem:
+ release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+free_workqueue:
+err:
+ if (retval == 0)
+ retval = -ENODEV;
+ CX18_ERR("Error %d on initialization\n", retval);
+
+ kfree(cx18_cards[cx18_cards_active]);
+ cx18_cards[cx18_cards_active] = NULL;
+ return retval;
+}
+
+int cx18_init_on_first_open(struct cx18 *cx)
+{
+ int video_input;
+ int fw_retry_count = 3;
+ struct v4l2_frequency vf;
+
+ if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
+ return -ENXIO;
+
+ if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags))
+ return 0;
+
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (cx18_firmware_init(cx) == 0)
+ break;
+ if (fw_retry_count > 1)
+ CX18_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(CX18_F_I_FAILED, &cx->i_flags);
+ return -ENXIO;
+ }
+ set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
+
+ /* Init the firmware twice to work around a silicon bug
+ * transport related. */
+
+ fw_retry_count = 3;
+ while (--fw_retry_count > 0) {
+ /* load firmware */
+ if (cx18_firmware_init(cx) == 0)
+ break;
+ if (fw_retry_count > 1)
+ CX18_WARN("Retry loading firmware\n");
+ }
+
+ if (fw_retry_count == 0) {
+ set_bit(CX18_F_I_FAILED, &cx->i_flags);
+ return -ENXIO;
+ }
+
+ vf.tuner = 0;
+ vf.type = V4L2_TUNER_ANALOG_TV;
+ vf.frequency = 6400; /* the tuner 'baseline' frequency */
+
+ /* Set initial frequency. For PAL/SECAM broadcasts no
+ 'default' channel exists AFAIK. */
+ if (cx->std == V4L2_STD_NTSC_M_JP)
+ vf.frequency = 1460; /* ch. 1 91250*16/1000 */
+ else if (cx->std & V4L2_STD_NTSC_M)
+ vf.frequency = 1076; /* ch. 4 67250*16/1000 */
+
+ video_input = cx->active_input;
+ cx->active_input++; /* Force update of input */
+ cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input);
+
+ /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
+ in one place. */
+ cx->std++; /* Force full standard initialization */
+ cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std);
+ cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf);
+ return 0;
+}
+
+static void cx18_remove(struct pci_dev *pci_dev)
+{
+ struct cx18 *cx = pci_get_drvdata(pci_dev);
+
+ CX18_DEBUG_INFO("Removing Card #%d\n", cx->num);
+
+ /* Stop all captures */
+ CX18_DEBUG_INFO("Stopping all streams\n");
+ if (atomic_read(&cx->capturing) > 0)
+ cx18_stop_all_captures(cx);
+
+ /* Interrupts */
+ sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+ sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ cx18_halt_firmware(cx);
+
+ cx18_streams_cleanup(cx);
+
+ exit_cx18_i2c(cx);
+
+ free_irq(cx->dev->irq, (void *)cx);
+
+ if (cx->dev)
+ cx18_iounmap(cx);
+
+ release_mem_region(cx->base_addr, CX18_MEM_SIZE);
+
+ pci_disable_device(cx->dev);
+
+ CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
+}
+
+/* define a pci_driver for card detection */
+static struct pci_driver cx18_pci_driver = {
+ .name = "cx18",
+ .id_table = cx18_pci_tbl,
+ .probe = cx18_probe,
+ .remove = cx18_remove,
+};
+
+static int module_start(void)
+{
+ printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION);
+
+ memset(cx18_cards, 0, sizeof(cx18_cards));
+
+ /* Validate parameters */
+ if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
+ printk(KERN_ERR "cx18: Exiting, ivtv_first_minor must be between 0 and %d\n",
+ CX18_MAX_CARDS - 1);
+ return -1;
+ }
+
+ if (cx18_debug < 0 || cx18_debug > 511) {
+ cx18_debug = 0;
+ printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n");
+ }
+
+ if (pci_register_driver(&cx18_pci_driver)) {
+ printk(KERN_ERR "cx18: Error detecting PCI card\n");
+ return -ENODEV;
+ }
+ printk(KERN_INFO "cx18: End initialization\n");
+ return 0;
+}
+
+static void module_cleanup(void)
+{
+ int i;
+
+ pci_unregister_driver(&cx18_pci_driver);
+
+ for (i = 0; i < cx18_cards_active; i++) {
+ if (cx18_cards[i] == NULL)
+ continue;
+ kfree(cx18_cards[i]);
+ }
+}
+
+module_init(module_start);
+module_exit(module_cleanup);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
new file mode 100644
index 0000000..2ee9391
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -0,0 +1,500 @@
+/*
+ * cx18 driver internal defines and structures
+ *
+ * Derived from ivtv-driver.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef CX18_DRIVER_H
+#define CX18_DRIVER_H
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/list.h>
+#include <linux/unistd.h>
+#include <linux/byteorder/swab.h>
+#include <linux/pagemap.h>
+#include <linux/workqueue.h>
+#include <linux/mutex.h>
+
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <media/v4l2-common.h>
+#include <media/tuner.h>
+#include "cx18-mailbox.h"
+#include "cx18-av-core.h"
+#include "cx23418.h"
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+#ifndef CONFIG_PCI
+# error "This driver requires kernel PCI support."
+#endif
+
+#define CX18_MEM_OFFSET 0x00000000
+#define CX18_MEM_SIZE 0x04000000
+#define CX18_REG_OFFSET 0x02000000
+
+/* Maximum cx18 driver instances. */
+#define CX18_MAX_CARDS 32
+
+/* Supported cards */
+#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */
+#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */
+#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */
+#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
+#define CX18_CARD_LAST 3
+
+#define CX18_ENC_STREAM_TYPE_MPG 0
+#define CX18_ENC_STREAM_TYPE_TS 1
+#define CX18_ENC_STREAM_TYPE_YUV 2
+#define CX18_ENC_STREAM_TYPE_VBI 3
+#define CX18_ENC_STREAM_TYPE_PCM 4
+#define CX18_ENC_STREAM_TYPE_IDX 5
+#define CX18_ENC_STREAM_TYPE_RAD 6
+#define CX18_MAX_STREAMS 7
+
+/* system vendor and device IDs */
+#define PCI_VENDOR_ID_CX 0x14f1
+#define PCI_DEVICE_ID_CX23418 0x5b7a
+
+/* subsystem vendor ID */
+#define CX18_PCI_ID_HAUPPAUGE 0x0070
+#define CX18_PCI_ID_COMPRO 0x185b
+#define CX18_PCI_ID_YUAN 0x12ab
+
+/* ======================================================================== */
+/* ========================== START USER SETTABLE DMA VARIABLES =========== */
+/* ======================================================================== */
+
+/* DMA Buffers, Default size in MB allocated */
+#define CX18_DEFAULT_ENC_TS_BUFFERS 1
+#define CX18_DEFAULT_ENC_MPG_BUFFERS 2
+#define CX18_DEFAULT_ENC_IDX_BUFFERS 1
+#define CX18_DEFAULT_ENC_YUV_BUFFERS 2
+#define CX18_DEFAULT_ENC_VBI_BUFFERS 1
+#define CX18_DEFAULT_ENC_PCM_BUFFERS 1
+
+/* i2c stuff */
+#define I2C_CLIENTS_MAX 16
+
+/* debugging */
+
+/* Flag to turn on high volume debugging */
+#define CX18_DBGFLG_WARN (1 << 0)
+#define CX18_DBGFLG_INFO (1 << 1)
+#define CX18_DBGFLG_API (1 << 2)
+#define CX18_DBGFLG_DMA (1 << 3)
+#define CX18_DBGFLG_IOCTL (1 << 4)
+#define CX18_DBGFLG_FILE (1 << 5)
+#define CX18_DBGFLG_I2C (1 << 6)
+#define CX18_DBGFLG_IRQ (1 << 7)
+/* Flag to turn on high volume debugging */
+#define CX18_DBGFLG_HIGHVOL (1 << 8)
+
+/* NOTE: extra space before comma in 'cx->num , ## args' is required for
+ gcc-2.95, otherwise it won't compile. */
+#define CX18_DEBUG(x, type, fmt, args...) \
+ do { \
+ if ((x) & cx18_debug) \
+ printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \
+ } while (0)
+#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args)
+#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args)
+#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args)
+#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args)
+#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
+#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
+
+#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \
+ do { \
+ if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
+ printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \
+ } while (0)
+#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args)
+#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args)
+#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args)
+#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args)
+#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
+#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args)
+#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
+#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
+
+/* Standard kernel messages */
+#define CX18_ERR(fmt, args...) printk(KERN_ERR "cx18-%d: " fmt, cx->num , ## args)
+#define CX18_WARN(fmt, args...) printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args)
+#define CX18_INFO(fmt, args...) printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args)
+
+/* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
+#define MPEG_FRAME_TYPE_IFRAME 1
+#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
+#define MPEG_FRAME_TYPE_ALL 7
+
+#define CX18_MAX_PGM_INDEX (400)
+
+extern int cx18_debug;
+
+
+struct cx18_options {
+ int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */
+ int cardtype; /* force card type on load */
+ int tuner; /* set tuner on load */
+ int radio; /* enable/disable radio */
+};
+
+/* per-buffer bit flags */
+#define CX18_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */
+
+/* per-stream, s_flags */
+#define CX18_F_S_CLAIMED 3 /* this stream is claimed */
+#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */
+#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */
+#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */
+#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */
+
+/* per-cx18, i_flags */
+#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */
+#define CX18_F_I_EOS 4 /* End of encoder stream reached */
+#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */
+#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */
+#define CX18_F_I_INITED 21 /* set after first open */
+#define CX18_F_I_FAILED 22 /* set if first open failed */
+
+/* These are the VBI types as they appear in the embedded VBI private packets. */
+#define CX18_SLICED_TYPE_TELETEXT_B (1)
+#define CX18_SLICED_TYPE_CAPTION_525 (4)
+#define CX18_SLICED_TYPE_WSS_625 (5)
+#define CX18_SLICED_TYPE_VPS (7)
+
+struct cx18_buffer {
+ struct list_head list;
+ dma_addr_t dma_handle;
+ u32 id;
+ unsigned long b_flags;
+ char *buf;
+
+ u32 bytesused;
+ u32 readpos;
+};
+
+struct cx18_queue {
+ struct list_head list;
+ u32 buffers;
+ u32 length;
+ u32 bytesused;
+};
+
+struct cx18_dvb {
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ struct dmxdev dmxdev;
+ struct dvb_adapter dvb_adapter;
+ struct dvb_demux demux;
+ struct dvb_frontend *fe;
+ struct dvb_net dvbnet;
+ int enabled;
+ int feeding;
+
+ struct mutex feedlock;
+
+};
+
+struct cx18; /* forward reference */
+struct cx18_scb; /* forward reference */
+
+struct cx18_stream {
+ /* These first four fields are always set, even if the stream
+ is not actually created. */
+ struct video_device *v4l2dev; /* NULL when stream not created */
+ struct cx18 *cx; /* for ease of use */
+ const char *name; /* name of the stream */
+ int type; /* stream type */
+ u32 handle; /* task handle */
+ unsigned mdl_offset;
+
+ u32 id;
+ spinlock_t qlock; /* locks access to the queues */
+ unsigned long s_flags; /* status flags, see above */
+ int dma; /* can be PCI_DMA_TODEVICE,
+ PCI_DMA_FROMDEVICE or
+ PCI_DMA_NONE */
+ u64 dma_pts;
+ wait_queue_head_t waitq;
+
+ /* Buffer Stats */
+ u32 buffers;
+ u32 buf_size;
+ u32 buffers_stolen;
+
+ /* Buffer Queues */
+ struct cx18_queue q_free; /* free buffers */
+ struct cx18_queue q_full; /* full buffers */
+ struct cx18_queue q_io; /* waiting for I/O */
+
+ /* DVB / Digital Transport */
+ struct cx18_dvb dvb;
+};
+
+struct cx18_open_id {
+ u32 open_id;
+ int type;
+ enum v4l2_priority prio;
+ struct cx18 *cx;
+};
+
+/* forward declaration of struct defined in cx18-cards.h */
+struct cx18_card;
+
+
+#define CX18_VBI_FRAMES 32
+
+/* VBI data */
+struct vbi_info {
+ u32 enc_size;
+ u32 frame;
+ u8 cc_data_odd[256];
+ u8 cc_data_even[256];
+ int cc_pos;
+ u8 cc_no_update;
+ u8 vps[5];
+ u8 vps_found;
+ int wss;
+ u8 wss_found;
+ u8 wss_no_update;
+ u32 raw_decoder_line_size;
+ u8 raw_decoder_sav_odd_field;
+ u8 raw_decoder_sav_even_field;
+ u32 sliced_decoder_line_size;
+ u8 sliced_decoder_sav_odd_field;
+ u8 sliced_decoder_sav_even_field;
+ struct v4l2_format in;
+ /* convenience pointer to sliced struct in vbi_in union */
+ struct v4l2_sliced_vbi_format *sliced_in;
+ u32 service_set_in;
+ int insert_mpeg;
+
+ /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
+ One for /dev/vbi0 and one for /dev/vbi8 */
+ struct v4l2_sliced_vbi_data sliced_data[36];
+
+ /* Buffer for VBI data inserted into MPEG stream.
+ The first byte is a dummy byte that's never used.
+ The next 16 bytes contain the MPEG header for the VBI data,
+ the remainder is the actual VBI data.
+ The max size accepted by the MPEG VBI reinsertion turns out
+ to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
+ where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
+ a single line header byte and 2 * 18 is the number of VBI lines per frame.
+
+ However, it seems that the data must be 1K aligned, so we have to
+ pad the data until the 1 or 2 K boundary.
+
+ This pointer array will allocate 2049 bytes to store each VBI frame. */
+ u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
+ u32 sliced_mpeg_size[CX18_VBI_FRAMES];
+ struct cx18_buffer sliced_mpeg_buf;
+ u32 inserted_frame;
+
+ u32 start[2], count;
+ u32 raw_size;
+ u32 sliced_size;
+};
+
+/* Per cx23418, per I2C bus private algo callback data */
+struct cx18_i2c_algo_callback_data {
+ struct cx18 *cx;
+ int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */
+};
+
+/* Struct to hold info about cx18 cards */
+struct cx18 {
+ int num; /* board number, -1 during init! */
+ char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */
+ struct pci_dev *dev; /* PCI device */
+ const struct cx18_card *card; /* card information */
+ const char *card_name; /* full name of the card */
+ const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
+ u8 is_50hz;
+ u8 is_60hz;
+ u8 is_out_50hz;
+ u8 is_out_60hz;
+ u8 nof_inputs; /* number of video inputs */
+ u8 nof_audio_inputs; /* number of audio inputs */
+ u16 buffer_id; /* buffer ID counter */
+ u32 v4l2_cap; /* V4L2 capabilities of card */
+ u32 hw_flags; /* Hardware description of the board */
+ unsigned mdl_offset;
+ struct cx18_scb *scb; /* pointer to SCB */
+
+ struct cx18_av_state av_state;
+
+ /* codec settings */
+ struct cx2341x_mpeg_params params;
+ u32 filter_mode;
+ u32 temporal_strength;
+ u32 spatial_strength;
+
+ /* dualwatch */
+ unsigned long dualwatch_jiffies;
+ u16 dualwatch_stereo_mode;
+
+ /* Digitizer type */
+ int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
+
+ struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
+ struct cx18_options options; /* User options */
+ int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
+ struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
+ unsigned long i_flags; /* global cx18 flags */
+ atomic_t capturing; /* count number of active capture streams */
+ spinlock_t lock; /* lock access to this struct */
+ int search_pack_header;
+
+ spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
+
+ int open_id; /* incremented each time an open occurs, used as
+ unique ID. Starts at 1, so 0 can be used as
+ uninitialized value in the stream->id. */
+
+ u32 base_addr;
+ struct v4l2_prio_state prio;
+
+ u8 card_rev;
+ void __iomem *enc_mem, *reg_mem;
+
+ struct vbi_info vbi;
+
+ u32 pgm_info_offset;
+ u32 pgm_info_num;
+ u32 pgm_info_write_idx;
+ u32 pgm_info_read_idx;
+ struct v4l2_enc_idx_entry pgm_info[CX18_MAX_PGM_INDEX];
+
+ u64 mpg_data_received;
+ u64 vbi_data_inserted;
+
+ wait_queue_head_t mb_apu_waitq;
+ wait_queue_head_t mb_cpu_waitq;
+ wait_queue_head_t mb_epu_waitq;
+ wait_queue_head_t mb_hpu_waitq;
+ wait_queue_head_t cap_w;
+ /* when the current DMA is finished this queue is woken up */
+ wait_queue_head_t dma_waitq;
+
+ /* i2c */
+ struct i2c_adapter i2c_adap[2];
+ struct i2c_algo_bit_data i2c_algo[2];
+ struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2];
+ struct i2c_client i2c_client[2];
+ struct mutex i2c_bus_lock[2];
+ struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
+
+ /* v4l2 and User settings */
+
+ /* codec settings */
+ u32 audio_input;
+ u32 active_input;
+ u32 active_output;
+ v4l2_std_id std;
+ v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
+};
+
+/* Globals */
+extern struct cx18 *cx18_cards[];
+extern int cx18_cards_active;
+extern int cx18_first_minor;
+extern spinlock_t cx18_cards_lock;
+
+/*==============Prototypes==================*/
+
+/* Return non-zero if a signal is pending */
+int cx18_msleep_timeout(unsigned int msecs, int intr);
+
+/* Wait on queue, returns -EINTR if interrupted */
+int cx18_waitq(wait_queue_head_t *waitq);
+
+/* Read Hauppauge eeprom */
+struct tveeprom; /* forward reference */
+void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
+
+/* First-open initialization: load firmware, etc. */
+int cx18_init_on_first_open(struct cx18 *cx);
+
+/* This is a PCI post thing, where if the pci register is not read, then
+ the write doesn't always take effect right away. By reading back the
+ register any pending PCI writes will be performed (in order), and so
+ you can be sure that the writes are guaranteed to be done.
+
+ Rarely needed, only in some timing sensitive cases.
+ Apparently if this is not done some motherboards seem
+ to kill the firmware and get into the broken state until computer is
+ rebooted. */
+#define write_sync(val, reg) \
+ do { writel(val, reg); readl(reg); } while (0)
+
+#define read_reg(reg) readl(cx->reg_mem + (reg))
+#define write_reg(val, reg) writel(val, cx->reg_mem + (reg))
+#define write_reg_sync(val, reg) \
+ do { write_reg(val, reg); read_reg(reg); } while (0)
+
+#define read_enc(addr) readl(cx->enc_mem + (u32)(addr))
+#define write_enc(val, addr) writel(val, cx->enc_mem + (u32)(addr))
+#define write_enc_sync(val, addr) \
+ do { write_enc(val, addr); read_enc(addr); } while (0)
+
+#define sw1_irq_enable(val) do { \
+ write_reg(val, SW1_INT_STATUS); \
+ write_reg(read_reg(SW1_INT_ENABLE_PCI) | (val), SW1_INT_ENABLE_PCI); \
+} while (0)
+
+#define sw1_irq_disable(val) \
+ write_reg(read_reg(SW1_INT_ENABLE_PCI) & ~(val), SW1_INT_ENABLE_PCI);
+
+#define sw2_irq_enable(val) do { \
+ write_reg(val, SW2_INT_STATUS); \
+ write_reg(read_reg(SW2_INT_ENABLE_PCI) | (val), SW2_INT_ENABLE_PCI); \
+} while (0)
+
+#define sw2_irq_disable(val) \
+ write_reg(read_reg(SW2_INT_ENABLE_PCI) & ~(val), SW2_INT_ENABLE_PCI);
+
+#define setup_page(addr) do { \
+ u32 val = read_reg(0xD000F8) & ~0x1f00; \
+ write_reg(val | (((addr) >> 17) & 0x1f00), 0xD000F8); \
+} while (0)
+
+#endif /* CX18_DRIVER_H */
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
new file mode 100644
index 0000000..65efe69
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -0,0 +1,288 @@
+/*
+ * cx18 functions for DVB support
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.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 "cx18-version.h"
+#include "cx18-dvb.h"
+#include "cx18-streams.h"
+#include "cx18-cards.h"
+#include "s5h1409.h"
+
+/* Wait until the MXL500X driver is merged */
+#ifdef HAVE_MXL500X
+#include "mxl500x.h"
+#endif
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
+
+#ifdef HAVE_MXL500X
+static struct mxl500x_config hauppauge_hvr1600_tuner = {
+ .delsys = MXL500x_MODE_ATSC,
+ .octf = MXL500x_OCTF_CH,
+ .xtal_freq = 16000000,
+ .iflo_freq = 5380000,
+ .ref_freq = 322800000,
+ .rssi_ena = MXL_RSSI_ENABLE,
+ .addr = 0xC6 >> 1,
+};
+
+static struct s5h1409_config hauppauge_hvr1600_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_ON,
+ .qam_if = 44000,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
+
+};
+#endif
+
+static int dvb_register(struct cx18_stream *stream);
+
+/* Kernel DVB framework calls this when the feed needs to start.
+ * The CX18 framework should enable the transport DMA handling
+ * and queue processing.
+ */
+static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
+ struct cx18 *cx = stream->cx;
+ int ret = -EINVAL;
+ u32 v;
+
+ CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
+ feed->pid, feed->index);
+ switch (cx->card->type) {
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ v = read_reg(CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+ v |= 0x00400000; /* Serial Mode */
+ v |= 0x00002000; /* Data Length - Byte */
+ v |= 0x00010000; /* Error - Polarity */
+ v |= 0x00020000; /* Error - Passthru */
+ v |= 0x000c0000; /* Error - Ignore */
+ write_reg(v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
+ break;
+
+ default:
+ /* Assumption - Parallel transport - Signalling
+ * undefined or default.
+ */
+ break;
+ }
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ if (stream) {
+ mutex_lock(&stream->dvb.feedlock);
+ if (stream->dvb.feeding++ == 0) {
+ CX18_DEBUG_INFO("Starting Transport DMA\n");
+ ret = cx18_start_v4l2_encode_stream(stream);
+ } else
+ ret = 0;
+ mutex_unlock(&stream->dvb.feedlock);
+ }
+
+ return ret;
+}
+
+/* Kernel DVB framework calls this when the feed needs to stop. */
+static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct cx18_stream *stream = (struct cx18_stream *)demux->priv;
+ struct cx18 *cx = stream->cx;
+ int ret = -EINVAL;
+
+ CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
+ feed->pid, feed->index);
+
+ if (stream) {
+ mutex_lock(&stream->dvb.feedlock);
+ if (--stream->dvb.feeding == 0) {
+ CX18_DEBUG_INFO("Stopping Transport DMA\n");
+ ret = cx18_stop_v4l2_encode_stream(stream, 0);
+ } else
+ ret = 0;
+ mutex_unlock(&stream->dvb.feedlock);
+ }
+
+ return ret;
+}
+
+int cx18_dvb_register(struct cx18_stream *stream)
+{
+ struct cx18 *cx = stream->cx;
+ struct cx18_dvb *dvb = &stream->dvb;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+ int ret;
+
+ if (!dvb)
+ return -EINVAL;
+
+ ret = dvb_register_adapter(&dvb->dvb_adapter,
+ CX18_DRIVER_NAME,
+ THIS_MODULE, &cx->dev->dev, adapter_nr);
+ if (ret < 0)
+ goto err_out;
+
+ dvb_adapter = &dvb->dvb_adapter;
+
+ dvbdemux = &dvb->demux;
+
+ dvbdemux->priv = (void *)stream;
+
+ dvbdemux->filternum = 256;
+ dvbdemux->feednum = 256;
+ dvbdemux->start_feed = cx18_dvb_start_feed;
+ dvbdemux->stop_feed = cx18_dvb_stop_feed;
+ dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+ ret = dvb_dmx_init(dvbdemux);
+ if (ret < 0)
+ goto err_dvb_unregister_adapter;
+
+ dmx = &dvbdemux->dmx;
+
+ dvb->hw_frontend.source = DMX_FRONTEND_0;
+ dvb->mem_frontend.source = DMX_MEMORY_FE;
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = dmx;
+
+ ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter);
+ if (ret < 0)
+ goto err_dvb_dmx_release;
+
+ ret = dmx->add_frontend(dmx, &dvb->hw_frontend);
+ if (ret < 0)
+ goto err_dvb_dmxdev_release;
+
+ ret = dmx->add_frontend(dmx, &dvb->mem_frontend);
+ if (ret < 0)
+ goto err_remove_hw_frontend;
+
+ ret = dmx->connect_frontend(dmx, &dvb->hw_frontend);
+ if (ret < 0)
+ goto err_remove_mem_frontend;
+
+ ret = dvb_register(stream);
+ if (ret < 0)
+ goto err_disconnect_frontend;
+
+ dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
+
+ CX18_INFO("DVB Frontend registered\n");
+ mutex_init(&dvb->feedlock);
+ dvb->enabled = 1;
+ return ret;
+
+err_disconnect_frontend:
+ dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+ dmx->remove_frontend(dmx, &dvb->mem_frontend);
+err_remove_hw_frontend:
+ dmx->remove_frontend(dmx, &dvb->hw_frontend);
+err_dvb_dmxdev_release:
+ dvb_dmxdev_release(&dvb->dmxdev);
+err_dvb_dmx_release:
+ dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+ dvb_unregister_adapter(dvb_adapter);
+err_out:
+ return ret;
+}
+
+void cx18_dvb_unregister(struct cx18_stream *stream)
+{
+ struct cx18 *cx = stream->cx;
+ struct cx18_dvb *dvb = &stream->dvb;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+
+ CX18_INFO("unregister DVB\n");
+
+ dvb_adapter = &dvb->dvb_adapter;
+ dvbdemux = &dvb->demux;
+ dmx = &dvbdemux->dmx;
+
+ dmx->close(dmx);
+ dvb_net_release(&dvb->dvbnet);
+ dmx->remove_frontend(dmx, &dvb->mem_frontend);
+ dmx->remove_frontend(dmx, &dvb->hw_frontend);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(dvbdemux);
+ dvb_unregister_frontend(dvb->fe);
+ dvb_frontend_detach(dvb->fe);
+ dvb_unregister_adapter(dvb_adapter);
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. No other function in this file needs
+ * to change.
+ */
+static int dvb_register(struct cx18_stream *stream)
+{
+ struct cx18_dvb *dvb = &stream->dvb;
+ struct cx18 *cx = stream->cx;
+ int ret = 0;
+
+ switch (cx->card->type) {
+/* Wait until the MXL500X driver is merged */
+#ifdef HAVE_MXL500X
+ case CX18_CARD_HVR_1600_ESMT:
+ case CX18_CARD_HVR_1600_SAMSUNG:
+ dvb->fe = dvb_attach(s5h1409_attach,
+ &hauppauge_hvr1600_config,
+ &cx->i2c_adap[0]);
+ if (dvb->fe != NULL) {
+ dvb_attach(mxl500x_attach, dvb->fe,
+ &hauppauge_hvr1600_tuner,
+ &cx->i2c_adap[0]);
+ ret = 0;
+ }
+ break;
+#endif
+ default:
+ /* No Digital Tv Support */
+ break;
+ }
+
+ if (dvb->fe == NULL) {
+ CX18_ERR("frontend initialization failed\n");
+ return -1;
+ }
+
+ ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
+ if (ret < 0) {
+ if (dvb->fe->ops.release)
+ dvb->fe->ops.release(dvb->fe);
+ return ret;
+ }
+
+ return ret;
+}
diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h
new file mode 100644
index 0000000..d6a6ccd
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-dvb.h
@@ -0,0 +1,25 @@
+/*
+ * cx18 functions for DVB support
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.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 "cx18-driver.h"
+
+int cx18_dvb_register(struct cx18_stream *stream);
+void cx18_dvb_unregister(struct cx18_stream *stream);
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
new file mode 100644
index 0000000..6930306
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -0,0 +1,711 @@
+/*
+ * cx18 file operation functions
+ *
+ * Derived from ivtv-fileops.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-fileops.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-vbi.h"
+#include "cx18-audio.h"
+#include "cx18-mailbox.h"
+#include "cx18-scb.h"
+#include "cx18-streams.h"
+#include "cx18-controls.h"
+#include "cx18-ioctl.h"
+#include "cx18-cards.h"
+
+/* This function tries to claim the stream for a specific file descriptor.
+ If no one else is using this stream then the stream is claimed and
+ associated VBI streams are also automatically claimed.
+ Possible error returns: -EBUSY if someone else has claimed
+ the stream or 0 on success. */
+int cx18_claim_stream(struct cx18_open_id *id, int type)
+{
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[type];
+ struct cx18_stream *s_vbi;
+ int vbi_type;
+
+ if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
+ /* someone already claimed this stream */
+ if (s->id == id->open_id) {
+ /* yes, this file descriptor did. So that's OK. */
+ return 0;
+ }
+ if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) {
+ /* VBI is handled already internally, now also assign
+ the file descriptor to this stream for external
+ reading of the stream. */
+ s->id = id->open_id;
+ CX18_DEBUG_INFO("Start Read VBI\n");
+ return 0;
+ }
+ /* someone else is using this stream already */
+ CX18_DEBUG_INFO("Stream %d is busy\n", type);
+ return -EBUSY;
+ }
+ s->id = id->open_id;
+
+ /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI,
+ CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
+ (provided VBI insertion is on and sliced VBI is selected), for all
+ other streams we're done */
+ if (type == CX18_ENC_STREAM_TYPE_MPG &&
+ cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) {
+ vbi_type = CX18_ENC_STREAM_TYPE_VBI;
+ } else {
+ return 0;
+ }
+ s_vbi = &cx->streams[vbi_type];
+
+ set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
+
+ /* mark that it is used internally */
+ set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags);
+ return 0;
+}
+
+/* This function releases a previously claimed stream. It will take into
+ account associated VBI streams. */
+void cx18_release_stream(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_stream *s_vbi;
+
+ s->id = -1;
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
+ test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) {
+ /* this stream is still in use internally */
+ return;
+ }
+ if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
+ CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name);
+ return;
+ }
+
+ cx18_flush_queues(s);
+
+ /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI,
+ for all other streams we're done */
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ else
+ return;
+
+ /* clear internal use flag */
+ if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
+ /* was already cleared */
+ return;
+ }
+ if (s_vbi->id != -1) {
+ /* VBI stream still claimed by a file descriptor */
+ return;
+ }
+ clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
+ cx18_flush_queues(s_vbi);
+}
+
+static void cx18_dualwatch(struct cx18 *cx)
+{
+ struct v4l2_tuner vt;
+ u16 new_bitmap;
+ u16 new_stereo_mode;
+ const u16 stereo_mask = 0x0300;
+ const u16 dual = 0x0200;
+
+ new_stereo_mode = cx->params.audio_properties & stereo_mask;
+ memset(&vt, 0, sizeof(vt));
+ cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt);
+ if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
+ (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
+ new_stereo_mode = dual;
+
+ if (new_stereo_mode == cx->dualwatch_stereo_mode)
+ return;
+
+ new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask);
+
+ CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
+ cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
+
+ if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
+ cx18_find_handle(cx), new_bitmap) == 0) {
+ cx->dualwatch_stereo_mode = new_stereo_mode;
+ return;
+ }
+ CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+}
+
+
+static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ struct cx18_buffer *buf;
+ DEFINE_WAIT(wait);
+
+ *err = 0;
+ while (1) {
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
+
+ if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
+ cx->dualwatch_jiffies = jiffies;
+ cx18_dualwatch(cx);
+ }
+ if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+ !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+ while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
+ /* byteswap and process VBI data */
+/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */
+ cx18_enqueue(s_vbi, buf, &s_vbi->q_free);
+ }
+ }
+ buf = &cx->vbi.sliced_mpeg_buf;
+ if (buf->readpos != buf->bytesused)
+ return buf;
+ }
+
+ /* do we have leftover data? */
+ buf = cx18_dequeue(s, &s->q_io);
+ if (buf)
+ return buf;
+
+ /* do we have new data? */
+ buf = cx18_dequeue(s, &s->q_full);
+ if (buf) {
+ if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP,
+ &buf->b_flags))
+ return buf;
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ /* byteswap MPG data */
+ cx18_buf_swap(buf);
+ else {
+ /* byteswap and process VBI data */
+ cx18_process_vbi_data(cx, buf,
+ s->dma_pts, s->type);
+ }
+ return buf;
+ }
+
+ /* return if end of stream */
+ if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ CX18_DEBUG_INFO("EOS %s\n", s->name);
+ return NULL;
+ }
+
+ /* return if file was opened with O_NONBLOCK */
+ if (non_block) {
+ *err = -EAGAIN;
+ return NULL;
+ }
+
+ /* wait for more data to arrive */
+ prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
+ /* New buffers might have become available before we were added
+ to the waitqueue */
+ if (!s->q_full.buffers)
+ schedule();
+ finish_wait(&s->waitq, &wait);
+ if (signal_pending(current)) {
+ /* return if a signal was received */
+ CX18_DEBUG_INFO("User stopped %s\n", s->name);
+ *err = -EINTR;
+ return NULL;
+ }
+ }
+}
+
+static void cx18_setup_sliced_vbi_buf(struct cx18 *cx)
+{
+ int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
+
+ cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx];
+ cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx];
+ cx->vbi.sliced_mpeg_buf.readpos = 0;
+}
+
+static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
+ struct cx18_buffer *buf, char __user *ubuf, size_t ucount)
+{
+ struct cx18 *cx = s->cx;
+ size_t len = buf->bytesused - buf->readpos;
+
+ if (len > ucount)
+ len = ucount;
+ if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) {
+ const char *start = buf->buf + buf->readpos;
+ const char *p = start + 1;
+ const u8 *q;
+ u8 ch = cx->search_pack_header ? 0xba : 0xe0;
+ int stuffing, i;
+
+ while (start + len > p) {
+ q = memchr(p, 0, start + len - p);
+ if (q == NULL)
+ break;
+ p = q + 1;
+ if ((char *)q + 15 >= buf->buf + buf->bytesused ||
+ q[1] != 0 || q[2] != 1 || q[3] != ch)
+ continue;
+ if (!cx->search_pack_header) {
+ if ((q[6] & 0xc0) != 0x80)
+ continue;
+ if (((q[7] & 0xc0) == 0x80 &&
+ (q[9] & 0xf0) == 0x20) ||
+ ((q[7] & 0xc0) == 0xc0 &&
+ (q[9] & 0xf0) == 0x30)) {
+ ch = 0xba;
+ cx->search_pack_header = 1;
+ p = q + 9;
+ }
+ continue;
+ }
+ stuffing = q[13] & 7;
+ /* all stuffing bytes must be 0xff */
+ for (i = 0; i < stuffing; i++)
+ if (q[14 + i] != 0xff)
+ break;
+ if (i == stuffing &&
+ (q[4] & 0xc4) == 0x44 &&
+ (q[12] & 3) == 3 &&
+ q[14 + stuffing] == 0 &&
+ q[15 + stuffing] == 0 &&
+ q[16 + stuffing] == 1) {
+ cx->search_pack_header = 0;
+ len = (char *)q - start;
+ cx18_setup_sliced_vbi_buf(cx);
+ break;
+ }
+ }
+ }
+ if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {
+ CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n",
+ len, s->name);
+ return -EFAULT;
+ }
+ buf->readpos += len;
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ buf != &cx->vbi.sliced_mpeg_buf)
+ cx->mpg_data_received += len;
+ return len;
+}
+
+static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
+ size_t tot_count, int non_block)
+{
+ struct cx18 *cx = s->cx;
+ size_t tot_written = 0;
+ int single_frame = 0;
+
+ if (atomic_read(&cx->capturing) == 0 && s->id == -1) {
+ /* shouldn't happen */
+ CX18_DEBUG_WARN("Stream %s not initialized before read\n",
+ s->name);
+ return -EIO;
+ }
+
+ /* Each VBI buffer is one frame, the v4l2 API says that for VBI the
+ frames should arrive one-by-one, so make sure we never output more
+ than one VBI frame at a time */
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
+ cx->vbi.sliced_in->service_set)
+ single_frame = 1;
+
+ for (;;) {
+ struct cx18_buffer *buf;
+ int rc;
+
+ buf = cx18_get_buffer(s, non_block, &rc);
+ /* if there is no data available... */
+ if (buf == NULL) {
+ /* if we got data, then return that regardless */
+ if (tot_written)
+ break;
+ /* EOS condition */
+ if (rc == 0) {
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+ clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ cx18_release_stream(s);
+ }
+ /* set errno */
+ return rc;
+ }
+
+ rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written,
+ tot_count - tot_written);
+
+ if (buf != &cx->vbi.sliced_mpeg_buf) {
+ if (buf->readpos == buf->bytesused) {
+ cx18_buf_sync_for_device(s, buf);
+ cx18_enqueue(s, buf, &s->q_free);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
+ s->handle,
+ (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
+ } else
+ cx18_enqueue(s, buf, &s->q_io);
+ } else if (buf->readpos == buf->bytesused) {
+ int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
+
+ cx->vbi.sliced_mpeg_size[idx] = 0;
+ cx->vbi.inserted_frame++;
+ cx->vbi_data_inserted += buf->bytesused;
+ }
+ if (rc < 0)
+ return rc;
+ tot_written += rc;
+
+ if (tot_written == tot_count || single_frame)
+ break;
+ }
+ return tot_written;
+}
+
+static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf,
+ size_t count, loff_t *pos, int non_block)
+{
+ ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0;
+ struct cx18 *cx = s->cx;
+
+ CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
+ if (rc > 0)
+ pos += rc;
+ return rc;
+}
+
+int cx18_start_capture(struct cx18_open_id *id)
+{
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ struct cx18_stream *s_vbi;
+
+ if (s->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* you cannot read from these stream types. */
+ return -EPERM;
+ }
+
+ /* Try to claim this stream. */
+ if (cx18_claim_stream(id, s->type))
+ return -EBUSY;
+
+ /* If capture is already in progress, then we also have to
+ do nothing extra. */
+ if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) ||
+ test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ set_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ return 0;
+ }
+
+ /* Start VBI capture if required */
+ s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
+ !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
+ /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed
+ automatically when the MPG stream is claimed.
+ We only need to start the VBI capturing. */
+ if (cx18_start_v4l2_encode_stream(s_vbi)) {
+ CX18_DEBUG_WARN("VBI capture start failed\n");
+
+ /* Failure, clean up and return an error */
+ clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+ /* also releases the associated VBI stream */
+ cx18_release_stream(s);
+ return -EIO;
+ }
+ CX18_DEBUG_INFO("VBI insertion started\n");
+ }
+
+ /* Tell the card to start capturing */
+ if (!cx18_start_v4l2_encode_stream(s)) {
+ /* We're done */
+ set_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ /* Resume a possibly paused encoder */
+ if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle);
+ return 0;
+ }
+
+ /* failure, clean up */
+ CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
+
+ /* Note: the CX18_ENC_STREAM_TYPE_VBI is released
+ automatically when the MPG stream is released.
+ We only need to stop the VBI capturing. */
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
+ test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
+ cx18_stop_v4l2_encode_stream(s_vbi, 0);
+ clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
+ }
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+ cx18_release_stream(s);
+ return -EIO;
+}
+
+ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
+{
+ struct cx18_open_id *id = filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ int rc;
+
+ CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
+
+ mutex_lock(&cx->serialize_lock);
+ rc = cx18_start_capture(id);
+ mutex_unlock(&cx->serialize_lock);
+ if (rc)
+ return rc;
+ return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
+}
+
+unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
+{
+ struct cx18_open_id *id = filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+ int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+ /* Start a capture if there is none */
+ if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ int rc;
+
+ mutex_lock(&cx->serialize_lock);
+ rc = cx18_start_capture(id);
+ mutex_unlock(&cx->serialize_lock);
+ if (rc) {
+ CX18_DEBUG_INFO("Could not start capture for %s (%d)\n",
+ s->name, rc);
+ return POLLERR;
+ }
+ CX18_DEBUG_FILE("Encoder poll started capture\n");
+ }
+
+ /* add stream's waitq to the poll list */
+ CX18_DEBUG_HI_FILE("Encoder poll\n");
+ poll_wait(filp, &s->waitq, wait);
+
+ if (s->q_full.length || s->q_io.length)
+ return POLLIN | POLLRDNORM;
+ if (eof)
+ return POLLHUP;
+ return 0;
+}
+
+void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
+{
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ CX18_DEBUG_IOCTL("close() of %s\n", s->name);
+
+ /* 'Unclaim' this stream */
+
+ /* Stop capturing */
+ if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
+ struct cx18_stream *s_vbi =
+ &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
+
+ CX18_DEBUG_INFO("close stopping capture\n");
+ /* Special case: a running VBI capture for VBI insertion
+ in the mpeg stream. Need to stop that too. */
+ if (id->type == CX18_ENC_STREAM_TYPE_MPG &&
+ test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
+ !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
+ CX18_DEBUG_INFO("close stopping embedded VBI capture\n");
+ cx18_stop_v4l2_encode_stream(s_vbi, 0);
+ }
+ if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
+ test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))
+ /* Also used internally, don't stop capturing */
+ s->id = -1;
+ else
+ cx18_stop_v4l2_encode_stream(s, gop_end);
+ }
+ if (!gop_end) {
+ clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+ cx18_release_stream(s);
+ }
+}
+
+int cx18_v4l2_close(struct inode *inode, struct file *filp)
+{
+ struct cx18_open_id *id = filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct cx18_stream *s = &cx->streams[id->type];
+
+ CX18_DEBUG_IOCTL("close() of %s\n", s->name);
+
+ v4l2_prio_close(&cx->prio, &id->prio);
+
+ /* Easy case first: this stream was never claimed by us */
+ if (s->id != id->open_id) {
+ kfree(id);
+ return 0;
+ }
+
+ /* 'Unclaim' this stream */
+
+ /* Stop radio */
+ mutex_lock(&cx->serialize_lock);
+ if (id->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* Closing radio device, return to TV mode */
+ cx18_mute(cx);
+ /* Mark that the radio is no longer in use */
+ clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
+ /* Switch tuner to TV */
+ cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+ /* Select correct audio input (i.e. TV tuner or Line in) */
+ cx18_audio_set_io(cx);
+ if (atomic_read(&cx->capturing) > 0) {
+ /* Undo video mute */
+ cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
+ cx->params.video_mute |
+ (cx->params.video_mute_yuv << 8));
+ }
+ /* Done! Unmute and continue. */
+ cx18_unmute(cx);
+ cx18_release_stream(s);
+ } else {
+ cx18_stop_capture(id, 0);
+ }
+ kfree(id);
+ mutex_unlock(&cx->serialize_lock);
+ return 0;
+}
+
+static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
+{
+ struct cx18 *cx = s->cx;
+ struct cx18_open_id *item;
+
+ CX18_DEBUG_FILE("open %s\n", s->name);
+
+ /* Allocate memory */
+ item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL);
+ if (NULL == item) {
+ CX18_DEBUG_WARN("nomem on v4l2 open\n");
+ return -ENOMEM;
+ }
+ item->cx = cx;
+ item->type = s->type;
+ v4l2_prio_open(&cx->prio, &item->prio);
+
+ item->open_id = cx->open_id++;
+ filp->private_data = item;
+
+ if (item->type == CX18_ENC_STREAM_TYPE_RAD) {
+ /* Try to claim this stream */
+ if (cx18_claim_stream(item, item->type)) {
+ /* No, it's already in use */
+ kfree(item);
+ return -EBUSY;
+ }
+
+ if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ if (atomic_read(&cx->capturing) > 0) {
+ /* switching to radio while capture is
+ in progress is not polite */
+ cx18_release_stream(s);
+ kfree(item);
+ return -EBUSY;
+ }
+ }
+
+ /* Mark that the radio is being used. */
+ set_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
+ /* We have the radio */
+ cx18_mute(cx);
+ /* Switch tuner to radio */
+ cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL);
+ /* Select the correct audio input (i.e. radio tuner) */
+ cx18_audio_set_io(cx);
+ /* Done! Unmute and continue. */
+ cx18_unmute(cx);
+ }
+ return 0;
+}
+
+int cx18_v4l2_open(struct inode *inode, struct file *filp)
+{
+ int res, x, y = 0;
+ struct cx18 *cx = NULL;
+ struct cx18_stream *s = NULL;
+ int minor = iminor(inode);
+
+ /* Find which card this open was on */
+ spin_lock(&cx18_cards_lock);
+ for (x = 0; cx == NULL && x < cx18_cards_active; x++) {
+ /* find out which stream this open was on */
+ for (y = 0; y < CX18_MAX_STREAMS; y++) {
+ s = &cx18_cards[x]->streams[y];
+ if (s->v4l2dev && s->v4l2dev->minor == minor) {
+ cx = cx18_cards[x];
+ break;
+ }
+ }
+ }
+ spin_unlock(&cx18_cards_lock);
+
+ if (cx == NULL) {
+ /* Couldn't find a device registered
+ on that minor, shouldn't happen! */
+ printk(KERN_WARNING "No cx18 device found on minor %d\n",
+ minor);
+ return -ENXIO;
+ }
+
+ mutex_lock(&cx->serialize_lock);
+ if (cx18_init_on_first_open(cx)) {
+ CX18_ERR("Failed to initialize on minor %d\n", minor);
+ mutex_unlock(&cx->serialize_lock);
+ return -ENXIO;
+ }
+ res = cx18_serialized_open(s, filp);
+ mutex_unlock(&cx->serialize_lock);
+ return res;
+}
+
+void cx18_mute(struct cx18 *cx)
+{
+ if (atomic_read(&cx->capturing))
+ cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+ cx18_find_handle(cx), 1);
+ CX18_DEBUG_INFO("Mute\n");
+}
+
+void cx18_unmute(struct cx18 *cx)
+{
+ if (atomic_read(&cx->capturing)) {
+ cx18_msleep_timeout(100, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
+ cx18_find_handle(cx), 12);
+ cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+ cx18_find_handle(cx), 0);
+ }
+ CX18_DEBUG_INFO("Unmute\n");
+}
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h
new file mode 100644
index 0000000..16cdafb
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-fileops.h
@@ -0,0 +1,45 @@
+/*
+ * cx18 file operation functions
+ *
+ * Derived from ivtv-fileops.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+/* Testing/Debugging */
+int cx18_v4l2_open(struct inode *inode, struct file *filp);
+ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos);
+ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count,
+ loff_t *pos);
+int cx18_v4l2_close(struct inode *inode, struct file *filp);
+unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait);
+int cx18_start_capture(struct cx18_open_id *id);
+void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
+void cx18_mute(struct cx18 *cx);
+void cx18_unmute(struct cx18 *cx);
+
+/* Utilities */
+
+/* Try to claim a stream for the filehandle. Return 0 on success,
+ -EBUSY if stream already claimed. Once a stream is claimed, it
+ remains claimed until the associated filehandle is closed. */
+int cx18_claim_stream(struct cx18_open_id *id, int type);
+
+/* Release a previously claimed stream. */
+void cx18_release_stream(struct cx18_stream *s);
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
new file mode 100644
index 0000000..2694ce3
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -0,0 +1,373 @@
+/*
+ * cx18 firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-scb.h"
+#include "cx18-irq.h"
+#include "cx18-firmware.h"
+#include "cx18-cards.h"
+#include <linux/firmware.h>
+
+#define CX18_PROC_SOFT_RESET 0xc70010
+#define CX18_DDR_SOFT_RESET 0xc70014
+#define CX18_CLOCK_SELECT1 0xc71000
+#define CX18_CLOCK_SELECT2 0xc71004
+#define CX18_HALF_CLOCK_SELECT1 0xc71008
+#define CX18_HALF_CLOCK_SELECT2 0xc7100C
+#define CX18_CLOCK_POLARITY1 0xc71010
+#define CX18_CLOCK_POLARITY2 0xc71014
+#define CX18_ADD_DELAY_ENABLE1 0xc71018
+#define CX18_ADD_DELAY_ENABLE2 0xc7101C
+#define CX18_CLOCK_ENABLE1 0xc71020
+#define CX18_CLOCK_ENABLE2 0xc71024
+
+#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
+
+#define CX18_AUDIO_ENABLE 0xc72014
+#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
+
+#define CX18_FAST_CLOCK_PLL_INT 0xc78000
+#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
+#define CX18_FAST_CLOCK_PLL_POST 0xc78008
+#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C
+#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010
+
+#define CX18_SLOW_CLOCK_PLL_INT 0xc78014
+#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018
+#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C
+#define CX18_MPEG_CLOCK_PLL_INT 0xc78040
+#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044
+#define CX18_MPEG_CLOCK_PLL_POST 0xc78048
+#define CX18_PLL_POWER_DOWN 0xc78088
+#define CX18_SW1_INT_STATUS 0xc73104
+#define CX18_SW1_INT_ENABLE_PCI 0xc7311C
+#define CX18_SW2_INT_SET 0xc73140
+#define CX18_SW2_INT_STATUS 0xc73144
+#define CX18_ADEC_CONTROL 0xc78120
+
+#define CX18_DDR_REQUEST_ENABLE 0xc80000
+#define CX18_DDR_CHIP_CONFIG 0xc80004
+#define CX18_DDR_REFRESH 0xc80008
+#define CX18_DDR_TIMING1 0xc8000C
+#define CX18_DDR_TIMING2 0xc80010
+#define CX18_DDR_POWER_REG 0xc8001C
+
+#define CX18_DDR_TUNE_LANE 0xc80048
+#define CX18_DDR_INITIAL_EMRS 0xc80054
+#define CX18_DDR_MB_PER_ROW_7 0xc8009C
+#define CX18_DDR_BASE_63_ADDR 0xc804FC
+
+#define CX18_WMB_CLIENT02 0xc90108
+#define CX18_WMB_CLIENT05 0xc90114
+#define CX18_WMB_CLIENT06 0xc90118
+#define CX18_WMB_CLIENT07 0xc9011C
+#define CX18_WMB_CLIENT08 0xc90120
+#define CX18_WMB_CLIENT09 0xc90124
+#define CX18_WMB_CLIENT10 0xc90128
+#define CX18_WMB_CLIENT11 0xc9012C
+#define CX18_WMB_CLIENT12 0xc90130
+#define CX18_WMB_CLIENT13 0xc90134
+#define CX18_WMB_CLIENT14 0xc90138
+
+#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
+
+/* Encoder/decoder firmware sizes */
+#define CX18_FW_CPU_SIZE (174716)
+#define CX18_FW_APU_SIZE (141200)
+
+#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
+#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */
+
+struct cx18_apu_rom_seghdr {
+ u32 sync1;
+ u32 sync2;
+ u32 addr;
+ u32 size;
+};
+
+static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx, long size)
+{
+ const struct firmware *fw = NULL;
+ int retries = 3;
+ int i, j;
+ u32 __iomem *dst = (u32 __iomem *)mem;
+ const u32 *src;
+
+retry:
+ if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) {
+ CX18_ERR("Unable to open firmware %s (must be %ld bytes)\n",
+ fn, size);
+ CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
+ return -ENOMEM;
+ }
+
+ src = (const u32 *)fw->data;
+
+ if (fw->size != size) {
+ /* Due to race conditions in firmware loading (esp. with
+ udev <0.95) the wrong file was sometimes loaded. So we check
+ filesizes to see if at least the right-sized file was
+ loaded. If not, then we retry. */
+ CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n",
+ fn, size, fw->size);
+ release_firmware(fw);
+ retries--;
+ goto retry;
+ }
+ for (i = 0; i < fw->size; i += 4096) {
+ setup_page(i);
+ for (j = i; j < fw->size && j < i + 4096; j += 4) {
+ /* no need for endianness conversion on the ppc */
+ __raw_writel(*src, dst);
+ if (__raw_readl(dst) != *src) {
+ CX18_ERR("Mismatch at offset %x\n", i);
+ release_firmware(fw);
+ return -EIO;
+ }
+ dst++;
+ src++;
+ }
+ }
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+ CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
+ release_firmware(fw);
+ return size;
+}
+
+static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size)
+{
+ const struct firmware *fw = NULL;
+ int retries = 3;
+ int i, j;
+ const u32 *src;
+ struct cx18_apu_rom_seghdr seghdr;
+ const u8 *vers;
+ u32 offset = 0;
+ u32 apu_version = 0;
+ int sz;
+
+retry:
+ if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) {
+ CX18_ERR("unable to open firmware %s (must be %ld bytes)\n",
+ fn, size);
+ CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
+ return -ENOMEM;
+ }
+
+ src = (const u32 *)fw->data;
+ vers = fw->data + sizeof(seghdr);
+ sz = fw->size;
+
+ if (fw->size != size) {
+ /* Due to race conditions in firmware loading (esp. with
+ udev <0.95) the wrong file was sometimes loaded. So we check
+ filesizes to see if at least the right-sized file was
+ loaded. If not, then we retry. */
+ CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n",
+ fn, size, fw->size);
+ release_firmware(fw);
+ retries--;
+ goto retry;
+ }
+ apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
+ while (offset + sizeof(seghdr) < size) {
+ /* TODO: byteswapping */
+ memcpy(&seghdr, src + offset / 4, sizeof(seghdr));
+ offset += sizeof(seghdr);
+ if (seghdr.sync1 != APU_ROM_SYNC1 ||
+ seghdr.sync2 != APU_ROM_SYNC2) {
+ offset += seghdr.size;
+ continue;
+ }
+ CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr,
+ seghdr.addr + seghdr.size - 1);
+ if (offset + seghdr.size > sz)
+ break;
+ for (i = 0; i < seghdr.size; i += 4096) {
+ setup_page(offset + i);
+ for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
+ /* no need for endianness conversion on the ppc */
+ __raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j);
+ if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) {
+ CX18_ERR("Mismatch at offset %x\n", offset + j);
+ release_firmware(fw);
+ return -EIO;
+ }
+ }
+ }
+ offset += seghdr.size;
+ }
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
+ CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
+ fn, apu_version, fw->size);
+ release_firmware(fw);
+ /* Clear bit0 for APU to start from 0 */
+ write_reg(read_reg(0xc72030) & ~1, 0xc72030);
+ return size;
+}
+
+void cx18_halt_firmware(struct cx18 *cx)
+{
+ CX18_DEBUG_INFO("Preparing for firmware halt.\n");
+ write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+ write_reg(0x00020002, CX18_ADEC_CONTROL);
+}
+
+void cx18_init_power(struct cx18 *cx, int lowpwr)
+{
+ /* power-down Spare and AOM PLLs */
+ /* power-up fast, slow and mpeg PLLs */
+ write_reg(0x00000008, CX18_PLL_POWER_DOWN);
+
+ /* ADEC out of sleep */
+ write_reg(0x00020000, CX18_ADEC_CONTROL);
+
+ /* The fast clock is at 200/245 MHz */
+ write_reg(lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
+ write_reg(lowpwr ? 0x1EFBF37 : 0x038E3D7, CX18_FAST_CLOCK_PLL_FRAC);
+
+ write_reg(2, CX18_FAST_CLOCK_PLL_POST);
+ write_reg(1, CX18_FAST_CLOCK_PLL_PRESCALE);
+ write_reg(4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
+
+ /* set slow clock to 125/120 MHz */
+ write_reg(lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
+ write_reg(lowpwr ? 0xEBAF05 : 0x18618A8, CX18_SLOW_CLOCK_PLL_FRAC);
+ write_reg(4, CX18_SLOW_CLOCK_PLL_POST);
+
+ /* mpeg clock pll 54MHz */
+ write_reg(0xF, CX18_MPEG_CLOCK_PLL_INT);
+ write_reg(0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
+ write_reg(8, CX18_MPEG_CLOCK_PLL_POST);
+
+ /* Defaults */
+ /* APU = SC or SC/2 = 125/62.5 */
+ /* EPU = SC = 125 */
+ /* DDR = FC = 180 */
+ /* ENC = SC = 125 */
+ /* AI1 = SC = 125 */
+ /* VIM2 = disabled */
+ /* PCI = FC/2 = 90 */
+ /* AI2 = disabled */
+ /* DEMUX = disabled */
+ /* AO = SC/2 = 62.5 */
+ /* SER = 54MHz */
+ /* VFC = disabled */
+ /* USB = disabled */
+
+ write_reg(lowpwr ? 0xFFFF0020 : 0x00060004, CX18_CLOCK_SELECT1);
+ write_reg(lowpwr ? 0xFFFF0004 : 0x00060006, CX18_CLOCK_SELECT2);
+
+ write_reg(0xFFFF0002, CX18_HALF_CLOCK_SELECT1);
+ write_reg(0xFFFF0104, CX18_HALF_CLOCK_SELECT2);
+
+ write_reg(0xFFFF9026, CX18_CLOCK_ENABLE1);
+ write_reg(0xFFFF3105, CX18_CLOCK_ENABLE2);
+}
+
+void cx18_init_memory(struct cx18 *cx)
+{
+ cx18_msleep_timeout(10, 0);
+ write_reg(0x10000, CX18_DDR_SOFT_RESET);
+ cx18_msleep_timeout(10, 0);
+
+ write_reg(cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
+
+ cx18_msleep_timeout(10, 0);
+
+ write_reg(cx->card->ddr.refresh, CX18_DDR_REFRESH);
+ write_reg(cx->card->ddr.timing1, CX18_DDR_TIMING1);
+ write_reg(cx->card->ddr.timing2, CX18_DDR_TIMING2);
+
+ cx18_msleep_timeout(10, 0);
+
+ /* Initialize DQS pad time */
+ write_reg(cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
+ write_reg(cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
+
+ cx18_msleep_timeout(10, 0);
+
+ write_reg(0x20000, CX18_DDR_SOFT_RESET);
+ cx18_msleep_timeout(10, 0);
+
+ /* use power-down mode when idle */
+ write_reg(0x00000010, CX18_DDR_POWER_REG);
+
+ write_reg(0x10001, CX18_REG_BUS_TIMEOUT_EN);
+
+ write_reg(0x48, CX18_DDR_MB_PER_ROW_7);
+ write_reg(0xE0000, CX18_DDR_BASE_63_ADDR);
+
+ write_reg(0x00000101, CX18_WMB_CLIENT02); /* AO */
+ write_reg(0x00000101, CX18_WMB_CLIENT09); /* AI2 */
+ write_reg(0x00000101, CX18_WMB_CLIENT05); /* VIM1 */
+ write_reg(0x00000101, CX18_WMB_CLIENT06); /* AI1 */
+ write_reg(0x00000101, CX18_WMB_CLIENT07); /* 3D comb */
+ write_reg(0x00000101, CX18_WMB_CLIENT10); /* ME */
+ write_reg(0x00000101, CX18_WMB_CLIENT12); /* ENC */
+ write_reg(0x00000101, CX18_WMB_CLIENT13); /* PK */
+ write_reg(0x00000101, CX18_WMB_CLIENT11); /* RC */
+ write_reg(0x00000101, CX18_WMB_CLIENT14); /* AVO */
+}
+
+int cx18_firmware_init(struct cx18 *cx)
+{
+ /* Allow chip to control CLKRUN */
+ write_reg(0x5, CX18_DSP0_INTERRUPT_MASK);
+
+ write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
+
+ cx18_msleep_timeout(1, 0);
+
+ sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
+ sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
+
+ /* Only if the processor is not running */
+ if (read_reg(CX18_PROC_SOFT_RESET) & 8) {
+ int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
+ cx->enc_mem, cx, CX18_FW_APU_SIZE);
+
+ sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
+ cx->enc_mem, cx, CX18_FW_CPU_SIZE);
+
+ if (sz > 0) {
+ int retries = 0;
+
+ /* start the CPU */
+ write_reg(0x00080000, CX18_PROC_SOFT_RESET);
+ while (retries++ < 50) { /* Loop for max 500mS */
+ if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0)
+ break;
+ cx18_msleep_timeout(10, 0);
+ }
+ cx18_msleep_timeout(200, 0);
+ if (retries == 51) {
+ CX18_ERR("Could not start the CPU\n");
+ return -EIO;
+ }
+ }
+ if (sz <= 0)
+ return -EIO;
+ }
+ /* initialize GPIO */
+ write_reg(0x14001400, 0xC78110);
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-firmware.h b/drivers/media/video/cx18/cx18-firmware.h
new file mode 100644
index 0000000..38d4c05
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-firmware.h
@@ -0,0 +1,25 @@
+/*
+ * cx18 firmware functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_firmware_init(struct cx18 *cx);
+void cx18_halt_firmware(struct cx18 *cx);
+void cx18_init_memory(struct cx18 *cx);
+void cx18_init_power(struct cx18 *cx, int lowpwr);
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
new file mode 100644
index 0000000..19253e6
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -0,0 +1,74 @@
+/*
+ * cx18 gpio functions
+ *
+ * Derived from ivtv-gpio.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "tuner-xc2028.h"
+
+/********************* GPIO stuffs *********************/
+
+/* GPIO registers */
+#define CX18_REG_GPIO_IN 0xc72010
+#define CX18_REG_GPIO_OUT1 0xc78100
+#define CX18_REG_GPIO_DIR1 0xc78108
+#define CX18_REG_GPIO_OUT2 0xc78104
+#define CX18_REG_GPIO_DIR2 0xc7810c
+
+/*
+ * HVR-1600 GPIO pins, courtesy of Hauppauge:
+ *
+ * gpio0: zilog ir process reset pin
+ * gpio1: zilog programming pin (you should never use this)
+ * gpio12: cx24227 reset pin
+ * gpio13: cs5345 reset pin
+*/
+
+void cx18_gpio_init(struct cx18 *cx)
+{
+ if (cx->card->gpio_init.direction == 0)
+ return;
+
+ CX18_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
+ read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_OUT1));
+
+ /* init output data then direction */
+ write_reg(cx->card->gpio_init.direction << 16, CX18_REG_GPIO_DIR1);
+ write_reg(0, CX18_REG_GPIO_DIR2);
+ write_reg((cx->card->gpio_init.direction << 16) |
+ cx->card->gpio_init.initial_value, CX18_REG_GPIO_OUT1);
+ write_reg(0, CX18_REG_GPIO_OUT2);
+}
+
+/* Xceive tuner reset function */
+int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
+{
+ struct i2c_algo_bit_data *algo = dev;
+ struct cx18 *cx = algo->data;
+/* int curdir, curout;*/
+
+ if (cmd != XC2028_TUNER_RESET)
+ return 0;
+ CX18_DEBUG_INFO("Resetting tuner\n");
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
new file mode 100644
index 0000000..41bac88
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -0,0 +1,24 @@
+/*
+ * cx18 gpio functions
+ *
+ * Derived from ivtv-gpio.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+void cx18_gpio_init(struct cx18 *cx);
+int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
new file mode 100644
index 0000000..18c88d1
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -0,0 +1,431 @@
+/*
+ * cx18 I2C functions
+ *
+ * Derived from ivtv-i2c.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-cards.h"
+#include "cx18-gpio.h"
+#include "cx18-av-core.h"
+
+#include <media/ir-kbd-i2c.h>
+
+#define CX18_REG_I2C_1_WR 0xf15000
+#define CX18_REG_I2C_1_RD 0xf15008
+#define CX18_REG_I2C_2_WR 0xf25100
+#define CX18_REG_I2C_2_RD 0xf25108
+
+#define SETSCL_BIT 0x0001
+#define SETSDL_BIT 0x0002
+#define GETSCL_BIT 0x0004
+#define GETSDL_BIT 0x0008
+
+#ifndef I2C_ADAP_CLASS_TV_ANALOG
+#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
+#endif
+
+#define CX18_CS5345_I2C_ADDR 0x4c
+
+/* This array should match the CX18_HW_ defines */
+static const u8 hw_driverids[] = {
+ I2C_DRIVERID_TUNER,
+ I2C_DRIVERID_TVEEPROM,
+ I2C_DRIVERID_CS5345,
+ 0, /* CX18_HW_GPIO dummy driver ID */
+ 0 /* CX18_HW_CX23418 dummy driver ID */
+};
+
+/* This array should match the CX18_HW_ defines */
+static const u8 hw_addrs[] = {
+ 0,
+ 0,
+ CX18_CS5345_I2C_ADDR,
+ 0, /* CX18_HW_GPIO dummy driver ID */
+ 0, /* CX18_HW_CX23418 dummy driver ID */
+};
+
+/* This array should match the CX18_HW_ defines */
+/* This might well become a card-specific array */
+static const u8 hw_bus[] = {
+ 0,
+ 0,
+ 0,
+ 0, /* CX18_HW_GPIO dummy driver ID */
+ 0, /* CX18_HW_CX23418 dummy driver ID */
+};
+
+/* This array should match the CX18_HW_ defines */
+static const char * const hw_drivernames[] = {
+ "tuner",
+ "tveeprom",
+ "cs5345",
+ "gpio",
+ "cx23418",
+};
+
+int cx18_i2c_register(struct cx18 *cx, unsigned idx)
+{
+ struct i2c_board_info info;
+ struct i2c_client *c;
+ u8 id, bus;
+ int i;
+
+ CX18_DEBUG_I2C("i2c client register\n");
+ if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
+ return -1;
+ id = hw_driverids[idx];
+ bus = hw_bus[idx];
+ memset(&info, 0, sizeof(info));
+ strlcpy(info.driver_name, hw_drivernames[idx],
+ sizeof(info.driver_name));
+ info.addr = hw_addrs[idx];
+ for (i = 0; i < I2C_CLIENTS_MAX; i++)
+ if (cx->i2c_clients[i] == NULL)
+ break;
+
+ if (i == I2C_CLIENTS_MAX) {
+ CX18_ERR("insufficient room for new I2C client!\n");
+ return -ENOMEM;
+ }
+
+ if (id != I2C_DRIVERID_TUNER) {
+ c = i2c_new_device(&cx->i2c_adap[bus], &info);
+ if (c->driver == NULL)
+ i2c_unregister_device(c);
+ else
+ cx->i2c_clients[i] = c;
+ return cx->i2c_clients[i] ? 0 : -ENODEV;
+ }
+
+ /* special tuner handling */
+ c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio);
+ if (c && c->driver == NULL)
+ i2c_unregister_device(c);
+ else if (c)
+ cx->i2c_clients[i++] = c;
+ c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod);
+ if (c && c->driver == NULL)
+ i2c_unregister_device(c);
+ else if (c)
+ cx->i2c_clients[i++] = c;
+ c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv);
+ if (c && c->driver == NULL)
+ i2c_unregister_device(c);
+ else if (c)
+ cx->i2c_clients[i++] = c;
+ return 0;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+ return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+ int i;
+ struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter);
+
+ CX18_DEBUG_I2C("i2c client detach\n");
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ if (cx->i2c_clients[i] == client) {
+ cx->i2c_clients[i] = NULL;
+ break;
+ }
+ }
+ CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n",
+ client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
+
+ return 0;
+}
+
+static void cx18_setscl(void *data, int state)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
+ u32 r = read_reg(addr);
+
+ if (state)
+ write_reg_sync(r | SETSCL_BIT, addr);
+ else
+ write_reg_sync(r & ~SETSCL_BIT, addr);
+}
+
+static void cx18_setsda(void *data, int state)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
+ u32 r = read_reg(addr);
+
+ if (state)
+ write_reg_sync(r | SETSDL_BIT, addr);
+ else
+ write_reg_sync(r & ~SETSDL_BIT, addr);
+}
+
+static int cx18_getscl(void *data)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
+
+ return read_reg(addr) & GETSCL_BIT;
+}
+
+static int cx18_getsda(void *data)
+{
+ struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
+ int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
+ u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
+
+ return read_reg(addr) & GETSDL_BIT;
+}
+
+/* template for i2c-bit-algo */
+static struct i2c_adapter cx18_i2c_adap_template = {
+ .name = "cx18 i2c driver",
+ .id = I2C_HW_B_CX2341X,
+ .algo = NULL, /* set by i2c-algo-bit */
+ .algo_data = NULL, /* filled from template */
+ .client_register = attach_inform,
+ .client_unregister = detach_inform,
+ .owner = THIS_MODULE,
+};
+
+#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */
+#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */
+
+static struct i2c_algo_bit_data cx18_i2c_algo_template = {
+ .setsda = cx18_setsda,
+ .setscl = cx18_setscl,
+ .getsda = cx18_getsda,
+ .getscl = cx18_getscl,
+ .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/
+ .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
+};
+
+static struct i2c_client cx18_i2c_client_template = {
+ .name = "cx18 internal",
+};
+
+int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg)
+{
+ struct i2c_client *client;
+ int retval;
+ int i;
+
+ CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ client = cx->i2c_clients[i];
+ if (client == NULL || client->driver == NULL ||
+ client->driver->command == NULL)
+ continue;
+ if (addr == client->addr) {
+ retval = client->driver->command(client, cmd, arg);
+ return retval;
+ }
+ }
+ if (cmd != VIDIOC_G_CHIP_IDENT)
+ CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n",
+ addr, cmd);
+ return -ENODEV;
+}
+
+/* Find the i2c device based on the driver ID and return
+ its i2c address or -ENODEV if no matching device was found. */
+static int cx18_i2c_id_addr(struct cx18 *cx, u32 id)
+{
+ struct i2c_client *client;
+ int retval = -ENODEV;
+ int i;
+
+ for (i = 0; i < I2C_CLIENTS_MAX; i++) {
+ client = cx->i2c_clients[i];
+ if (client == NULL || client->driver == NULL)
+ continue;
+ if (id == client->driver->id) {
+ retval = client->addr;
+ break;
+ }
+ }
+ return retval;
+}
+
+/* Find the i2c device name matching the DRIVERID */
+static const char *cx18_i2c_id_name(u32 id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+ if (hw_driverids[i] == id)
+ return hw_drivernames[i];
+ return "unknown device";
+}
+
+/* Find the i2c device name matching the CX18_HW_ flag */
+static const char *cx18_i2c_hw_name(u32 hw)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+ if (1 << i == hw)
+ return hw_drivernames[i];
+ return "unknown device";
+}
+
+/* Find the i2c device matching the CX18_HW_ flag and return
+ its i2c address or -ENODEV if no matching device was found. */
+int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
+ if (1 << i == hw)
+ return cx18_i2c_id_addr(cx, hw_driverids[i]);
+ return -ENODEV;
+}
+
+/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing.
+ If hw == CX18_HW_GPIO then call the gpio handler. */
+int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
+{
+ int addr;
+
+ if (hw == CX18_HW_GPIO || hw == 0)
+ return 0;
+ if (hw == CX18_HW_CX23418)
+ return cx18_av_cmd(cx, cmd, arg);
+
+ addr = cx18_i2c_hw_addr(cx, hw);
+ if (addr < 0) {
+ CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n",
+ hw, cx18_i2c_hw_name(hw), cmd);
+ return addr;
+ }
+ return cx18_call_i2c_client(cx, addr, cmd, arg);
+}
+
+/* Calls i2c device based on I2C driver ID. */
+int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg)
+{
+ int addr;
+
+ addr = cx18_i2c_id_addr(cx, id);
+ if (addr < 0) {
+ if (cmd != VIDIOC_G_CHIP_IDENT)
+ CX18_ERR("i2c ID 0x%08x (%s) not found for cmd 0x%x!\n",
+ id, cx18_i2c_id_name(id), cmd);
+ return addr;
+ }
+ return cx18_call_i2c_client(cx, addr, cmd, arg);
+}
+
+/* broadcast cmd for all I2C clients and for the gpio subsystem */
+void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) {
+ CX18_ERR("adapter is not set\n");
+ return;
+ }
+ cx18_av_cmd(cx, cmd, arg);
+ i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
+ i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
+}
+
+/* init + register i2c algo-bit adapter */
+int init_cx18_i2c(struct cx18 *cx)
+{
+ int i;
+ CX18_DEBUG_I2C("i2c init\n");
+
+ for (i = 0; i < 2; i++) {
+ memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
+ sizeof(struct i2c_adapter));
+ memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template,
+ sizeof(struct i2c_algo_bit_data));
+ cx->i2c_algo_cb_data[i].cx = cx;
+ cx->i2c_algo_cb_data[i].bus_index = i;
+ cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
+ cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
+
+ sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
+ " #%d-%d", cx->num, i);
+ i2c_set_adapdata(&cx->i2c_adap[i], cx);
+
+ memcpy(&cx->i2c_client[i], &cx18_i2c_client_template,
+ sizeof(struct i2c_client));
+ sprintf(cx->i2c_client[i].name +
+ strlen(cx->i2c_client[i].name), "%d", i);
+ cx->i2c_client[i].adapter = &cx->i2c_adap[i];
+ cx->i2c_adap[i].dev.parent = &cx->dev->dev;
+ }
+
+ if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) {
+ /* Reset/Unreset I2C hardware block */
+ write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */
+ write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */
+ }
+ /* courtesy of Steven Toth <stoth@hauppauge.com> */
+ write_reg_sync(0x00c00000, 0xc7001c);
+ mdelay(10);
+ write_reg_sync(0x00c000c0, 0xc7001c);
+ mdelay(10);
+ write_reg_sync(0x00c00000, 0xc7001c);
+
+ write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
+ write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
+
+ /* Hw I2C1 Clock Freq ~100kHz */
+ write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR);
+ cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
+ cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
+
+ /* Hw I2C2 Clock Freq ~100kHz */
+ write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR);
+ cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
+ cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
+
+ return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
+ i2c_bit_add_bus(&cx->i2c_adap[1]);
+}
+
+void exit_cx18_i2c(struct cx18 *cx)
+{
+ int i;
+ CX18_DEBUG_I2C("i2c exit\n");
+ write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR);
+ write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR);
+
+ for (i = 0; i < 2; i++) {
+ i2c_del_adapter(&cx->i2c_adap[i]);
+ }
+}
+
+/*
+ Hauppauge HVR1600 should have:
+ 32 cx24227
+ 98 unknown
+ a0 eeprom
+ c2 tuner
+ e? zilog ir
+ */
diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h
new file mode 100644
index 0000000..113c3f9
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-i2c.h
@@ -0,0 +1,33 @@
+/*
+ * cx18 I2C functions
+ *
+ * Derived from ivtv-i2c.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw);
+int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg);
+int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg);
+int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg);
+void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg);
+int cx18_i2c_register(struct cx18 *cx, unsigned idx);
+
+/* init + register i2c algo-bit adapter */
+int init_cx18_i2c(struct cx18 *cx);
+void exit_cx18_i2c(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
new file mode 100644
index 0000000..dbdcb86
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -0,0 +1,851 @@
+/*
+ * cx18 ioctl system call
+ *
+ * Derived from ivtv-ioctl.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-version.h"
+#include "cx18-mailbox.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-fileops.h"
+#include "cx18-vbi.h"
+#include "cx18-audio.h"
+#include "cx18-video.h"
+#include "cx18-streams.h"
+#include "cx18-ioctl.h"
+#include "cx18-gpio.h"
+#include "cx18-controls.h"
+#include "cx18-cards.h"
+#include "cx18-av-core.h"
+#include <media/tveeprom.h>
+#include <media/v4l2-chip-ident.h>
+#include <linux/i2c-id.h>
+
+u16 cx18_service2vbi(int type)
+{
+ switch (type) {
+ case V4L2_SLICED_TELETEXT_B:
+ return CX18_SLICED_TYPE_TELETEXT_B;
+ case V4L2_SLICED_CAPTION_525:
+ return CX18_SLICED_TYPE_CAPTION_525;
+ case V4L2_SLICED_WSS_625:
+ return CX18_SLICED_TYPE_WSS_625;
+ case V4L2_SLICED_VPS:
+ return CX18_SLICED_TYPE_VPS;
+ default:
+ return 0;
+ }
+}
+
+static int valid_service_line(int field, int line, int is_pal)
+{
+ return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
+ (!is_pal && line >= 10 && line < 22);
+}
+
+static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
+{
+ u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
+ int i;
+
+ set = set & valid_set;
+ if (set == 0 || !valid_service_line(field, line, is_pal))
+ return 0;
+ if (!is_pal) {
+ if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
+ return V4L2_SLICED_CAPTION_525;
+ } else {
+ if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
+ return V4L2_SLICED_VPS;
+ if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
+ return V4L2_SLICED_WSS_625;
+ if (line == 23)
+ return 0;
+ }
+ for (i = 0; i < 32; i++) {
+ if ((1 << i) & set)
+ return 1 << i;
+ }
+ return 0;
+}
+
+void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+ u16 set = fmt->service_set;
+ int f, l;
+
+ fmt->service_set = 0;
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++)
+ fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
+ }
+}
+
+static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
+{
+ int f, l;
+ u16 set = 0;
+
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++) {
+ fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
+ set |= fmt->service_lines[f][l];
+ }
+ }
+ return set != 0;
+}
+
+u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt)
+{
+ int f, l;
+ u16 set = 0;
+
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++)
+ set |= fmt->service_lines[f][l];
+ }
+ return set;
+}
+
+static const struct {
+ v4l2_std_id std;
+ char *name;
+} enum_stds[] = {
+ { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
+ { V4L2_STD_PAL_DK, "PAL-DK" },
+ { V4L2_STD_PAL_I, "PAL-I" },
+ { V4L2_STD_PAL_M, "PAL-M" },
+ { V4L2_STD_PAL_N, "PAL-N" },
+ { V4L2_STD_PAL_Nc, "PAL-Nc" },
+ { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
+ { V4L2_STD_SECAM_DK, "SECAM-DK" },
+ { V4L2_STD_SECAM_L, "SECAM-L" },
+ { V4L2_STD_SECAM_LC, "SECAM-L'" },
+ { V4L2_STD_NTSC_M, "NTSC-M" },
+ { V4L2_STD_NTSC_M_JP, "NTSC-J" },
+ { V4L2_STD_NTSC_M_KR, "NTSC-K" },
+};
+
+static const struct v4l2_standard cx18_std_60hz = {
+ .frameperiod = {.numerator = 1001, .denominator = 30000},
+ .framelines = 525,
+};
+
+static const struct v4l2_standard cx18_std_50hz = {
+ .frameperiod = { .numerator = 1, .denominator = 25 },
+ .framelines = 625,
+};
+
+static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
+{
+ struct v4l2_register *regs = arg;
+ unsigned long flags;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
+ return -EINVAL;
+
+ spin_lock_irqsave(&cx18_cards_lock, flags);
+ if (cmd == VIDIOC_DBG_G_REGISTER)
+ regs->val = read_enc(regs->reg);
+ else
+ write_enc(regs->val, regs->reg);
+ spin_unlock_irqrestore(&cx18_cards_lock, flags);
+ return 0;
+}
+
+static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt)
+{
+ switch (fmt->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ fmt->fmt.pix.width = cx->params.width;
+ fmt->fmt.pix.height = cx->params.height;
+ fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ if (streamtype == CX18_ENC_STREAM_TYPE_YUV) {
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
+ /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
+ fmt->fmt.pix.sizeimage =
+ fmt->fmt.pix.height * fmt->fmt.pix.width +
+ fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
+ } else {
+ fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ fmt->fmt.pix.sizeimage = 128 * 1024;
+ }
+ break;
+
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ fmt->fmt.vbi.sampling_rate = 27000000;
+ fmt->fmt.vbi.offset = 248;
+ fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4;
+ fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ fmt->fmt.vbi.start[0] = cx->vbi.start[0];
+ fmt->fmt.vbi.start[1] = cx->vbi.start[1];
+ fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count;
+ break;
+
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ {
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+ memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+ memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
+
+ cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
+ vbifmt->service_set = cx18_get_service_set(vbifmt);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
+ struct v4l2_format *fmt, int set_fmt)
+{
+ struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
+ u16 set;
+
+ /* set window size */
+ if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ int w = fmt->fmt.pix.width;
+ int h = fmt->fmt.pix.height;
+
+ if (w > 720)
+ w = 720;
+ else if (w < 1)
+ w = 1;
+ if (h > (cx->is_50hz ? 576 : 480))
+ h = (cx->is_50hz ? 576 : 480);
+ else if (h < 2)
+ h = 2;
+ cx18_get_fmt(cx, streamtype, fmt);
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+
+ if (!set_fmt || (cx->params.width == w && cx->params.height == h))
+ return 0;
+ if (atomic_read(&cx->capturing) > 0)
+ return -EBUSY;
+
+ cx->params.width = w;
+ cx->params.height = h;
+ if (w != 720 || h != (cx->is_50hz ? 576 : 480))
+ cx->params.video_temporal_filter = 0;
+ else
+ cx->params.video_temporal_filter = 8;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ return cx18_get_fmt(cx, streamtype, fmt);
+ }
+
+ /* set raw VBI format */
+ if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
+ cx->vbi.sliced_in->service_set &&
+ atomic_read(&cx->capturing) > 0)
+ return -EBUSY;
+ if (set_fmt) {
+ cx->vbi.sliced_in->service_set = 0;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+ }
+ return cx18_get_fmt(cx, streamtype, fmt);
+ }
+
+ /* any else but sliced VBI capture is an error */
+ if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
+ return -EINVAL;
+
+ /* TODO: implement sliced VBI, for now silently return 0 */
+ return 0;
+
+ /* set sliced VBI capture format */
+ vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
+ memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
+
+ if (vbifmt->service_set)
+ cx18_expand_service_set(vbifmt, cx->is_50hz);
+ set = check_service_set(vbifmt, cx->is_50hz);
+ vbifmt->service_set = cx18_get_service_set(vbifmt);
+
+ if (!set_fmt)
+ return 0;
+ if (set == 0)
+ return -EINVAL;
+ if (atomic_read(&cx->capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
+ return -EBUSY;
+ cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
+ memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
+ return 0;
+}
+
+static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
+{
+ struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18 *cx = id->cx;
+ struct v4l2_register *reg = arg;
+
+ switch (cmd) {
+ /* ioctls to allow direct access to the encoder registers for testing */
+ case VIDIOC_DBG_G_REGISTER:
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, cmd, arg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
+ return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+
+ case VIDIOC_DBG_S_REGISTER:
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
+ return cx18_cxc(cx, cmd, arg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
+ return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+
+ case VIDIOC_G_CHIP_IDENT: {
+ struct v4l2_chip_ident *chip = arg;
+
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
+ if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
+ struct v4l2_chip_ident *chip = arg;
+
+ chip->ident = V4L2_IDENT_CX23418;
+ }
+ return 0;
+ }
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
+ return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
+ if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
+ return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
+ return -EINVAL;
+ }
+
+ case VIDIOC_INT_S_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
+
+ cx18_audio_set_route(cx, route);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg)
+{
+ struct cx18_open_id *id = NULL;
+
+ if (filp)
+ id = (struct cx18_open_id *)filp->private_data;
+
+ switch (cmd) {
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p = arg;
+
+ *p = v4l2_prio_max(&cx->prio);
+ break;
+ }
+
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *prio = arg;
+
+ return v4l2_prio_change(&cx->prio, &id->prio, *prio);
+ }
+
+ case VIDIOC_QUERYCAP:{
+ struct v4l2_capability *vcap = arg;
+
+ memset(vcap, 0, sizeof(*vcap));
+ strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
+ strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
+ vcap->version = CX18_DRIVER_VERSION; /* version */
+ vcap->capabilities = cx->v4l2_cap; /* capabilities */
+
+ /* reserved.. must set to 0! */
+ vcap->reserved[0] = vcap->reserved[1] =
+ vcap->reserved[2] = vcap->reserved[3] = 0;
+ break;
+ }
+
+ case VIDIOC_ENUMAUDIO:{
+ struct v4l2_audio *vin = arg;
+
+ return cx18_get_audio_input(cx, vin->index, vin);
+ }
+
+ case VIDIOC_G_AUDIO:{
+ struct v4l2_audio *vin = arg;
+
+ vin->index = cx->audio_input;
+ return cx18_get_audio_input(cx, vin->index, vin);
+ }
+
+ case VIDIOC_S_AUDIO:{
+ struct v4l2_audio *vout = arg;
+
+ if (vout->index >= cx->nof_audio_inputs)
+ return -EINVAL;
+ cx->audio_input = vout->index;
+ cx18_audio_set_io(cx);
+ break;
+ }
+
+ case VIDIOC_ENUMINPUT:{
+ struct v4l2_input *vin = arg;
+
+ /* set it to defaults from our table */
+ return cx18_get_input(cx, vin->index, vin);
+ }
+
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_S_FMT: {
+ struct v4l2_format *fmt = arg;
+
+ return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT);
+ }
+
+ case VIDIOC_G_FMT: {
+ struct v4l2_format *fmt = arg;
+ int type = fmt->type;
+
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->type = type;
+ return cx18_get_fmt(cx, id->type, fmt);
+ }
+
+ case VIDIOC_CROPCAP: {
+ struct v4l2_cropcap *cropcap = arg;
+
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ cropcap->bounds.top = cropcap->bounds.left = 0;
+ cropcap->bounds.width = 720;
+ cropcap->bounds.height = cx->is_50hz ? 576 : 480;
+ cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
+ cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
+ cropcap->defrect = cropcap->bounds;
+ return 0;
+ }
+
+ case VIDIOC_S_CROP: {
+ struct v4l2_crop *crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_S_CROP, arg);
+ }
+
+ case VIDIOC_G_CROP: {
+ struct v4l2_crop *crop = arg;
+
+ if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ return cx18_av_cmd(cx, VIDIOC_G_CROP, arg);
+ }
+
+ case VIDIOC_ENUM_FMT: {
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, 0, 0,
+ "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
+ { 0, 0, 0, 0 }
+ },
+ { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
+ "MPEG", V4L2_PIX_FMT_MPEG,
+ { 0, 0, 0, 0 }
+ }
+ };
+ struct v4l2_fmtdesc *fmt = arg;
+ enum v4l2_buf_type type = fmt->type;
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (fmt->index > 1)
+ return -EINVAL;
+ *fmt = formats[fmt->index];
+ fmt->type = type;
+ return 0;
+ }
+
+ case VIDIOC_G_INPUT:{
+ *(int *)arg = cx->active_input;
+ break;
+ }
+
+ case VIDIOC_S_INPUT:{
+ int inp = *(int *)arg;
+
+ if (inp < 0 || inp >= cx->nof_inputs)
+ return -EINVAL;
+
+ if (inp == cx->active_input) {
+ CX18_DEBUG_INFO("Input unchanged\n");
+ break;
+ }
+ CX18_DEBUG_INFO("Changing input from %d to %d\n",
+ cx->active_input, inp);
+
+ cx->active_input = inp;
+ /* Set the audio input to whatever is appropriate for the
+ input type. */
+ cx->audio_input = cx->card->video_inputs[inp].audio_index;
+
+ /* prevent others from messing with the streams until
+ we're finished changing inputs. */
+ cx18_mute(cx);
+ cx18_video_set_io(cx);
+ cx18_audio_set_io(cx);
+ cx18_unmute(cx);
+ break;
+ }
+
+ case VIDIOC_G_FREQUENCY:{
+ struct v4l2_frequency *vf = arg;
+
+ if (vf->tuner != 0)
+ return -EINVAL;
+ cx18_call_i2c_clients(cx, cmd, arg);
+ break;
+ }
+
+ case VIDIOC_S_FREQUENCY:{
+ struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
+
+ if (vf.tuner != 0)
+ return -EINVAL;
+
+ cx18_mute(cx);
+ CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
+ cx18_call_i2c_clients(cx, cmd, &vf);
+ cx18_unmute(cx);
+ break;
+ }
+
+ case VIDIOC_ENUMSTD:{
+ struct v4l2_standard *vs = arg;
+ int idx = vs->index;
+
+ if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
+ return -EINVAL;
+
+ *vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
+ cx18_std_60hz : cx18_std_50hz;
+ vs->index = idx;
+ vs->id = enum_stds[idx].std;
+ strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
+ break;
+ }
+
+ case VIDIOC_G_STD:{
+ *(v4l2_std_id *) arg = cx->std;
+ break;
+ }
+
+ case VIDIOC_S_STD: {
+ v4l2_std_id std = *(v4l2_std_id *) arg;
+
+ if ((std & V4L2_STD_ALL) == 0)
+ return -EINVAL;
+
+ if (std == cx->std)
+ break;
+
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
+ atomic_read(&cx->capturing) > 0) {
+ /* Switching standard would turn off the radio or mess
+ with already running streams, prevent that by
+ returning EBUSY. */
+ return -EBUSY;
+ }
+
+ cx->std = std;
+ cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
+ cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
+ cx->params.width = 720;
+ cx->params.height = cx->is_50hz ? 576 : 480;
+ cx->vbi.count = cx->is_50hz ? 18 : 12;
+ cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
+ cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
+ cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
+ CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std);
+
+ /* Tuner */
+ cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
+ break;
+ }
+
+ case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */
+ struct v4l2_tuner *vt = arg;
+
+ if (vt->index != 0)
+ return -EINVAL;
+
+ cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
+ break;
+ }
+
+ case VIDIOC_G_TUNER: {
+ struct v4l2_tuner *vt = arg;
+
+ if (vt->index != 0)
+ return -EINVAL;
+
+ memset(vt, 0, sizeof(*vt));
+ cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
+
+ if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
+ strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_RADIO;
+ } else {
+ strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
+ vt->type = V4L2_TUNER_ANALOG_TV;
+ }
+ break;
+ }
+
+ case VIDIOC_G_SLICED_VBI_CAP: {
+ struct v4l2_sliced_vbi_cap *cap = arg;
+ int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
+ int f, l;
+ enum v4l2_buf_type type = cap->type;
+
+ memset(cap, 0, sizeof(*cap));
+ cap->type = type;
+ if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
+ for (f = 0; f < 2; f++) {
+ for (l = 0; l < 24; l++) {
+ if (valid_service_line(f, l, cx->is_50hz))
+ cap->service_lines[f][l] = set;
+ }
+ }
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENCODER_CMD:
+ case VIDIOC_TRY_ENCODER_CMD: {
+ struct v4l2_encoder_cmd *enc = arg;
+ int try = cmd == VIDIOC_TRY_ENCODER_CMD;
+
+ memset(&enc->raw, 0, sizeof(enc->raw));
+ switch (enc->cmd) {
+ case V4L2_ENC_CMD_START:
+ enc->flags = 0;
+ if (try)
+ return 0;
+ return cx18_start_capture(id);
+
+ case V4L2_ENC_CMD_STOP:
+ enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
+ if (try)
+ return 0;
+ cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
+ return 0;
+
+ case V4L2_ENC_CMD_PAUSE:
+ enc->flags = 0;
+ if (try)
+ return 0;
+ if (!atomic_read(&cx->capturing))
+ return -EPERM;
+ if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ return 0;
+ cx18_mute(cx);
+ cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
+ break;
+
+ case V4L2_ENC_CMD_RESUME:
+ enc->flags = 0;
+ if (try)
+ return 0;
+ if (!atomic_read(&cx->capturing))
+ return -EPERM;
+ if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
+ return 0;
+ cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
+ cx18_unmute(cx);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ {
+ struct v4l2_input vidin;
+ struct v4l2_audio audin;
+ int i;
+
+ CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num);
+ if (cx->hw_flags & CX18_HW_TVEEPROM) {
+ struct tveeprom tv;
+
+ cx18_read_eeprom(cx, &tv);
+ }
+ cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
+ cx18_get_input(cx, cx->active_input, &vidin);
+ cx18_get_audio_input(cx, cx->audio_input, &audin);
+ CX18_INFO("Video Input: %s\n", vidin.name);
+ CX18_INFO("Audio Input: %s\n", audin.name);
+ CX18_INFO("Tuner: %s\n",
+ test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?
+ "Radio" : "TV");
+ cx2341x_log_status(&cx->params, cx->name);
+ CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev == NULL || s->buffers == 0)
+ continue;
+ CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
+ s->name, s->s_flags,
+ (s->buffers - s->q_free.buffers) * 100 / s->buffers,
+ (s->buffers * s->buf_size) / 1024, s->buffers);
+ }
+ CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
+ (long long)cx->mpg_data_received,
+ (long long)cx->vbi_data_inserted);
+ CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, void *arg)
+{
+ struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18 *cx = id->cx;
+ int ret;
+
+ /* check priority */
+ switch (cmd) {
+ case VIDIOC_S_CTRL:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_S_FMT:
+ case VIDIOC_S_CROP:
+ case VIDIOC_S_EXT_CTRLS:
+ ret = v4l2_prio_check(&cx->prio, &id->prio);
+ if (ret)
+ return ret;
+ }
+
+ switch (cmd) {
+ case VIDIOC_DBG_G_REGISTER:
+ case VIDIOC_DBG_S_REGISTER:
+ case VIDIOC_G_CHIP_IDENT:
+ case VIDIOC_INT_S_AUDIO_ROUTING:
+ case VIDIOC_INT_RESET:
+ if (cx18_debug & CX18_DBGFLG_IOCTL) {
+ printk(KERN_INFO "cx18%d ioctl: ", cx->num);
+ v4l_printk_ioctl(cmd);
+ }
+ return cx18_debug_ioctls(filp, cmd, arg);
+
+ case VIDIOC_G_PRIORITY:
+ case VIDIOC_S_PRIORITY:
+ case VIDIOC_QUERYCAP:
+ case VIDIOC_ENUMINPUT:
+ case VIDIOC_G_INPUT:
+ case VIDIOC_S_INPUT:
+ case VIDIOC_G_FMT:
+ case VIDIOC_S_FMT:
+ case VIDIOC_TRY_FMT:
+ case VIDIOC_ENUM_FMT:
+ case VIDIOC_CROPCAP:
+ case VIDIOC_G_CROP:
+ case VIDIOC_S_CROP:
+ case VIDIOC_G_FREQUENCY:
+ case VIDIOC_S_FREQUENCY:
+ case VIDIOC_ENUMSTD:
+ case VIDIOC_G_STD:
+ case VIDIOC_S_STD:
+ case VIDIOC_S_TUNER:
+ case VIDIOC_G_TUNER:
+ case VIDIOC_ENUMAUDIO:
+ case VIDIOC_S_AUDIO:
+ case VIDIOC_G_AUDIO:
+ case VIDIOC_G_SLICED_VBI_CAP:
+ case VIDIOC_LOG_STATUS:
+ case VIDIOC_G_ENC_INDEX:
+ case VIDIOC_ENCODER_CMD:
+ case VIDIOC_TRY_ENCODER_CMD:
+ if (cx18_debug & CX18_DBGFLG_IOCTL) {
+ printk(KERN_INFO "cx18%d ioctl: ", cx->num);
+ v4l_printk_ioctl(cmd);
+ }
+ return cx18_v4l2_ioctls(cx, filp, cmd, arg);
+
+ case VIDIOC_QUERYMENU:
+ case VIDIOC_QUERYCTRL:
+ case VIDIOC_S_CTRL:
+ case VIDIOC_G_CTRL:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ if (cx18_debug & CX18_DBGFLG_IOCTL) {
+ printk(KERN_INFO "cx18%d ioctl: ", cx->num);
+ v4l_printk_ioctl(cmd);
+ }
+ return cx18_control_ioctls(cx, cmd, arg);
+
+ case 0x00005401: /* Handle isatty() calls */
+ return -EINVAL;
+ default:
+ return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
+ cx18_v4l2_do_ioctl);
+ }
+ return 0;
+}
+
+int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
+ struct cx18 *cx = id->cx;
+ int res;
+
+ mutex_lock(&cx->serialize_lock);
+ res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl);
+ mutex_unlock(&cx->serialize_lock);
+ return res;
+}
diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h
new file mode 100644
index 0000000..9f4c7eb
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-ioctl.h
@@ -0,0 +1,30 @@
+/*
+ * cx18 ioctl system call
+ *
+ * Derived from ivtv-ioctl.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+u16 cx18_service2vbi(int type);
+void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
+u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt);
+int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd,
+ void *arg);
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
new file mode 100644
index 0000000..6e14f8b
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -0,0 +1,179 @@
+/*
+ * cx18 interrupt handling
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-firmware.h"
+#include "cx18-fileops.h"
+#include "cx18-queue.h"
+#include "cx18-irq.h"
+#include "cx18-ioctl.h"
+#include "cx18-mailbox.h"
+#include "cx18-vbi.h"
+#include "cx18-scb.h"
+
+#define DMA_MAGIC_COOKIE 0x000001fe
+
+static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
+{
+ u32 handle = mb->args[0];
+ struct cx18_stream *s = NULL;
+ struct cx18_buffer *buf;
+ u32 off;
+ int i;
+ int id;
+
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ s = &cx->streams[i];
+ if ((handle == s->handle) && (s->dvb.enabled))
+ break;
+ if (s->v4l2dev && handle == s->handle)
+ break;
+ }
+ if (i == CX18_MAX_STREAMS) {
+ CX18_WARN("DMA done for unknown handle %d for stream %s\n",
+ handle, s->name);
+ mb->error = CXERR_NOT_OPEN;
+ mb->cmd = 0;
+ cx18_mb_ack(cx, mb);
+ return;
+ }
+
+ off = mb->args[1];
+ if (mb->args[2] != 1)
+ CX18_WARN("Ack struct = %d for %s\n",
+ mb->args[2], s->name);
+ id = read_enc(off);
+ buf = cx18_queue_find_buf(s, id, read_enc(off + 4));
+ CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
+ if (buf) {
+ cx18_buf_sync_for_cpu(s, buf);
+ if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
+ /* process the buffer here */
+ CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n",
+ buf->bytesused);
+
+ dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
+ buf->bytesused);
+
+ cx18_buf_sync_for_device(s, buf);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+ (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
+ 1, buf->id, s->buf_size);
+ } else
+ set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
+ } else {
+ CX18_WARN("Could not find buf %d for stream %s\n",
+ read_enc(off), s->name);
+ }
+ mb->error = 0;
+ mb->cmd = 0;
+ cx18_mb_ack(cx, mb);
+ wake_up(&cx->dma_waitq);
+ if (s->id != -1)
+ wake_up(&s->waitq);
+}
+
+static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb)
+{
+ char str[256] = { 0 };
+ char *p;
+
+ if (mb->args[1]) {
+ setup_page(mb->args[1]);
+ memcpy_fromio(str, cx->enc_mem + mb->args[1], 252);
+ str[252] = 0;
+ }
+ cx18_mb_ack(cx, mb);
+ CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
+ p = strchr(str, '.');
+ if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
+ CX18_INFO("FW version: %s\n", p - 1);
+}
+
+static void hpu_cmd(struct cx18 *cx, u32 sw1)
+{
+ struct cx18_mailbox mb;
+
+ if (sw1 & IRQ_CPU_TO_EPU) {
+ memcpy_fromio(&mb, &cx->scb->cpu2epu_mb, sizeof(mb));
+ mb.error = 0;
+
+ switch (mb.cmd) {
+ case CX18_EPU_DMA_DONE:
+ epu_dma_done(cx, &mb);
+ break;
+ case CX18_EPU_DEBUG:
+ epu_debug(cx, &mb);
+ break;
+ default:
+ CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd);
+ break;
+ }
+ }
+ if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU))
+ CX18_WARN("Unexpected interrupt %08x\n", sw1);
+}
+
+irqreturn_t cx18_irq_handler(int irq, void *dev_id)
+{
+ struct cx18 *cx = (struct cx18 *)dev_id;
+ u32 sw1, sw1_mask;
+ u32 sw2, sw2_mask;
+ u32 hw2, hw2_mask;
+
+ spin_lock(&cx->dma_reg_lock);
+
+ hw2_mask = read_reg(HW2_INT_MASK5_PCI);
+ hw2 = read_reg(HW2_INT_CLR_STATUS) & hw2_mask;
+ sw2_mask = read_reg(SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
+ sw2 = read_reg(SW2_INT_STATUS) & sw2_mask;
+ sw1_mask = read_reg(SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
+ sw1 = read_reg(SW1_INT_STATUS) & sw1_mask;
+
+ write_reg(sw2&sw2_mask, SW2_INT_STATUS);
+ write_reg(sw1&sw1_mask, SW1_INT_STATUS);
+ write_reg(hw2&hw2_mask, HW2_INT_CLR_STATUS);
+
+ if (sw1 || sw2 || hw2)
+ CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2);
+
+ /* To do: interrupt-based I2C handling
+ if (hw2 & 0x00c00000) {
+ }
+ */
+
+ if (sw2) {
+ if (sw2 & (cx->scb->cpu2hpu_irq_ack | cx->scb->cpu2epu_irq_ack))
+ wake_up(&cx->mb_cpu_waitq);
+ if (sw2 & (cx->scb->apu2hpu_irq_ack | cx->scb->apu2epu_irq_ack))
+ wake_up(&cx->mb_apu_waitq);
+ if (sw2 & cx->scb->epu2hpu_irq_ack)
+ wake_up(&cx->mb_epu_waitq);
+ if (sw2 & cx->scb->hpu2epu_irq_ack)
+ wake_up(&cx->mb_hpu_waitq);
+ }
+
+ if (sw1)
+ hpu_cmd(cx, sw1);
+ spin_unlock(&cx->dma_reg_lock);
+
+ return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE;
+}
diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h
new file mode 100644
index 0000000..379f704
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-irq.h
@@ -0,0 +1,37 @@
+/*
+ * cx18 interrupt handling
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#define HW2_I2C1_INT (1 << 22)
+#define HW2_I2C2_INT (1 << 23)
+#define HW2_INT_CLR_STATUS 0xc730c4
+#define HW2_INT_MASK5_PCI 0xc730e4
+#define SW1_INT_SET 0xc73100
+#define SW1_INT_STATUS 0xc73104
+#define SW1_INT_ENABLE_PCI 0xc7311c
+#define SW2_INT_SET 0xc73140
+#define SW2_INT_STATUS 0xc73144
+#define SW2_INT_ENABLE_PCI 0xc7315c
+
+irqreturn_t cx18_irq_handler(int irq, void *dev_id);
+
+void cx18_irq_work_handler(struct work_struct *work);
+void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock);
+void cx18_unfinished_dma(unsigned long arg);
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
new file mode 100644
index 0000000..0c5f328
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -0,0 +1,372 @@
+/*
+ * cx18 mailbox functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include <stdarg.h>
+
+#include "cx18-driver.h"
+#include "cx18-scb.h"
+#include "cx18-irq.h"
+#include "cx18-mailbox.h"
+
+#define API_FAST (1 << 2) /* Short timeout */
+#define API_SLOW (1 << 3) /* Additional 300ms timeout */
+
+#define APU 0
+#define CPU 1
+#define EPU 2
+#define HPU 3
+
+struct cx18_api_info {
+ u32 cmd;
+ u8 flags; /* Flags, see above */
+ u8 rpu; /* Processing unit */
+ const char *name; /* The name of the command */
+};
+
+#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x }
+
+static const struct cx18_api_info api_info[] = {
+ /* MPEG encoder API */
+ API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
+ API_ENTRY(CPU, CX18_EPU_DEBUG, 0),
+ API_ENTRY(CPU, CX18_CREATE_TASK, 0),
+ API_ENTRY(CPU, CX18_DESTROY_TASK, 0),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0),
+ API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW),
+ API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0),
+ API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0),
+ API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
+ API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
+ API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
+ API_ENTRY(0, 0, 0),
+};
+
+static const struct cx18_api_info *find_api_info(u32 cmd)
+{
+ int i;
+
+ for (i = 0; api_info[i].cmd; i++)
+ if (api_info[i].cmd == cmd)
+ return &api_info[i];
+ return NULL;
+}
+
+static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu,
+ u32 *state, u32 *irq, u32 *req)
+{
+ struct cx18_mailbox *mb = NULL;
+ int wait_count = 0;
+ u32 ack;
+
+ switch (rpu) {
+ case APU:
+ mb = &cx->scb->epu2apu_mb;
+ *state = readl(&cx->scb->apu_state);
+ *irq = readl(&cx->scb->epu2apu_irq);
+ break;
+
+ case CPU:
+ mb = &cx->scb->epu2cpu_mb;
+ *state = readl(&cx->scb->cpu_state);
+ *irq = readl(&cx->scb->epu2cpu_irq);
+ break;
+
+ case HPU:
+ mb = &cx->scb->epu2hpu_mb;
+ *state = readl(&cx->scb->hpu_state);
+ *irq = readl(&cx->scb->epu2hpu_irq);
+ break;
+ }
+
+ if (mb == NULL)
+ return mb;
+
+ do {
+ *req = readl(&mb->request);
+ ack = readl(&mb->ack);
+ wait_count++;
+ } while (*req != ack && wait_count < 600);
+
+ if (*req == ack) {
+ (*req)++;
+ if (*req == 0 || *req == 0xffffffff)
+ *req = 1;
+ return mb;
+ }
+ return NULL;
+}
+
+long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
+{
+ const struct cx18_api_info *info = find_api_info(mb->cmd);
+ struct cx18_mailbox *ack_mb;
+ u32 ack_irq;
+ u8 rpu = CPU;
+
+ if (info == NULL && mb->cmd) {
+ CX18_WARN("Cannot ack unknown command %x\n", mb->cmd);
+ return -EINVAL;
+ }
+ if (info)
+ rpu = info->rpu;
+
+ switch (rpu) {
+ case HPU:
+ ack_irq = IRQ_EPU_TO_HPU_ACK;
+ ack_mb = &cx->scb->hpu2epu_mb;
+ break;
+ case APU:
+ ack_irq = IRQ_EPU_TO_APU_ACK;
+ ack_mb = &cx->scb->apu2epu_mb;
+ break;
+ case CPU:
+ ack_irq = IRQ_EPU_TO_CPU_ACK;
+ ack_mb = &cx->scb->cpu2epu_mb;
+ break;
+ default:
+ CX18_WARN("Unknown RPU for command %x\n", mb->cmd);
+ return -EINVAL;
+ }
+
+ setup_page(SCB_OFFSET);
+ write_sync(mb->request, &ack_mb->ack);
+ write_reg(ack_irq, SW2_INT_SET);
+ return 0;
+}
+
+
+static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
+{
+ const struct cx18_api_info *info = find_api_info(cmd);
+ u32 state = 0, irq = 0, req, oldreq, err;
+ struct cx18_mailbox *mb;
+ wait_queue_head_t *waitq;
+ int timeout = 100;
+ int cnt = 0;
+ int sig = 0;
+ int i;
+
+ if (info == NULL) {
+ CX18_WARN("unknown cmd %x\n", cmd);
+ return -EINVAL;
+ }
+
+ if (cmd == CX18_CPU_DE_SET_MDL)
+ CX18_DEBUG_HI_API("%s\n", info->name);
+ else
+ CX18_DEBUG_API("%s\n", info->name);
+ setup_page(SCB_OFFSET);
+ mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
+
+ if (mb == NULL) {
+ CX18_ERR("mb %s busy\n", info->name);
+ return -EBUSY;
+ }
+
+ oldreq = req - 1;
+ writel(cmd, &mb->cmd);
+ for (i = 0; i < args; i++)
+ writel(data[i], &mb->args[i]);
+ writel(0, &mb->error);
+ writel(req, &mb->request);
+
+ switch (info->rpu) {
+ case APU: waitq = &cx->mb_apu_waitq; break;
+ case CPU: waitq = &cx->mb_cpu_waitq; break;
+ case EPU: waitq = &cx->mb_epu_waitq; break;
+ case HPU: waitq = &cx->mb_hpu_waitq; break;
+ default: return -EINVAL;
+ }
+ if (info->flags & API_FAST)
+ timeout /= 2;
+ write_reg(irq, SW1_INT_SET);
+
+ while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) {
+ if (cnt > 200 && !in_atomic())
+ sig = cx18_msleep_timeout(10, 1);
+ cnt++;
+ }
+ if (sig)
+ return -EINTR;
+ if (cnt == 660) {
+ writel(oldreq, &mb->request);
+ CX18_ERR("mb %s failed\n", info->name);
+ return -EINVAL;
+ }
+ for (i = 0; i < MAX_MB_ARGUMENTS; i++)
+ data[i] = readl(&mb->args[i]);
+ err = readl(&mb->error);
+ if (!in_atomic() && (info->flags & API_SLOW))
+ cx18_msleep_timeout(300, 0);
+ if (err)
+ CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
+ info->name);
+ return err ? -EIO : 0;
+}
+
+int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
+{
+ int res = cx18_api_call(cx, cmd, args, data);
+
+ /* Allow a single retry, probably already too late though.
+ If there is no free mailbox then that is usually an indication
+ of a more serious problem. */
+ return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res;
+}
+
+static int cx18_set_filter_param(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ u32 mode;
+ int ret;
+
+ mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0);
+ ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+ s->handle, 1, mode, cx->spatial_strength);
+ mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0);
+ ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+ s->handle, 0, mode, cx->temporal_strength);
+ ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
+ s->handle, 2, cx->filter_mode >> 2, 0);
+ return ret;
+}
+
+int cx18_api_func(void *priv, u32 cmd, int in, int out,
+ u32 data[CX2341X_MBOX_MAX_DATA])
+{
+ struct cx18 *cx = priv;
+ struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+
+ switch (cmd) {
+ case CX2341X_ENC_SET_OUTPUT_PORT:
+ return 0;
+ case CX2341X_ENC_SET_FRAME_RATE:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6,
+ s->handle, 0, 0, 0, 0, data[0]);
+ case CX2341X_ENC_SET_FRAME_SIZE:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3,
+ s->handle, data[1], data[0]);
+ case CX2341X_ENC_SET_STREAM_TYPE:
+ return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_SET_ASPECT_RATIO:
+ return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2,
+ s->handle, data[0]);
+
+ case CX2341X_ENC_SET_GOP_PROPERTIES:
+ return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3,
+ s->handle, data[0], data[1]);
+ case CX2341X_ENC_SET_GOP_CLOSURE:
+ return 0;
+ case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+ return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_MUTE_AUDIO:
+ return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_SET_BIT_RATE:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5,
+ s->handle, data[0], data[1], data[2], data[3]);
+ case CX2341X_ENC_MUTE_VIDEO:
+ return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_SET_FRAME_DROP_RATE:
+ return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2,
+ s->handle, data[0]);
+ case CX2341X_ENC_MISC:
+ return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4,
+ s->handle, data[0], data[1], data[2]);
+ case CX2341X_ENC_SET_DNR_FILTER_MODE:
+ cx->filter_mode = (data[0] & 3) | (data[1] << 2);
+ return cx18_set_filter_param(s);
+ case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+ cx->spatial_strength = data[0];
+ cx->temporal_strength = data[1];
+ return cx18_set_filter_param(s);
+ case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+ return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3,
+ s->handle, data[0], data[1]);
+ case CX2341X_ENC_SET_CORING_LEVELS:
+ return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5,
+ s->handle, data[0], data[1], data[2], data[3]);
+ }
+ CX18_WARN("Unknown cmd %x\n", cmd);
+ return 0;
+}
+
+int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS],
+ u32 cmd, int args, ...)
+{
+ va_list ap;
+ int i;
+
+ va_start(ap, args);
+ for (i = 0; i < args; i++)
+ data[i] = va_arg(ap, u32);
+ va_end(ap);
+ return cx18_api(cx, cmd, args, data);
+}
+
+int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...)
+{
+ u32 data[MAX_MB_ARGUMENTS];
+ va_list ap;
+ int i;
+
+ if (cx == NULL) {
+ CX18_ERR("cx == NULL (cmd=%x)\n", cmd);
+ return 0;
+ }
+ if (args > MAX_MB_ARGUMENTS) {
+ CX18_ERR("args too big (cmd=%x)\n", cmd);
+ args = MAX_MB_ARGUMENTS;
+ }
+ va_start(ap, args);
+ for (i = 0; i < args; i++)
+ data[i] = va_arg(ap, u32);
+ va_end(ap);
+ return cx18_api(cx, cmd, args, data);
+}
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h
new file mode 100644
index 0000000..d995641
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-mailbox.h
@@ -0,0 +1,73 @@
+/*
+ * cx18 mailbox functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef _CX18_MAILBOX_H_
+#define _CX18_MAILBOX_H_
+
+/* mailbox max args */
+#define MAX_MB_ARGUMENTS 6
+/* compatibility, should be same as the define in cx2341x.h */
+#define CX2341X_MBOX_MAX_DATA 16
+
+#define MB_RESERVED_HANDLE_0 0
+#define MB_RESERVED_HANDLE_1 0xFFFFFFFF
+
+struct cx18;
+
+/* The cx18_mailbox struct is the mailbox structure which is used for passing
+ messages between processors */
+struct cx18_mailbox {
+ /* The sender sets a handle in 'request' after he fills the command. The
+ 'request' should be different than 'ack'. The sender, also, generates
+ an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the
+ receiver. */
+ u32 request;
+ /* The receiver detects a new command when 'req' is different than 'ack'.
+ He sets 'ack' to the same value as 'req' to clear the command. He, also,
+ generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU
+ is the receiver. */
+ u32 ack;
+ u32 reserved[6];
+ /* 'cmd' identifies the command. The list of these commands are in
+ cx23418.h */
+ u32 cmd;
+ /* Each command can have up to 6 arguments */
+ u32 args[MAX_MB_ARGUMENTS];
+ /* The return code can be one of the codes in the file cx23418.h. If the
+ command is completed successfuly, the error will be ERR_SYS_SUCCESS.
+ If it is pending, the code is ERR_SYS_PENDING. If it failed, the error
+ code would indicate the task from which the error originated and will
+ be one of the errors in cx23418.h. In that case, the following
+ applies ((error & 0xff) != 0).
+ If the command is pending, the return will be passed in a MB from the
+ receiver to the sender. 'req' will be returned in args[0] */
+ u32 error;
+};
+
+int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
+int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
+ int args, ...);
+int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...);
+int cx18_api_func(void *priv, u32 cmd, int in, int out,
+ u32 data[CX2341X_MBOX_MAX_DATA]);
+long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb);
+
+#endif
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
new file mode 100644
index 0000000..65af1bb
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -0,0 +1,282 @@
+/*
+ * cx18 buffer queues
+ *
+ * Derived from ivtv-queue.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-streams.h"
+#include "cx18-queue.h"
+#include "cx18-scb.h"
+
+int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf,
+ const char __user *src, int copybytes)
+{
+ if (s->buf_size - buf->bytesused < copybytes)
+ copybytes = s->buf_size - buf->bytesused;
+ if (copy_from_user(buf->buf + buf->bytesused, src, copybytes))
+ return -EFAULT;
+ buf->bytesused += copybytes;
+ return copybytes;
+}
+
+void cx18_buf_swap(struct cx18_buffer *buf)
+{
+ int i;
+
+ for (i = 0; i < buf->bytesused; i += 4)
+ swab32s((u32 *)(buf->buf + i));
+}
+
+void cx18_queue_init(struct cx18_queue *q)
+{
+ INIT_LIST_HEAD(&q->list);
+ q->buffers = 0;
+ q->length = 0;
+ q->bytesused = 0;
+}
+
+void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q)
+{
+ unsigned long flags = 0;
+
+ /* clear the buffer if it is going to be enqueued to the free queue */
+ if (q == &s->q_free) {
+ buf->bytesused = 0;
+ buf->readpos = 0;
+ buf->b_flags = 0;
+ }
+ spin_lock_irqsave(&s->qlock, flags);
+ list_add_tail(&buf->list, &q->list);
+ q->buffers++;
+ q->length += s->buf_size;
+ q->bytesused += buf->bytesused - buf->readpos;
+ spin_unlock_irqrestore(&s->qlock, flags);
+}
+
+struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
+{
+ struct cx18_buffer *buf = NULL;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&s->qlock, flags);
+ if (!list_empty(&q->list)) {
+ buf = list_entry(q->list.next, struct cx18_buffer, list);
+ list_del_init(q->list.next);
+ q->buffers--;
+ q->length -= s->buf_size;
+ q->bytesused -= buf->bytesused - buf->readpos;
+ }
+ spin_unlock_irqrestore(&s->qlock, flags);
+ return buf;
+}
+
+struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+ u32 bytesused)
+{
+ struct cx18 *cx = s->cx;
+ struct list_head *p;
+
+ list_for_each(p, &s->q_free.list) {
+ struct cx18_buffer *buf =
+ list_entry(p, struct cx18_buffer, list);
+
+ if (buf->id != id)
+ continue;
+ buf->bytesused = bytesused;
+ /* the transport buffers are handled differently,
+ so there is no need to move them to the full queue */
+ if (s->type == CX18_ENC_STREAM_TYPE_TS)
+ return buf;
+ s->q_free.buffers--;
+ s->q_free.length -= s->buf_size;
+ s->q_full.buffers++;
+ s->q_full.length += s->buf_size;
+ s->q_full.bytesused += buf->bytesused;
+ list_move_tail(&buf->list, &s->q_full.list);
+ return buf;
+ }
+ CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name);
+ return NULL;
+}
+
+static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from,
+ struct cx18_queue *to, int clear, int full)
+{
+ struct cx18_buffer *buf =
+ list_entry(from->list.next, struct cx18_buffer, list);
+
+ list_move_tail(from->list.next, &to->list);
+ from->buffers--;
+ from->length -= s->buf_size;
+ from->bytesused -= buf->bytesused - buf->readpos;
+ /* special handling for q_free */
+ if (clear)
+ buf->bytesused = buf->readpos = buf->b_flags = 0;
+ else if (full) {
+ /* special handling for stolen buffers, assume
+ all bytes are used. */
+ buf->bytesused = s->buf_size;
+ buf->readpos = buf->b_flags = 0;
+ }
+ to->buffers++;
+ to->length += s->buf_size;
+ to->bytesused += buf->bytesused - buf->readpos;
+}
+
+/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
+ If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
+ If 'steal' != NULL, then buffers may also taken from that queue if
+ needed.
+
+ The buffer is automatically cleared if it goes to the free queue. It is
+ also cleared if buffers need to be taken from the 'steal' queue and
+ the 'from' queue is the free queue.
+
+ When 'from' is q_free, then needed_bytes is compared to the total
+ available buffer length, otherwise needed_bytes is compared to the
+ bytesused value. For the 'steal' queue the total available buffer
+ length is always used.
+
+ -ENOMEM is returned if the buffers could not be obtained, 0 if all
+ buffers where obtained from the 'from' list and if non-zero then
+ the number of stolen buffers is returned. */
+int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
+ struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes)
+{
+ unsigned long flags;
+ int rc = 0;
+ int from_free = from == &s->q_free;
+ int to_free = to == &s->q_free;
+ int bytes_available;
+
+ spin_lock_irqsave(&s->qlock, flags);
+ if (needed_bytes == 0) {
+ from_free = 1;
+ needed_bytes = from->length;
+ }
+
+ bytes_available = from_free ? from->length : from->bytesused;
+ bytes_available += steal ? steal->length : 0;
+
+ if (bytes_available < needed_bytes) {
+ spin_unlock_irqrestore(&s->qlock, flags);
+ return -ENOMEM;
+ }
+ if (from_free) {
+ u32 old_length = to->length;
+
+ while (to->length - old_length < needed_bytes) {
+ if (list_empty(&from->list))
+ from = steal;
+ if (from == steal)
+ rc++; /* keep track of 'stolen' buffers */
+ cx18_queue_move_buf(s, from, to, 1, 0);
+ }
+ } else {
+ u32 old_bytesused = to->bytesused;
+
+ while (to->bytesused - old_bytesused < needed_bytes) {
+ if (list_empty(&from->list))
+ from = steal;
+ if (from == steal)
+ rc++; /* keep track of 'stolen' buffers */
+ cx18_queue_move_buf(s, from, to, to_free, rc);
+ }
+ }
+ spin_unlock_irqrestore(&s->qlock, flags);
+ return rc;
+}
+
+void cx18_flush_queues(struct cx18_stream *s)
+{
+ cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
+ cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
+}
+
+int cx18_stream_alloc(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ int i;
+
+ if (s->buffers == 0)
+ return 0;
+
+ CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n",
+ s->name, s->buffers, s->buf_size,
+ s->buffers * s->buf_size / 1024);
+
+ if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
+ (char *)cx->scb) > SCB_RESERVED_SIZE) {
+ unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE -
+ ((char *)cx->scb->cpu_mdl));
+
+ CX18_ERR("Too many buffers, cannot fit in SCB area\n");
+ CX18_ERR("Max buffers = %zd\n",
+ bufsz / sizeof(struct cx18_mdl));
+ return -ENOMEM;
+ }
+
+ s->mdl_offset = cx->mdl_offset;
+
+ /* allocate stream buffers. Initially all buffers are in q_free. */
+ for (i = 0; i < s->buffers; i++) {
+ struct cx18_buffer *buf =
+ kzalloc(sizeof(struct cx18_buffer), GFP_KERNEL);
+
+ if (buf == NULL)
+ break;
+ buf->buf = kmalloc(s->buf_size, GFP_KERNEL);
+ if (buf->buf == NULL) {
+ kfree(buf);
+ break;
+ }
+ buf->id = cx->buffer_id++;
+ INIT_LIST_HEAD(&buf->list);
+ buf->dma_handle = pci_map_single(s->cx->dev,
+ buf->buf, s->buf_size, s->dma);
+ cx18_buf_sync_for_cpu(s, buf);
+ cx18_enqueue(s, buf, &s->q_free);
+ }
+ if (i == s->buffers) {
+ cx->mdl_offset += s->buffers;
+ return 0;
+ }
+ CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name);
+ cx18_stream_free(s);
+ return -ENOMEM;
+}
+
+void cx18_stream_free(struct cx18_stream *s)
+{
+ struct cx18_buffer *buf;
+
+ /* move all buffers to q_free */
+ cx18_flush_queues(s);
+
+ /* empty q_free */
+ while ((buf = cx18_dequeue(s, &s->q_free))) {
+ pci_unmap_single(s->cx->dev, buf->dma_handle,
+ s->buf_size, s->dma);
+ kfree(buf->buf);
+ kfree(buf);
+ }
+}
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
new file mode 100644
index 0000000..f86c8a6
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -0,0 +1,59 @@
+/*
+ * cx18 buffer queues
+ *
+ * Derived from ivtv-queue.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#define CX18_DMA_UNMAPPED ((u32) -1)
+
+/* cx18_buffer utility functions */
+
+static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+{
+ pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle,
+ s->buf_size, s->dma);
+}
+
+static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
+ struct cx18_buffer *buf)
+{
+ pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle,
+ s->buf_size, s->dma);
+}
+
+int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf,
+ const char __user *src, int copybytes);
+void cx18_buf_swap(struct cx18_buffer *buf);
+
+/* cx18_queue utility functions */
+void cx18_queue_init(struct cx18_queue *q);
+void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
+ struct cx18_queue *q);
+struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
+int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
+ struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes);
+struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
+ u32 bytesused);
+void cx18_flush_queues(struct cx18_stream *s);
+
+/* cx18_stream utility functions */
+int cx18_stream_alloc(struct cx18_stream *s);
+void cx18_stream_free(struct cx18_stream *s);
diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c
new file mode 100644
index 0000000..30bc803
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-scb.c
@@ -0,0 +1,121 @@
+/*
+ * cx18 System Control Block initialization
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-scb.h"
+
+void cx18_init_scb(struct cx18 *cx)
+{
+ setup_page(SCB_OFFSET);
+ memset_io(cx->scb, 0, 0x10000);
+
+ writel(IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq);
+ writel(IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack);
+ writel(IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq);
+ writel(IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack);
+ writel(IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq);
+ writel(IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack);
+ writel(IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq);
+ writel(IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq);
+ writel(IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack);
+ writel(IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq);
+ writel(IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack);
+ writel(IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq);
+ writel(IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack);
+ writel(IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq);
+ writel(IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq);
+ writel(IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack);
+ writel(IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq);
+ writel(IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack);
+ writel(IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq);
+ writel(IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack);
+ writel(IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq);
+ writel(IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq);
+ writel(IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack);
+ writel(IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq);
+ writel(IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack);
+ writel(IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq);
+ writel(IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack);
+ writel(IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq);
+ writel(IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack);
+
+ writel(IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq);
+ writel(IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack);
+ writel(IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq);
+ writel(IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack);
+ writel(IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq);
+ writel(IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack);
+ writel(IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq);
+ writel(IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack);
+
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb),
+ &cx->scb->apu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb),
+ &cx->scb->hpu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb),
+ &cx->scb->ppu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb),
+ &cx->scb->epu2cpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb),
+ &cx->scb->cpu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb),
+ &cx->scb->hpu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb),
+ &cx->scb->ppu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb),
+ &cx->scb->epu2apu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb),
+ &cx->scb->cpu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb),
+ &cx->scb->apu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb),
+ &cx->scb->ppu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb),
+ &cx->scb->epu2hpu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb),
+ &cx->scb->cpu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb),
+ &cx->scb->apu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb),
+ &cx->scb->hpu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb),
+ &cx->scb->epu2ppu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb),
+ &cx->scb->cpu2epu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb),
+ &cx->scb->apu2epu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb),
+ &cx->scb->hpu2epu_mb_offset);
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb),
+ &cx->scb->ppu2epu_mb_offset);
+
+ writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
+ &cx->scb->ipc_offset);
+
+ writel(1, &cx->scb->hpu_state);
+ writel(1, &cx->scb->epu_state);
+}
diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h
new file mode 100644
index 0000000..86b4cb1
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-scb.h
@@ -0,0 +1,285 @@
+/*
+ * cx18 System Control Block initialization
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef CX18_SCB_H
+#define CX18_SCB_H
+
+#include "cx18-mailbox.h"
+
+/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts
+ are in the SW1 register. */
+
+#define IRQ_APU_TO_CPU 0x00000001
+#define IRQ_CPU_TO_APU_ACK 0x00000001
+#define IRQ_HPU_TO_CPU 0x00000002
+#define IRQ_CPU_TO_HPU_ACK 0x00000002
+#define IRQ_PPU_TO_CPU 0x00000004
+#define IRQ_CPU_TO_PPU_ACK 0x00000004
+#define IRQ_EPU_TO_CPU 0x00000008
+#define IRQ_CPU_TO_EPU_ACK 0x00000008
+
+#define IRQ_CPU_TO_APU 0x00000010
+#define IRQ_APU_TO_CPU_ACK 0x00000010
+#define IRQ_HPU_TO_APU 0x00000020
+#define IRQ_APU_TO_HPU_ACK 0x00000020
+#define IRQ_PPU_TO_APU 0x00000040
+#define IRQ_APU_TO_PPU_ACK 0x00000040
+#define IRQ_EPU_TO_APU 0x00000080
+#define IRQ_APU_TO_EPU_ACK 0x00000080
+
+#define IRQ_CPU_TO_HPU 0x00000100
+#define IRQ_HPU_TO_CPU_ACK 0x00000100
+#define IRQ_APU_TO_HPU 0x00000200
+#define IRQ_HPU_TO_APU_ACK 0x00000200
+#define IRQ_PPU_TO_HPU 0x00000400
+#define IRQ_HPU_TO_PPU_ACK 0x00000400
+#define IRQ_EPU_TO_HPU 0x00000800
+#define IRQ_HPU_TO_EPU_ACK 0x00000800
+
+#define IRQ_CPU_TO_PPU 0x00001000
+#define IRQ_PPU_TO_CPU_ACK 0x00001000
+#define IRQ_APU_TO_PPU 0x00002000
+#define IRQ_PPU_TO_APU_ACK 0x00002000
+#define IRQ_HPU_TO_PPU 0x00004000
+#define IRQ_PPU_TO_HPU_ACK 0x00004000
+#define IRQ_EPU_TO_PPU 0x00008000
+#define IRQ_PPU_TO_EPU_ACK 0x00008000
+
+#define IRQ_CPU_TO_EPU 0x00010000
+#define IRQ_EPU_TO_CPU_ACK 0x00010000
+#define IRQ_APU_TO_EPU 0x00020000
+#define IRQ_EPU_TO_APU_ACK 0x00020000
+#define IRQ_HPU_TO_EPU 0x00040000
+#define IRQ_EPU_TO_HPU_ACK 0x00040000
+#define IRQ_PPU_TO_EPU 0x00080000
+#define IRQ_EPU_TO_PPU_ACK 0x00080000
+
+#define SCB_OFFSET 0xDC0000
+
+/* If Firmware uses fixed memory map, it shall not allocate the area
+ between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */
+#define SCB_RESERVED_SIZE 0x10000
+
+
+/* This structure is used by EPU to provide memory descriptors in its memory */
+struct cx18_mdl {
+ u32 paddr; /* Physical address of a buffer segment */
+ u32 length; /* Length of the buffer segment */
+};
+
+/* This structure is used by CPU to provide completed buffers information */
+struct cx18_mdl_ack {
+ u32 id; /* ID of a completed MDL */
+ u32 data_used; /* Total data filled in the MDL for buffer 'id' */
+};
+
+struct cx18_scb {
+ /* These fields form the System Control Block which is used at boot time
+ for localizing the IPC data as well as the code positions for all
+ processors. The offsets are from the start of this struct. */
+
+ /* Offset where to find the Inter-Processor Communication data */
+ u32 ipc_offset;
+ u32 reserved01[7];
+ /* Offset where to find the start of the CPU code */
+ u32 cpu_code_offset;
+ u32 reserved02[3];
+ /* Offset where to find the start of the APU code */
+ u32 apu_code_offset;
+ u32 reserved03[3];
+ /* Offset where to find the start of the HPU code */
+ u32 hpu_code_offset;
+ u32 reserved04[3];
+ /* Offset where to find the start of the PPU code */
+ u32 ppu_code_offset;
+ u32 reserved05[3];
+
+ /* These fields form Inter-Processor Communication data which is used
+ by all processors to locate the information needed for communicating
+ with other processors */
+
+ /* Fields for CPU: */
+
+ /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */
+ u32 cpu_state;
+ u32 reserved1[7];
+ /* Offset to the mailbox used for sending commands from APU to CPU */
+ u32 apu2cpu_mb_offset;
+ /* Value to write to register SW1 register set (0xC7003100) after the
+ command is ready */
+ u32 apu2cpu_irq;
+ /* Value to write to register SW2 register set (0xC7003140) after the
+ command is cleared */
+ u32 apu2cpu_irq_ack;
+ u32 reserved2[13];
+
+ u32 hpu2cpu_mb_offset;
+ u32 hpu2cpu_irq;
+ u32 hpu2cpu_irq_ack;
+ u32 reserved3[13];
+
+ u32 ppu2cpu_mb_offset;
+ u32 ppu2cpu_irq;
+ u32 ppu2cpu_irq_ack;
+ u32 reserved4[13];
+
+ u32 epu2cpu_mb_offset;
+ u32 epu2cpu_irq;
+ u32 epu2cpu_irq_ack;
+ u32 reserved5[13];
+ u32 reserved6[8];
+
+ /* Fields for APU: */
+
+ u32 apu_state;
+ u32 reserved11[7];
+ u32 cpu2apu_mb_offset;
+ u32 cpu2apu_irq;
+ u32 cpu2apu_irq_ack;
+ u32 reserved12[13];
+
+ u32 hpu2apu_mb_offset;
+ u32 hpu2apu_irq;
+ u32 hpu2apu_irq_ack;
+ u32 reserved13[13];
+
+ u32 ppu2apu_mb_offset;
+ u32 ppu2apu_irq;
+ u32 ppu2apu_irq_ack;
+ u32 reserved14[13];
+
+ u32 epu2apu_mb_offset;
+ u32 epu2apu_irq;
+ u32 epu2apu_irq_ack;
+ u32 reserved15[13];
+ u32 reserved16[8];
+
+ /* Fields for HPU: */
+
+ u32 hpu_state;
+ u32 reserved21[7];
+ u32 cpu2hpu_mb_offset;
+ u32 cpu2hpu_irq;
+ u32 cpu2hpu_irq_ack;
+ u32 reserved22[13];
+
+ u32 apu2hpu_mb_offset;
+ u32 apu2hpu_irq;
+ u32 apu2hpu_irq_ack;
+ u32 reserved23[13];
+
+ u32 ppu2hpu_mb_offset;
+ u32 ppu2hpu_irq;
+ u32 ppu2hpu_irq_ack;
+ u32 reserved24[13];
+
+ u32 epu2hpu_mb_offset;
+ u32 epu2hpu_irq;
+ u32 epu2hpu_irq_ack;
+ u32 reserved25[13];
+ u32 reserved26[8];
+
+ /* Fields for PPU: */
+
+ u32 ppu_state;
+ u32 reserved31[7];
+ u32 cpu2ppu_mb_offset;
+ u32 cpu2ppu_irq;
+ u32 cpu2ppu_irq_ack;
+ u32 reserved32[13];
+
+ u32 apu2ppu_mb_offset;
+ u32 apu2ppu_irq;
+ u32 apu2ppu_irq_ack;
+ u32 reserved33[13];
+
+ u32 hpu2ppu_mb_offset;
+ u32 hpu2ppu_irq;
+ u32 hpu2ppu_irq_ack;
+ u32 reserved34[13];
+
+ u32 epu2ppu_mb_offset;
+ u32 epu2ppu_irq;
+ u32 epu2ppu_irq_ack;
+ u32 reserved35[13];
+ u32 reserved36[8];
+
+ /* Fields for EPU: */
+
+ u32 epu_state;
+ u32 reserved41[7];
+ u32 cpu2epu_mb_offset;
+ u32 cpu2epu_irq;
+ u32 cpu2epu_irq_ack;
+ u32 reserved42[13];
+
+ u32 apu2epu_mb_offset;
+ u32 apu2epu_irq;
+ u32 apu2epu_irq_ack;
+ u32 reserved43[13];
+
+ u32 hpu2epu_mb_offset;
+ u32 hpu2epu_irq;
+ u32 hpu2epu_irq_ack;
+ u32 reserved44[13];
+
+ u32 ppu2epu_mb_offset;
+ u32 ppu2epu_irq;
+ u32 ppu2epu_irq_ack;
+ u32 reserved45[13];
+ u32 reserved46[8];
+
+ u32 semaphores[8]; /* Semaphores */
+
+ u32 reserved50[32]; /* Reserved for future use */
+
+ struct cx18_mailbox apu2cpu_mb;
+ struct cx18_mailbox hpu2cpu_mb;
+ struct cx18_mailbox ppu2cpu_mb;
+ struct cx18_mailbox epu2cpu_mb;
+
+ struct cx18_mailbox cpu2apu_mb;
+ struct cx18_mailbox hpu2apu_mb;
+ struct cx18_mailbox ppu2apu_mb;
+ struct cx18_mailbox epu2apu_mb;
+
+ struct cx18_mailbox cpu2hpu_mb;
+ struct cx18_mailbox apu2hpu_mb;
+ struct cx18_mailbox ppu2hpu_mb;
+ struct cx18_mailbox epu2hpu_mb;
+
+ struct cx18_mailbox cpu2ppu_mb;
+ struct cx18_mailbox apu2ppu_mb;
+ struct cx18_mailbox hpu2ppu_mb;
+ struct cx18_mailbox epu2ppu_mb;
+
+ struct cx18_mailbox cpu2epu_mb;
+ struct cx18_mailbox apu2epu_mb;
+ struct cx18_mailbox hpu2epu_mb;
+ struct cx18_mailbox ppu2epu_mb;
+
+ struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][2];
+ struct cx18_mdl cpu_mdl[1];
+};
+
+void cx18_init_scb(struct cx18 *cx);
+
+#endif
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
new file mode 100644
index 0000000..afb141b
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -0,0 +1,566 @@
+/*
+ * cx18 init/start/stop/exit stream functions
+ *
+ * Derived from ivtv-streams.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-fileops.h"
+#include "cx18-mailbox.h"
+#include "cx18-i2c.h"
+#include "cx18-queue.h"
+#include "cx18-ioctl.h"
+#include "cx18-streams.h"
+#include "cx18-cards.h"
+#include "cx18-scb.h"
+#include "cx18-av-core.h"
+#include "cx18-dvb.h"
+
+#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
+
+static struct file_operations cx18_v4l2_enc_fops = {
+ .owner = THIS_MODULE,
+ .read = cx18_v4l2_read,
+ .open = cx18_v4l2_open,
+ .ioctl = cx18_v4l2_ioctl,
+ .release = cx18_v4l2_close,
+ .poll = cx18_v4l2_enc_poll,
+};
+
+/* offset from 0 to register ts v4l2 minors on */
+#define CX18_V4L2_ENC_TS_OFFSET 16
+/* offset from 0 to register pcm v4l2 minors on */
+#define CX18_V4L2_ENC_PCM_OFFSET 24
+/* offset from 0 to register yuv v4l2 minors on */
+#define CX18_V4L2_ENC_YUV_OFFSET 32
+
+static struct {
+ const char *name;
+ int vfl_type;
+ int minor_offset;
+ int dma;
+ enum v4l2_buf_type buf_type;
+ struct file_operations *fops;
+} cx18_stream_info[] = {
+ { /* CX18_ENC_STREAM_TYPE_MPG */
+ "encoder MPEG",
+ VFL_TYPE_GRABBER, 0,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_TS */
+ "TS",
+ VFL_TYPE_GRABBER, -1,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_YUV */
+ "encoder YUV",
+ VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_VBI */
+ "encoder VBI",
+ VFL_TYPE_VBI, 0,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_PCM */
+ "encoder PCM audio",
+ VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_IDX */
+ "encoder IDX",
+ VFL_TYPE_GRABBER, -1,
+ PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ &cx18_v4l2_enc_fops
+ },
+ { /* CX18_ENC_STREAM_TYPE_RAD */
+ "encoder radio",
+ VFL_TYPE_RADIO, 0,
+ PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE,
+ &cx18_v4l2_enc_fops
+ },
+};
+
+static void cx18_stream_init(struct cx18 *cx, int type)
+{
+ struct cx18_stream *s = &cx->streams[type];
+ struct video_device *dev = s->v4l2dev;
+ u32 max_size = cx->options.megabytes[type] * 1024 * 1024;
+
+ /* we need to keep v4l2dev, so restore it afterwards */
+ memset(s, 0, sizeof(*s));
+ s->v4l2dev = dev;
+
+ /* initialize cx18_stream fields */
+ s->cx = cx;
+ s->type = type;
+ s->name = cx18_stream_info[type].name;
+ s->handle = 0xffffffff;
+
+ s->dma = cx18_stream_info[type].dma;
+ s->buf_size = cx->stream_buf_size[type];
+ if (s->buf_size)
+ s->buffers = max_size / s->buf_size;
+ if (s->buffers > 63) {
+ /* Each stream has a maximum of 63 buffers,
+ ensure we do not exceed that. */
+ s->buffers = 63;
+ s->buf_size = (max_size / s->buffers) & ~0xfff;
+ }
+ spin_lock_init(&s->qlock);
+ init_waitqueue_head(&s->waitq);
+ s->id = -1;
+ cx18_queue_init(&s->q_free);
+ cx18_queue_init(&s->q_full);
+ cx18_queue_init(&s->q_io);
+}
+
+static int cx18_prep_dev(struct cx18 *cx, int type)
+{
+ struct cx18_stream *s = &cx->streams[type];
+ u32 cap = cx->v4l2_cap;
+ int minor_offset = cx18_stream_info[type].minor_offset;
+ int minor;
+
+ /* These four fields are always initialized. If v4l2dev == NULL, then
+ this stream is not in use. In that case no other fields but these
+ four can be used. */
+ s->v4l2dev = NULL;
+ s->cx = cx;
+ s->type = type;
+ s->name = cx18_stream_info[type].name;
+
+ /* Check whether the radio is supported */
+ if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO))
+ return 0;
+
+ /* Check whether VBI is supported */
+ if (type == CX18_ENC_STREAM_TYPE_VBI &&
+ !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
+ return 0;
+
+ /* card number + user defined offset + device offset */
+ minor = cx->num + cx18_first_minor + minor_offset;
+
+ /* User explicitly selected 0 buffers for these streams, so don't
+ create them. */
+ if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
+ cx->options.megabytes[type] == 0) {
+ CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name);
+ return 0;
+ }
+
+ cx18_stream_init(cx, type);
+
+ if (minor_offset == -1)
+ return 0;
+
+ /* allocate and initialize the v4l2 video device structure */
+ s->v4l2dev = video_device_alloc();
+ if (s->v4l2dev == NULL) {
+ CX18_ERR("Couldn't allocate v4l2 video_device for %s\n",
+ s->name);
+ return -ENOMEM;
+ }
+
+ s->v4l2dev->type =
+ VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT |
+ VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER;
+ snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s",
+ cx->num, s->name);
+
+ s->v4l2dev->minor = minor;
+ s->v4l2dev->dev = &cx->dev->dev;
+ s->v4l2dev->fops = cx18_stream_info[type].fops;
+ s->v4l2dev->release = video_device_release;
+
+ return 0;
+}
+
+/* Initialize v4l2 variables and register v4l2 devices */
+int cx18_streams_setup(struct cx18 *cx)
+{
+ int type;
+
+ /* Setup V4L2 Devices */
+ for (type = 0; type < CX18_MAX_STREAMS; type++) {
+ /* Prepare device */
+ if (cx18_prep_dev(cx, type))
+ break;
+
+ /* Allocate Stream */
+ if (cx18_stream_alloc(&cx->streams[type]))
+ break;
+ }
+ if (type == CX18_MAX_STREAMS)
+ return 0;
+
+ /* One or more streams could not be initialized. Clean 'em all up. */
+ cx18_streams_cleanup(cx);
+ return -ENOMEM;
+}
+
+static int cx18_reg_dev(struct cx18 *cx, int type)
+{
+ struct cx18_stream *s = &cx->streams[type];
+ int vfl_type = cx18_stream_info[type].vfl_type;
+ int minor;
+
+ /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
+ * We need a VFL_TYPE_TS defined.
+ */
+ if (strcmp("TS", s->name) == 0) {
+ /* just return if no DVB is supported */
+ if ((cx->card->hw_all & CX18_HW_DVB) == 0)
+ return 0;
+ if (cx18_dvb_register(s) < 0) {
+ CX18_ERR("DVB failed to register\n");
+ return -EINVAL;
+ }
+ }
+
+ if (s->v4l2dev == NULL)
+ return 0;
+
+ minor = s->v4l2dev->minor;
+
+ /* Register device. First try the desired minor, then any free one. */
+ if (video_register_device(s->v4l2dev, vfl_type, minor) &&
+ video_register_device(s->v4l2dev, vfl_type, -1)) {
+ CX18_ERR("Couldn't register v4l2 device for %s minor %d\n",
+ s->name, minor);
+ video_device_release(s->v4l2dev);
+ s->v4l2dev = NULL;
+ return -ENOMEM;
+ }
+ minor = s->v4l2dev->minor;
+
+ switch (vfl_type) {
+ case VFL_TYPE_GRABBER:
+ CX18_INFO("Registered device video%d for %s (%d MB)\n",
+ minor, s->name, cx->options.megabytes[type]);
+ break;
+
+ case VFL_TYPE_RADIO:
+ CX18_INFO("Registered device radio%d for %s\n",
+ minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
+ break;
+
+ case VFL_TYPE_VBI:
+ if (cx->options.megabytes[type])
+ CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
+ minor - MINOR_VFL_TYPE_VBI_MIN,
+ s->name, cx->options.megabytes[type]);
+ else
+ CX18_INFO("Registered device vbi%d for %s\n",
+ minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
+ break;
+ }
+
+ return 0;
+}
+
+/* Register v4l2 devices */
+int cx18_streams_register(struct cx18 *cx)
+{
+ int type;
+ int err = 0;
+
+ /* Register V4L2 devices */
+ for (type = 0; type < CX18_MAX_STREAMS; type++)
+ err |= cx18_reg_dev(cx, type);
+
+ if (err == 0)
+ return 0;
+
+ /* One or more streams could not be initialized. Clean 'em all up. */
+ cx18_streams_cleanup(cx);
+ return -ENOMEM;
+}
+
+/* Unregister v4l2 devices */
+void cx18_streams_cleanup(struct cx18 *cx)
+{
+ struct video_device *vdev;
+ int type;
+
+ /* Teardown all streams */
+ for (type = 0; type < CX18_MAX_STREAMS; type++) {
+ if (cx->streams[type].dvb.enabled)
+ cx18_dvb_unregister(&cx->streams[type]);
+
+ vdev = cx->streams[type].v4l2dev;
+
+ cx->streams[type].v4l2dev = NULL;
+ if (vdev == NULL)
+ continue;
+
+ cx18_stream_free(&cx->streams[type]);
+
+ /* Unregister device */
+ video_unregister_device(vdev);
+ }
+}
+
+static void cx18_vbi_setup(struct cx18_stream *s)
+{
+ struct cx18 *cx = s->cx;
+ int raw = cx->vbi.sliced_in->service_set == 0;
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ int lines;
+
+ if (cx->is_60hz) {
+ cx->vbi.count = 12;
+ cx->vbi.start[0] = 10;
+ cx->vbi.start[1] = 273;
+ } else { /* PAL/SECAM */
+ cx->vbi.count = 18;
+ cx->vbi.start[0] = 6;
+ cx->vbi.start[1] = 318;
+ }
+
+ /* setup VBI registers */
+ cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
+
+ /* determine number of lines and total number of VBI bytes.
+ A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
+ The '- 1' byte is probably an unused U or V byte. Or something...
+ A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
+ header, 42 data bytes + checksum (to be confirmed) */
+ if (raw) {
+ lines = cx->vbi.count * 2;
+ } else {
+ lines = cx->is_60hz ? 24 : 38;
+ if (cx->is_60hz)
+ lines += 2;
+ }
+
+ cx->vbi.enc_size = lines *
+ (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+
+ data[0] = s->handle;
+ /* Lines per field */
+ data[1] = (lines / 2) | ((lines / 2) << 16);
+ /* bytes per line */
+ data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
+ /* Every X number of frames a VBI interrupt arrives
+ (frames as in 25 or 30 fps) */
+ data[3] = 1;
+ /* Setup VBI for the cx25840 digitizer */
+ if (raw) {
+ data[4] = 0x20602060;
+ data[5] = 0x30703070;
+ } else {
+ data[4] = 0xB0F0B0F0;
+ data[5] = 0xA0E0A0E0;
+ }
+
+ CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+
+ if (s->type == CX18_ENC_STREAM_TYPE_VBI)
+ cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
+}
+
+int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
+{
+ u32 data[MAX_MB_ARGUMENTS];
+ struct cx18 *cx = s->cx;
+ struct list_head *p;
+ int ts = 0;
+ int captype = 0;
+
+ if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+ return -EINVAL;
+
+ CX18_DEBUG_INFO("Start encoder stream %s\n", s->name);
+
+ switch (s->type) {
+ case CX18_ENC_STREAM_TYPE_MPG:
+ captype = CAPTURE_CHANNEL_TYPE_MPEG;
+ cx->mpg_data_received = cx->vbi_data_inserted = 0;
+ cx->dualwatch_jiffies = jiffies;
+ cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300;
+ cx->search_pack_header = 0;
+ break;
+
+ case CX18_ENC_STREAM_TYPE_TS:
+ captype = CAPTURE_CHANNEL_TYPE_TS;
+ ts = 1;
+ break;
+ case CX18_ENC_STREAM_TYPE_YUV:
+ captype = CAPTURE_CHANNEL_TYPE_YUV;
+ break;
+ case CX18_ENC_STREAM_TYPE_PCM:
+ captype = CAPTURE_CHANNEL_TYPE_PCM;
+ break;
+ case CX18_ENC_STREAM_TYPE_VBI:
+ captype = cx->vbi.sliced_in->service_set ?
+ CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI;
+ cx->vbi.frame = 0;
+ cx->vbi.inserted_frame = 0;
+ memset(cx->vbi.sliced_mpeg_size,
+ 0, sizeof(cx->vbi.sliced_mpeg_size));
+ break;
+ default:
+ return -EINVAL;
+ }
+ s->buffers_stolen = 0;
+
+ /* mute/unmute video */
+ cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
+ s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags));
+
+ /* Clear Streamoff flags in case left from last capture */
+ clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
+
+ cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE);
+ s->handle = data[0];
+ cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
+
+ if (atomic_read(&cx->capturing) == 0 && !ts) {
+ /* Stuff from Windows, we don't know what it is */
+ cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1);
+ cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12);
+
+ cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3,
+ s->handle, cx->digitizer, cx->digitizer);
+
+ /* Setup VBI */
+ if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE)
+ cx18_vbi_setup(s);
+
+ /* assign program index info.
+ Mask 7: select I/P/B, Num_req: 400 max */
+ cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
+
+ /* Setup API for Stream */
+ cx2341x_update(cx, cx18_api_func, NULL, &cx->params);
+ }
+
+ if (atomic_read(&cx->capturing) == 0) {
+ clear_bit(CX18_F_I_EOS, &cx->i_flags);
+ write_reg(7, CX18_DSP0_INTERRUPT_MASK);
+ }
+
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
+ (void *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
+ (void *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
+
+ list_for_each(p, &s->q_free.list) {
+ struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
+
+ writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr);
+ writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
+ cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
+ (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, 1,
+ buf->id, s->buf_size);
+ }
+ /* begin_capture */
+ if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
+ CX18_DEBUG_WARN("Error starting capture!\n");
+ cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+ return -EINVAL;
+ }
+
+ /* you're live! sit back and await interrupts :) */
+ atomic_inc(&cx->capturing);
+ return 0;
+}
+
+void cx18_stop_all_captures(struct cx18 *cx)
+{
+ int i;
+
+ for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+ continue;
+ if (test_bit(CX18_F_S_STREAMING, &s->s_flags))
+ cx18_stop_v4l2_encode_stream(s, 0);
+ }
+}
+
+int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
+{
+ struct cx18 *cx = s->cx;
+ unsigned long then;
+
+ if (s->v4l2dev == NULL && s->dvb.enabled == 0)
+ return -EINVAL;
+
+ /* This function assumes that you are allowed to stop the capture
+ and that we are actually capturing */
+
+ CX18_DEBUG_INFO("Stop Capture\n");
+
+ if (atomic_read(&cx->capturing) == 0)
+ return 0;
+
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG)
+ cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
+ else
+ cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
+
+ then = jiffies;
+
+ if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
+ CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
+ }
+
+ atomic_dec(&cx->capturing);
+
+ /* Clear capture and no-read bits */
+ clear_bit(CX18_F_S_STREAMING, &s->s_flags);
+
+ cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
+ s->handle = 0xffffffff;
+
+ if (atomic_read(&cx->capturing) > 0)
+ return 0;
+
+ write_reg(5, CX18_DSP0_INTERRUPT_MASK);
+ wake_up(&s->waitq);
+
+ return 0;
+}
+
+u32 cx18_find_handle(struct cx18 *cx)
+{
+ int i;
+
+ /* find first available handle to be used for global settings */
+ for (i = 0; i < CX18_MAX_STREAMS; i++) {
+ struct cx18_stream *s = &cx->streams[i];
+
+ if (s->v4l2dev && s->handle)
+ return s->handle;
+ }
+ return 0;
+}
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
new file mode 100644
index 0000000..8c7ba7d
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -0,0 +1,33 @@
+/*
+ * cx18 init/start/stop/exit stream functions
+ *
+ * Derived from ivtv-streams.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+u32 cx18_find_handle(struct cx18 *cx);
+int cx18_streams_setup(struct cx18 *cx);
+int cx18_streams_register(struct cx18 *cx);
+void cx18_streams_cleanup(struct cx18 *cx);
+
+/* Capture related */
+int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
+int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
+
+void cx18_stop_all_captures(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c
new file mode 100644
index 0000000..22e76ee
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-vbi.c
@@ -0,0 +1,208 @@
+/*
+ * cx18 Vertical Blank Interval support functions
+ *
+ * Derived from ivtv-vbi.c
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-vbi.h"
+#include "cx18-ioctl.h"
+#include "cx18-queue.h"
+#include "cx18-av-core.h"
+
+static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
+{
+ int line = 0;
+ int i;
+ u32 linemask[2] = { 0, 0 };
+ unsigned short size;
+ static const u8 mpeg_hdr_data[] = {
+ 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
+ 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
+ 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
+ 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
+ };
+ const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
+ int idx = cx->vbi.frame % CX18_VBI_FRAMES;
+ u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0];
+
+ for (i = 0; i < lines; i++) {
+ struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i;
+ int f, l;
+
+ if (sdata->id == 0)
+ continue;
+
+ l = sdata->line - 6;
+ f = sdata->field;
+ if (f)
+ l += 18;
+ if (l < 32)
+ linemask[0] |= (1 << l);
+ else
+ linemask[1] |= (1 << (l - 32));
+ dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id);
+ memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42);
+ line++;
+ }
+ memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
+ if (line == 36) {
+ /* All lines are used, so there is no space for the linemask
+ (the max size of the VBI data is 36 * 43 + 4 bytes).
+ So in this case we use the magic number 'ITV0'. */
+ memcpy(dst + sd, "ITV0", 4);
+ memcpy(dst + sd + 4, dst + sd + 12, line * 43);
+ size = 4 + ((43 * line + 3) & ~3);
+ } else {
+ memcpy(dst + sd, "cx0", 4);
+ memcpy(dst + sd + 4, &linemask[0], 8);
+ size = 12 + ((43 * line + 3) & ~3);
+ }
+ dst[4+16] = (size + 10) >> 8;
+ dst[5+16] = (size + 10) & 0xff;
+ dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
+ dst[10+16] = (pts_stamp >> 22) & 0xff;
+ dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
+ dst[12+16] = (pts_stamp >> 7) & 0xff;
+ dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
+ cx->vbi.sliced_mpeg_size[idx] = sd + size;
+}
+
+/* Compress raw VBI format, removes leading SAV codes and surplus space
+ after the field.
+ Returns new compressed size. */
+static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
+{
+ u32 line_size = cx->vbi.raw_decoder_line_size;
+ u32 lines = cx->vbi.count;
+ u8 sav1 = cx->vbi.raw_decoder_sav_odd_field;
+ u8 sav2 = cx->vbi.raw_decoder_sav_even_field;
+ u8 *q = buf;
+ u8 *p;
+ int i;
+
+ for (i = 0; i < lines; i++) {
+ p = buf + i * line_size;
+
+ /* Look for SAV code */
+ if (p[0] != 0xff || p[1] || p[2] ||
+ (p[3] != sav1 && p[3] != sav2))
+ break;
+ memcpy(q, p + 4, line_size - 4);
+ q += line_size - 4;
+ }
+ return lines * (line_size - 4);
+}
+
+
+/* Compressed VBI format, all found sliced blocks put next to one another
+ Returns new compressed size */
+static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
+ u32 size, u8 sav)
+{
+ u32 line_size = cx->vbi.sliced_decoder_line_size;
+ struct v4l2_decode_vbi_line vbi;
+ int i;
+
+ /* find the first valid line */
+ for (i = 0; i < size; i++, buf++) {
+ if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
+ break;
+ }
+
+ size -= i;
+ if (size < line_size)
+ return line;
+ for (i = 0; i < size / line_size; i++) {
+ u8 *p = buf + i * line_size;
+
+ /* Look for SAV code */
+ if (p[0] != 0xff || p[1] || p[2] || p[3] != sav)
+ continue;
+ vbi.p = p + 4;
+ cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
+ if (vbi.type) {
+ cx->vbi.sliced_data[line].id = vbi.type;
+ cx->vbi.sliced_data[line].field = vbi.is_second_field;
+ cx->vbi.sliced_data[line].line = vbi.line;
+ memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42);
+ line++;
+ }
+ }
+ return line;
+}
+
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+ u64 pts_stamp, int streamtype)
+{
+ u8 *p = (u8 *) buf->buf;
+ u32 size = buf->bytesused;
+ int lines;
+
+ if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
+ return;
+
+ /* Raw VBI data */
+ if (cx->vbi.sliced_in->service_set == 0) {
+ u8 type;
+
+ cx18_buf_swap(buf);
+
+ type = p[3];
+
+ size = buf->bytesused = compress_raw_buf(cx, p, size);
+
+ /* second field of the frame? */
+ if (type == cx->vbi.raw_decoder_sav_even_field) {
+ /* Dirty hack needed for backwards
+ compatibility of old VBI software. */
+ p += size - 4;
+ memcpy(p, &cx->vbi.frame, 4);
+ cx->vbi.frame++;
+ }
+ return;
+ }
+
+ /* Sliced VBI data with data insertion */
+ cx18_buf_swap(buf);
+
+ /* first field */
+ lines = compress_sliced_buf(cx, 0, p, size / 2,
+ cx->vbi.sliced_decoder_sav_odd_field);
+ /* second field */
+ /* experimentation shows that the second half does not always
+ begin at the exact address. So start a bit earlier
+ (hence 32). */
+ lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
+ size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field);
+ /* always return at least one empty line */
+ if (lines == 0) {
+ cx->vbi.sliced_data[0].id = 0;
+ cx->vbi.sliced_data[0].line = 0;
+ cx->vbi.sliced_data[0].field = 0;
+ lines = 1;
+ }
+ buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]);
+ memcpy(p, &cx->vbi.sliced_data[0], size);
+
+ if (cx->vbi.insert_mpeg)
+ copy_vbi_data(cx, lines, pts_stamp);
+ cx->vbi.frame++;
+}
diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h
new file mode 100644
index 0000000..c56ff7d
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-vbi.h
@@ -0,0 +1,26 @@
+/*
+ * cx18 Vertical Blank Interval support functions
+ *
+ * Derived from ivtv-vbi.h
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
+ u64 pts_stamp, int streamtype);
+int cx18_used_line(struct cx18 *cx, int line, int field);
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h
new file mode 100644
index 0000000..d5c7a6f
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-version.h
@@ -0,0 +1,34 @@
+/*
+ * cx18 driver version information
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef CX18_VERSION_H
+#define CX18_VERSION_H
+
+#define CX18_DRIVER_NAME "cx18"
+#define CX18_DRIVER_VERSION_MAJOR 1
+#define CX18_DRIVER_VERSION_MINOR 0
+#define CX18_DRIVER_VERSION_PATCHLEVEL 0
+
+#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
+#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
+ CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL)
+
+#endif
diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/video/cx18/cx18-video.c
new file mode 100644
index 0000000..2e5c419
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-video.c
@@ -0,0 +1,45 @@
+/*
+ * cx18 video interface functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#include "cx18-driver.h"
+#include "cx18-video.h"
+#include "cx18-av-core.h"
+#include "cx18-cards.h"
+
+void cx18_video_set_io(struct cx18 *cx)
+{
+ struct v4l2_routing route;
+ int inp = cx->active_input;
+ u32 type;
+
+ route.input = cx->card->video_inputs[inp].video_input;
+ route.output = 0;
+ cx18_av_cmd(cx, VIDIOC_INT_S_VIDEO_ROUTING, &route);
+
+ type = cx->card->video_inputs[inp].video_type;
+
+ if (type == CX18_CARD_INPUT_VID_TUNER)
+ route.input = 0; /* Tuner */
+ else if (type < CX18_CARD_INPUT_COMPOSITE1)
+ route.input = 2; /* S-Video */
+ else
+ route.input = 1; /* Composite */
+}
diff --git a/drivers/media/video/cx18/cx18-video.h b/drivers/media/video/cx18/cx18-video.h
new file mode 100644
index 0000000..529006a
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-video.h
@@ -0,0 +1,22 @@
+/*
+ * cx18 video interface functions
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+void cx18_video_set_io(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
new file mode 100644
index 0000000..33f78da
--- /dev/null
+++ b/drivers/media/video/cx18/cx23418.h
@@ -0,0 +1,458 @@
+/*
+ * cx18 header containing common defines.
+ *
+ * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.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., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307 USA
+ */
+
+#ifndef CX23418_H
+#define CX23418_H
+
+#include <media/cx2341x.h>
+
+#define MGR_CMD_MASK 0x40000000
+/* The MSB of the command code indicates that this is the completion of a
+ command */
+#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000)
+
+/* Description: This command creates a new instance of a certain task
+ IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is
+ the processor on which the task YYY will be created
+ OUT[0] - Task handle. This handle is passed along with commands to
+ dispatch to the right instance of the task
+ ReturnCode - One of the ERR_SYS_... */
+#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001)
+
+/* Description: This command destroys an instance of a task
+ IN[0] - Task handle. Hanlde of the task to destroy
+ ReturnCode - One of the ERR_SYS_... */
+#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002)
+
+/* All commands for CPU have the following mask set */
+#define CPU_CMD_MASK 0x20000000
+#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000)
+#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000)
+#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000)
+
+#define EPU_CMD_MASK 0x02000000
+#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000)
+#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000)
+
+/* Description: This command indicates that a Memory Descriptor List has been
+ filled with the requested channel type
+ IN[0] - Task handle. Handle of the task
+ IN[1] - Offset of the MDL_ACK from the beginning of the local DDR.
+ IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1]
+ ReturnCode - One of the ERR_DE_... */
+#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001)
+
+/* Something interesting happened
+ IN[0] - A value to log
+ IN[1] - An offset of a string in the MiniMe memory;
+ 0/zero/NULL means "I have nothing to say" */
+#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003)
+
+/* Description: This command starts streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to start
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002)
+
+/* Description: This command stops streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to stop
+ IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only)
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003)
+
+/* Description: This command pauses streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to pause
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007)
+
+/* Description: This command resumes streaming with the set channel type
+ IN[0] - Task handle. Handle of the task to resume
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008)
+
+#define CAPTURE_CHANNEL_TYPE_NONE 0
+#define CAPTURE_CHANNEL_TYPE_MPEG 1
+#define CAPTURE_CHANNEL_TYPE_INDEX 2
+#define CAPTURE_CHANNEL_TYPE_YUV 3
+#define CAPTURE_CHANNEL_TYPE_PCM 4
+#define CAPTURE_CHANNEL_TYPE_VBI 5
+#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6
+#define CAPTURE_CHANNEL_TYPE_TS 7
+#define CAPTURE_CHANNEL_TYPE_MAX 15
+
+/* Description: This command sets the channel type. This can only be done
+ when stopped.
+ IN[0] - Task handle. Handle of the task to start
+ IN[1] - Channel Type. See Below.
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1)
+
+/* Description: Set stream output type
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - type
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012)
+
+/* Description: Set video input resolution and frame rate
+ IN[0] - task handle
+ IN[1] - reserved
+ IN[2] - reserved
+ IN[3] - reserved
+ IN[4] - reserved
+ IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004)
+
+/* Description: Set video frame rate
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - video bit rate mode
+ IN[2] - video average rate
+ IN[3] - video peak rate
+ IN[4] - system mux rate
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005)
+
+/* Description: Set video output resolution
+ IN[0] - task handle
+ IN[1] - horizontal size
+ IN[2] - vertical size
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006)
+
+/* Description: This command set filter parameters
+ IN[0] - Task handle. Handle of the task
+ IN[1] - type, 0 - temporal, 1 - spatial, 2 - median
+ IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic
+ median: 0 = disable, 1 = horizontal, 2 = vertical,
+ 3 = horizontal/vertical, 4 = diagonal
+ IN[3] - strength, temporal 0 - 31, spatial 0 - 15
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009)
+
+/* Description: This command set spatial filter type
+ IN[0] - Task handle.
+ IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only,
+ 3 = 2D H/V separable, 4 = 2D symmetric non-separable
+ IN[2] - chroma type: 0 - diable, 1 = 1D horizontal
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C)
+
+/* Description: This command set coring levels for median filter
+ IN[0] - Task handle.
+ IN[1] - luma_high
+ IN[2] - luma_low
+ IN[3] - chroma_high
+ IN[4] - chroma_low
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E)
+
+/* Description: This command set the picture type mask for index file
+ IN[0] - 0 = disable index file output
+ 1 = output I picture
+ 2 = P picture
+ 4 = B picture
+ other = illegal */
+#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010)
+
+/* Description: Set audio parameters
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - audio parameter
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011)
+
+/* Description: Set video mute
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - bit31-24: muteYvalue
+ bit23-16: muteUvalue
+ bit15-8: muteVvalue
+ bit0: 1:mute, 0: unmute
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013)
+
+/* Description: Set audio mute
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - mute/unmute
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014)
+
+/* Description: Set stream output type
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - subType
+ SET_INITIAL_SCR 1
+ SET_QUALITY_MODE 2
+ SET_VIM_PROTECT_MODE 3
+ SET_PTS_CORRECTION 4
+ SET_USB_FLUSH_MODE 5
+ SET_MERAQPAR_ENABLE 6
+ SET_NAV_PACK_INSERTION 7
+ SET_SCENE_CHANGE_ENABLE 8
+ IN[2] - parameter 1
+ IN[3] - parameter 2
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015)
+
+/* Description: Set raw VBI parameters
+ IN[0] - Task handle
+ IN[1] - No. of input lines per field:
+ bit[15:0]: field 1,
+ bit[31:16]: field 2
+ IN[2] - No. of input bytes per line
+ IN[3] - No. of output frames per transfer
+ IN[4] - start code
+ IN[5] - stop code
+ ReturnCode */
+#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016)
+
+/* Description: Set capture line No.
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - height1
+ IN[2] - height2
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017)
+
+/* Description: Set copyright
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - copyright
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018)
+
+/* Description: Set audio PID
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - PID
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019)
+
+/* Description: Set video PID
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - PID
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A)
+
+/* Description: Set Vertical Crop Line
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - Line
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B)
+
+/* Description: Set COP structure
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - M
+ IN[2] - N
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C)
+
+/* Description: Set Scene Change Detection
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - scene change
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D)
+
+/* Description: Set Aspect Ratio
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - AspectRatio
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E)
+
+/* Description: Set Skip Input Frame
+ IN[0] - task handle. Handle of the task to start
+ IN[1] - skip input frames
+ ReturnCode - One of the ERR_CAPTURE_... */
+#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F)
+
+/* Description: Set sliced VBI parameters -
+ Note This API will only apply to MPEG and Sliced VBI Channels
+ IN[0] - Task handle
+ IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext
+ IN[2] - start / stop line
+ bit[15:0] start line number
+ bit[31:16] stop line number
+ IN[3] - number of output frames per interrupt
+ IN[4] - VBI insertion mode
+ bit 0: output user data, 1 - enable
+ bit 1: output private stream, 1 - enable
+ bit 2: mux option, 0 - in GOP, 1 - in picture
+ bit[7:0] private stream ID
+ IN[5] - insertion period while mux option is in picture
+ ReturnCode - VBI data offset */
+#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020)
+
+/* Description: Set the user data place holder
+ IN[0] - type of data (0 for user)
+ IN[1] - Stuffing period
+ IN[2] - ID data size in word (less than 10)
+ IN[3] - Pointer to ID buffer */
+#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021)
+
+
+/* Description:
+ In[0] Task Handle
+ return parameter:
+ Out[0] Reserved
+ Out[1] Video PTS bit[32:2] of last output video frame.
+ Out[2] Video PTS bit[ 1:0] of last output video frame.
+ Out[3] Hardware Video PTS counter bit[31:0],
+ these bits get incremented on every 90kHz clock tick.
+ Out[4] Hardware Video PTS counter bit32,
+ these bits get incremented on every 90kHz clock tick.
+ ReturnCode */
+#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022)
+
+/* Below is the list of commands related to the data exchange */
+#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000)
+
+/* Description: This command provides the physical base address of the local
+ DDR as viewed by EPU
+ IN[0] - Physical offset where EPU has the local DDR mapped
+ ReturnCode - One of the ERR_DE_... */
+#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001)
+
+/* Description: This command provides the offsets in the device memory where
+ the 2 cx18_mdl_ack blocks reside
+ IN[0] - Task handle. Handle of the task to start
+ IN[1] - Offset of the first cx18_mdl_ack from the beginning of the
+ local DDR.
+ IN[2] - Offset of the second cx18_mdl_ack from the beginning of the
+ local DDR.
+ ReturnCode - One of the ERR_DE_... */
+#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002)
+
+/* Description: This command provides the offset to a Memory Descriptor List
+ IN[0] - Task handle. Handle of the task to start
+ IN[1] - Offset of the MDL from the beginning of the local DDR.
+ IN[2] - Number of cx18_mdl structures in the array pointed to by IN[1]
+ IN[3] - Buffer ID
+ IN[4] - Total buffer length
+ ReturnCode - One of the ERR_DE_... */
+#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005)
+
+/* Description: This command requests return of all current Memory
+ Descriptor Lists to the driver
+ IN[0] - Task handle. Handle of the task to start
+ ReturnCode - One of the ERR_DE_... */
+/* #define CX18_CPU_DE_ReleaseMDL (CPU_CMD_MASK_DE | 0x0006) */
+
+/* Description: This command signals the cpu that the dat buffer has been
+ consumed and ready for re-use.
+ IN[0] - Task handle. Handle of the task
+ IN[1] - Offset of the data block from the beginning of the local DDR.
+ IN[2] - Number of bytes in the data block
+ ReturnCode - One of the ERR_DE_... */
+/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */
+
+/* No Error / Success */
+#define CNXT_OK 0x000000
+
+/* Received unknown command */
+#define CXERR_UNK_CMD 0x000001
+
+/* First parameter in the command is invalid */
+#define CXERR_INVALID_PARAM1 0x000002
+
+/* Second parameter in the command is invalid */
+#define CXERR_INVALID_PARAM2 0x000003
+
+/* Device interface is not open/found */
+#define CXERR_DEV_NOT_FOUND 0x000004
+
+/* Requested function is not implemented/available */
+#define CXERR_NOTSUPPORTED 0x000005
+
+/* Invalid pointer is provided */
+#define CXERR_BADPTR 0x000006
+
+/* Unable to allocate memory */
+#define CXERR_NOMEM 0x000007
+
+/* Object/Link not found */
+#define CXERR_LINK 0x000008
+
+/* Device busy, command cannot be executed */
+#define CXERR_BUSY 0x000009
+
+/* File/device/handle is not open. */
+#define CXERR_NOT_OPEN 0x00000A
+
+/* Value is out of range */
+#define CXERR_OUTOFRANGE 0x00000B
+
+/* Buffer overflow */
+#define CXERR_OVERFLOW 0x00000C
+
+/* Version mismatch */
+#define CXERR_BADVER 0x00000D
+
+/* Operation timed out */
+#define CXERR_TIMEOUT 0x00000E
+
+/* Operation aborted */
+#define CXERR_ABORT 0x00000F
+
+/* Specified I2C device not found for read/write */
+#define CXERR_I2CDEV_NOTFOUND 0x000010
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_XFERERR 0x000011
+
+/* Chanel changing component not ready */
+#define CXERR_CHANNELNOTREADY 0x000012
+
+/* PPU (Presensation/Decoder) mail box is corrupted */
+#define CXERR_PPU_MB_CORRUPT 0x000013
+
+/* CPU (Capture/Encoder) mail box is corrupted */
+#define CXERR_CPU_MB_CORRUPT 0x000014
+
+/* APU (Audio) mail box is corrupted */
+#define CXERR_APU_MB_CORRUPT 0x000015
+
+/* Unable to open file for reading */
+#define CXERR_FILE_OPEN_READ 0x000016
+
+/* Unable to open file for writing */
+#define CXERR_FILE_OPEN_WRITE 0x000017
+
+/* Unable to find the I2C section specified */
+#define CXERR_I2C_BADSECTION 0x000018
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_DATALOW 0x000019
+
+/* Error in I2C data xfer (but I2C device is present) */
+#define CXERR_I2CDEV_CLOCKLOW 0x00001A
+
+/* No Interrupt received from HW (for I2C access) */
+#define CXERR_NO_HW_I2C_INTR 0x00001B
+
+/* RPU is not ready to accept commands! */
+#define CXERR_RPU_NOT_READY 0x00001C
+
+/* RPU is not ready to accept commands! */
+#define CXERR_RPU_NO_ACK 0x00001D
+
+/* The are no buffers ready. Try again soon! */
+#define CXERR_NODATA_AGAIN 0x00001E
+
+/* The stream is stopping. Function not alllowed now! */
+#define CXERR_STOPPING_STATUS 0x00001F
+
+/* Trying to access hardware when the power is turned OFF */
+#define CXERR_DEVPOWER_OFF 0x000020
+
+#endif /* CX23418_H */
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index ca5fbce..cadf936 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -4,19 +4,19 @@
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_BTCX
- select VIDEO_TUNER
+ select MEDIA_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
select VIDEOBUF_DVB
select VIDEO_CX25840
- select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_MT2131 if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_PLL if !DVB_FE_CUSTOMISE
- select TUNER_XC2028 if !DVB_FE_CUSTOMIZE
- select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
- select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
- select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
---help---
This is a video4linux driver for Conexant 23885 based
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
index d7b0721..29c23b4 100644
--- a/drivers/media/video/cx23885/Makefile
+++ b/drivers/media/video/cx23885/Makefile
@@ -3,6 +3,7 @@
obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 7fde678..8882381 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -1209,7 +1209,8 @@
/* ----------------------------------------------------------------------- */
-static int cx25840_probe(struct i2c_client *client)
+static int cx25840_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct cx25840_state *state;
u32 id;
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 27635cd..b0d7d6a 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -5,7 +5,7 @@
select FW_LOADER
select VIDEO_BTCX
select VIDEOBUF_DMA_SG
- select VIDEO_TUNER
+ select MEDIA_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
@@ -57,7 +57,7 @@
select DVB_NXT200X if !DVB_FE_CUSTOMISE
select DVB_CX24123 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB/ATSC cards based on the
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 532cee3..6ec30f2 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -10,5 +10,6 @@
obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 2b6b283..aeba26d 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -57,6 +57,9 @@
/* ------------------------------------------------------------------ */
/* board config info */
+/* If radio_type !=UNSET, radio_addr should be specified
+ */
+
static const struct cx88_board cx88_boards[] = {
[CX88_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
@@ -2446,25 +2449,31 @@
static void cx88_card_setup(struct cx88_core *core)
{
static u8 eeprom[256];
+ struct tuner_setup tun_setup;
+ unsigned int mode_mask = T_RADIO |
+ T_ANALOG_TV |
+ T_DIGITAL_TV;
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
if (0 == core->i2c_rc) {
core->i2c_client.addr = 0xa0 >> 1;
- tveeprom_read(&core->i2c_client,eeprom,sizeof(eeprom));
+ tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom));
}
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_ROSLYN:
if (0 == core->i2c_rc)
- hauppauge_eeprom(core,eeprom+8);
+ hauppauge_eeprom(core, eeprom+8);
break;
case CX88_BOARD_GDI:
if (0 == core->i2c_rc)
- gdi_eeprom(core,eeprom);
+ gdi_eeprom(core, eeprom);
break;
case CX88_BOARD_WINFAST2000XP_EXPERT:
if (0 == core->i2c_rc)
- leadtek_eeprom(core,eeprom);
+ leadtek_eeprom(core, eeprom);
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
@@ -2474,7 +2483,7 @@
case CX88_BOARD_HAUPPAUGE_HVR3000:
case CX88_BOARD_HAUPPAUGE_HVR1300:
if (0 == core->i2c_rc)
- hauppauge_eeprom(core,eeprom);
+ hauppauge_eeprom(core, eeprom);
break;
case CX88_BOARD_KWORLD_DVBS_100:
cx_write(MO_GP0_IO, 0x000007f8);
@@ -2555,6 +2564,35 @@
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
}
+ } /*end switch() */
+
+
+ /* Setup tuners */
+ if ((core->board.radio_type != UNSET)) {
+ tun_setup.mode_mask = T_RADIO;
+ tun_setup.type = core->board.radio_type;
+ tun_setup.addr = core->board.radio_addr;
+ tun_setup.tuner_callback = cx88_tuner_callback;
+ cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+ mode_mask &= ~T_RADIO;
+ }
+
+ if (core->board.tuner_type != TUNER_ABSENT) {
+ tun_setup.mode_mask = mode_mask;
+ tun_setup.type = core->board.tuner_type;
+ tun_setup.addr = core->board.tuner_addr;
+ tun_setup.tuner_callback = cx88_tuner_callback;
+
+ cx88_call_i2c_clients(core, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
+ if (core->board.tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &core->board.tda9887_conf;
+
+ cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tda9887_cfg);
}
if (core->board.tuner_type == TUNER_XC2028) {
@@ -2572,6 +2610,7 @@
ctl.fname);
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg);
}
+ cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
}
/* ------------------------------------------------------------------ */
@@ -2710,7 +2749,6 @@
if (TUNER_ABSENT != core->board.tuner_type)
request_module("tuner");
- cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
cx88_card_setup(core);
cx88_ir_init(core, pci);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index c6b4473..cb6a096 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -99,42 +99,11 @@
static int attach_inform(struct i2c_client *client)
{
- struct tuner_setup tun_setup;
struct cx88_core *core = i2c_get_adapdata(client->adapter);
dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
client->driver->driver.name, client->addr, client->name);
- if (!client->driver->command)
- return 0;
- if (core->board.radio_type != UNSET) {
- if ((core->board.radio_addr==ADDR_UNSET)||(core->board.radio_addr==client->addr)) {
- tun_setup.mode_mask = T_RADIO;
- tun_setup.type = core->board.radio_type;
- tun_setup.addr = core->board.radio_addr;
- tun_setup.tuner_callback = cx88_tuner_callback;
- client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
- if (core->board.tuner_type != UNSET) {
- if ((core->board.tuner_addr==ADDR_UNSET)||(core->board.tuner_addr==client->addr)) {
-
- tun_setup.mode_mask = T_ANALOG_TV;
- tun_setup.type = core->board.tuner_type;
- tun_setup.addr = core->board.tuner_addr;
- tun_setup.tuner_callback = cx88_tuner_callback;
- client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
-
- if (core->board.tda9887_conf) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &core->board.tda9887_conf;
-
- client->driver->command(client, TUNER_SET_CONFIG, &tda9887_cfg);
- }
return 0;
}
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index 9caffed..c7c2896 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,7 +1,7 @@
config VIDEO_EM28XX
tristate "Empia EM28xx USB video capture support"
depends on VIDEO_DEV && I2C && INPUT
- select VIDEO_TUNER
+ select MEDIA_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
select VIDEOBUF_VMALLOC
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
index 3d1c3cc..8137a8c 100644
--- a/drivers/media/video/em28xx/Makefile
+++ b/drivers/media/video/em28xx/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index b617170..eec115b 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -4,7 +4,7 @@
select I2C_ALGOBIT
select FW_LOADER
select VIDEO_IR
- select VIDEO_TUNER
+ select MEDIA_TUNER
select VIDEO_TVEEPROM
select VIDEO_CX2341X
select VIDEO_CX25840
diff --git a/drivers/media/video/ivtv/Makefile b/drivers/media/video/ivtv/Makefile
index a038901..26ce0d6 100644
--- a/drivers/media/video/ivtv/Makefile
+++ b/drivers/media/video/ivtv/Makefile
@@ -8,6 +8,7 @@
obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index e908649..4fb8fae 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -40,6 +40,8 @@
#define MSP_MONO MSP_INPUT(MSP_IN_MONO, MSP_IN_TUNER1, \
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART)
+#define V4L2_STD_NOT_MN (V4L2_STD_PAL|V4L2_STD_SECAM)
+
/* usual i2c tuner addresses to probe */
static struct ivtv_card_tuner_i2c ivtv_i2c_std = {
.radio = { I2C_CLIENT_END },
@@ -298,7 +300,7 @@
.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
.tuners = {
/* The PAL tuner is confirmed */
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_mpg600,
@@ -339,7 +341,7 @@
.lang1 = 0x0004, .lang2 = 0x0000, .both = 0x0008 },
.gpio_audio_detect = { .mask = 0x0900, .stereo = 0x0100 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_mpg160,
@@ -375,7 +377,7 @@
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL },
},
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FQ1216ME },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FQ1216ME },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_pg600,
@@ -416,7 +418,7 @@
on the country/region setting of the user to decide which tuner
is available. */
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP,
.tuner = TUNER_PHILIPS_FM1236_MK3 },
{ .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 },
@@ -490,7 +492,7 @@
.gpio_video_input = { .mask = 0x0030, .tuner = 0x0000,
.composite = 0x0010, .svideo = 0x0020 },
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_tg5000tv,
.i2c = &ivtv_i2c_std,
@@ -521,7 +523,7 @@
{ IVTV_CARD_INPUT_AUD_TUNER, MSP_TUNER },
},
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_va2000,
.i2c = &ivtv_i2c_std,
@@ -565,7 +567,7 @@
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.pci_list = ivtv_pci_cx23416gyc,
@@ -597,7 +599,7 @@
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.i2c = &ivtv_i2c_std,
@@ -627,7 +629,7 @@
.gpio_audio_freq = { .mask = 0xc000, .f32000 = 0x0000,
.f44100 = 0x4000, .f48000 = 0x8000 },
.tuners = {
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
{ .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.i2c = &ivtv_i2c_std,
@@ -667,7 +669,7 @@
.gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 },
.tuners = {
/* This card has the Panasonic VP27 tuner */
- { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
},
.pci_list = ivtv_pci_gv_mvprx,
.i2c = &ivtv_i2c_std,
@@ -704,7 +706,7 @@
.gpio_audio_input = { .mask = 0xffff, .tuner = 0x0200, .linein = 0x0300 },
.tuners = {
/* This card has the Panasonic VP27 tuner */
- { .std = V4L2_STD_525_60, .tuner = TUNER_PANASONIC_VP27 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PANASONIC_VP27 },
},
.pci_list = ivtv_pci_gv_mvprx2e,
.i2c = &ivtv_i2c_std,
@@ -739,7 +741,7 @@
.gpio_init = { .direction = 0xf000, .initial_value = 0xA000 },
.tuners = {
/* This card has a Philips FQ1216ME MK3 tuner */
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
},
.pci_list = ivtv_pci_gotview_pci_dvd,
.i2c = &ivtv_i2c_std,
@@ -778,7 +780,7 @@
.gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
.tuners = {
/* This card has a Philips FQ1216ME MK5 tuner */
- { .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
+ { .std = V4L2_STD_NOT_MN, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
},
.pci_list = ivtv_pci_gotview_pci_dvd2,
.i2c = &ivtv_i2c_std,
@@ -856,7 +858,7 @@
.gpio_video_input = { .mask = 0x0030, .tuner = 0x0000,
.composite = 0x0010, .svideo = 0x0020},
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FQ1286 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_dctmvtvp1,
.i2c = &ivtv_i2c_std,
@@ -875,6 +877,7 @@
static const struct ivtv_card ivtv_card_pg600v2 = {
.type = IVTV_CARD_PG600V2,
.name = "Yuan PG600-2, GotView PCI DVD Lite",
+ .comment = "only Composite and S-Video inputs are supported, not the tuner\n",
.v4l2_capabilities = IVTV_CAP_ENCODER,
.hw_video = IVTV_HW_CX25840,
.hw_audio = IVTV_HW_CX25840,
@@ -921,6 +924,7 @@
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
.gpio_init = { .direction = 0x1000, .initial_value = 0x1000 }, /* tuner reset */
+ .xceive_pin = 12,
.tuners = {
{ .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
},
@@ -944,15 +948,22 @@
.hw_video = IVTV_HW_CX25840,
.hw_audio = IVTV_HW_CX25840,
.hw_audio_ctrl = IVTV_HW_CX25840,
- .hw_all = IVTV_HW_CX25840 | IVTV_HW_WM8739,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
.video_inputs = {
- { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 },
- { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+ { IVTV_CARD_INPUT_VID_TUNER, 0, CX25840_COMPOSITE2 },
+ { IVTV_CARD_INPUT_SVIDEO1, 1, CX25840_SVIDEO3 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 1, CX25840_COMPOSITE1 },
},
.audio_inputs = {
+ { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO5 },
{ IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
},
- .gpio_init = { .direction = 0xe000, .initial_value = 0x4000 }, /* enable line-in */
+ /* enable line-in */
+ .gpio_init = { .direction = 0xe400, .initial_value = 0x4400 },
+ .xceive_pin = 10,
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
.pci_list = ivtv_pci_avertv_mce116,
.i2c = &ivtv_i2c_std,
};
@@ -990,7 +1001,7 @@
.gpio_audio_input = { .mask = 0x0800, .tuner = 0, .linein = 0, .radio = 0x0800 },
.tuners = {
/* This card has a Partsnic PTI-5NF05 tuner */
- { .std = V4L2_STD_525_60, .tuner = TUNER_TCL_2002N },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_TCL_2002N },
},
.pci_list = ivtv_pci_aver_pvr150,
.i2c = &ivtv_i2c_radio,
@@ -1058,12 +1069,48 @@
},
.radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, M52790_IN_TUNER },
.tuners = {
- { .std = V4L2_STD_525_60, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ { .std = V4L2_STD_525_60|V4L2_STD_MN, .tuner = TUNER_PHILIPS_FM1236_MK3 },
},
.pci_list = ivtv_pci_asus_falcon2,
.i2c = &ivtv_i2c_std,
};
+/* ------------------------------------------------------------------------- */
+
+/* AVerMedia M104 miniPCI card */
+
+static const struct ivtv_card_pci_info ivtv_pci_aver_m104[] = {
+ { PCI_DEVICE_ID_IVTV16, IVTV_PCI_ID_AVERMEDIA, 0xc136 },
+ { 0, 0, 0 }
+};
+
+static const struct ivtv_card ivtv_card_aver_m104 = {
+ .type = IVTV_CARD_AVER_M104,
+ .name = "AVerMedia M104",
+ .comment = "Not yet supported!\n",
+ .v4l2_capabilities = 0, /*IVTV_CAP_ENCODER,*/
+ .hw_video = IVTV_HW_CX25840,
+ .hw_audio = IVTV_HW_CX25840,
+ .hw_audio_ctrl = IVTV_HW_CX25840,
+ .hw_all = IVTV_HW_CX25840 | IVTV_HW_TUNER | IVTV_HW_WM8739,
+ .video_inputs = {
+ { IVTV_CARD_INPUT_SVIDEO1, 0, CX25840_SVIDEO3 },
+ { IVTV_CARD_INPUT_COMPOSITE1, 0, CX25840_COMPOSITE1 },
+ },
+ .audio_inputs = {
+ { IVTV_CARD_INPUT_LINE_IN1, CX25840_AUDIO_SERIAL, 1 },
+ },
+ .radio_input = { IVTV_CARD_INPUT_AUD_TUNER, CX25840_AUDIO_SERIAL, 2 },
+ /* enable line-in + reset tuner */
+ .gpio_init = { .direction = 0xe400, .initial_value = 0x4000 },
+ .xceive_pin = 10,
+ .tuners = {
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ .pci_list = ivtv_pci_aver_m104,
+ .i2c = &ivtv_i2c_std,
+};
+
static const struct ivtv_card *ivtv_card_list[] = {
&ivtv_card_pvr250,
&ivtv_card_pvr350,
@@ -1089,6 +1136,7 @@
&ivtv_card_asus_falcon2,
&ivtv_card_aver_pvr150,
&ivtv_card_aver_ezmaker,
+ &ivtv_card_aver_m104,
/* Variations of standard cards but with the same PCI IDs.
These cards must come last in this list. */
@@ -1120,7 +1168,8 @@
if (index >= itv->nof_inputs)
return -EINVAL;
input->index = index;
- strcpy(input->name, input_strs[card_input->video_type - 1]);
+ strlcpy(input->name, input_strs[card_input->video_type - 1],
+ sizeof(input->name));
input->type = (card_input->video_type == IVTV_CARD_INPUT_VID_TUNER ?
V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
input->audioset = (1 << itv->nof_audio_inputs) - 1;
@@ -1137,7 +1186,7 @@
if (index >= itv->card->nof_outputs)
return -EINVAL;
output->index = index;
- strcpy(output->name, card_output->name);
+ strlcpy(output->name, card_output->name, sizeof(output->name));
output->type = V4L2_OUTPUT_TYPE_ANALOG;
output->audioset = 1;
output->std = V4L2_STD_ALL;
@@ -1156,7 +1205,8 @@
memset(audio, 0, sizeof(*audio));
if (index >= itv->nof_audio_inputs)
return -EINVAL;
- strcpy(audio->name, input_strs[aud_input->audio_type - 1]);
+ strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
+ sizeof(audio->name));
audio->index = index;
audio->capability = V4L2_AUDCAP_STEREO;
return 0;
@@ -1167,6 +1217,6 @@
memset(aud_output, 0, sizeof(*aud_output));
if (itv->card->video_outputs == NULL || index != 0)
return -EINVAL;
- strcpy(aud_output->name, "A/V Audio Out");
+ strlcpy(aud_output->name, "A/V Audio Out", sizeof(aud_output->name));
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 9186fa2..748485d 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -48,7 +48,8 @@
#define IVTV_CARD_ASUS_FALCON2 21 /* ASUS Falcon2 */
#define IVTV_CARD_AVER_PVR150PLUS 22 /* AVerMedia PVR-150 Plus */
#define IVTV_CARD_AVER_EZMAKER 23 /* AVerMedia EZMaker PCI Deluxe */
-#define IVTV_CARD_LAST 23
+#define IVTV_CARD_AVER_M104 24 /* AverMedia M104 miniPCI card */
+#define IVTV_CARD_LAST 24
/* Variants of existing cards but with the same PCI IDs. The driver
detects these based on other device information.
@@ -244,6 +245,7 @@
struct ivtv_card {
int type;
char *name;
+ char *comment;
u32 v4l2_capabilities;
u32 hw_video; /* hardware used to process video */
u32 hw_audio; /* hardware used to process audio */
@@ -256,6 +258,7 @@
int nof_outputs;
const struct ivtv_card_output *video_outputs;
u8 gr_config; /* config byte for the ghost reduction device */
+ u8 xceive_pin; /* XCeive tuner GPIO reset pin */
/* GPIO card-specific settings */
struct ivtv_gpio_init gpio_init;
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 065df53..ed020f7 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -190,6 +190,7 @@
"\t\t\t22 = ASUS Falcon2\n"
"\t\t\t23 = AverMedia PVR-150 Plus\n"
"\t\t\t24 = AverMedia EZMaker PCI Deluxe\n"
+ "\t\t\t25 = AverMedia M104 (not yet working)\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
@@ -871,7 +872,7 @@
unsigned i;
/* load modules */
-#ifndef CONFIG_VIDEO_TUNER
+#ifndef CONFIG_MEDIA_TUNER
hw = ivtv_request_module(itv, hw, "tuner", IVTV_HW_TUNER);
#endif
#ifndef CONFIG_VIDEO_CX25840
@@ -1048,7 +1049,7 @@
IVTV_ENCODER_SIZE);
if (!itv->enc_mem) {
IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+ IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1060,7 +1061,7 @@
IVTV_DECODER_SIZE);
if (!itv->dec_mem) {
IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+ IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1076,7 +1077,7 @@
ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (!itv->reg_mem) {
IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIMEM4G into the kernel would help\n");
+ IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
retval = -ENOMEM;
goto free_io;
}
@@ -1097,6 +1098,13 @@
The PCI IDs are not always reliable. */
ivtv_process_eeprom(itv);
}
+ if (itv->card->comment)
+ IVTV_INFO("%s", itv->card->comment);
+ if (itv->card->v4l2_capabilities == 0) {
+ /* card was detected but is not supported */
+ retval = -ENODEV;
+ goto free_i2c;
+ }
if (itv->std == 0) {
itv->std = V4L2_STD_NTSC_M;
@@ -1195,13 +1203,6 @@
ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std);
}
- retval = ivtv_streams_setup(itv);
- if (retval) {
- IVTV_ERR("Error %d setting up streams\n", retval);
- goto free_i2c;
- }
-
- IVTV_DEBUG_IRQ("Masking interrupts\n");
/* clear interrupt mask, effectively disabling interrupts */
ivtv_set_irq_mask(itv, 0xffffffff);
@@ -1210,32 +1211,38 @@
IRQF_SHARED | IRQF_DISABLED, itv->name, (void *)itv);
if (retval) {
IVTV_ERR("Failed to register irq %d\n", retval);
- goto free_streams;
+ goto free_i2c;
+ }
+
+ retval = ivtv_streams_setup(itv);
+ if (retval) {
+ IVTV_ERR("Error %d setting up streams\n", retval);
+ goto free_irq;
}
retval = ivtv_streams_register(itv);
if (retval) {
IVTV_ERR("Error %d registering devices\n", retval);
- goto free_irq;
+ goto free_streams;
}
IVTV_INFO("Initialized card #%d: %s\n", itv->num, itv->card_name);
return 0;
- free_irq:
- free_irq(itv->dev->irq, (void *)itv);
- free_streams:
+free_streams:
ivtv_streams_cleanup(itv);
- free_i2c:
+free_irq:
+ free_irq(itv->dev->irq, (void *)itv);
+free_i2c:
exit_ivtv_i2c(itv);
- free_io:
+free_io:
ivtv_iounmap(itv);
- free_mem:
+free_mem:
release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (itv->has_cx23415)
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
- free_workqueue:
+free_workqueue:
destroy_workqueue(itv->irq_work_queues);
- err:
+err:
if (retval == 0)
retval = -ENODEV;
IVTV_ERR("Error %d on initialization\n", retval);
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index a7640c4..2b74b0a 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -755,8 +755,10 @@
IVTV_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
- if (eof || s->q_full.length || s->q_io.length)
+ if (s->q_full.length || s->q_io.length)
return POLLIN | POLLRDNORM;
+ if (eof)
+ return POLLHUP;
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index 688cd38..d8ac09f 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -128,20 +128,17 @@
{
struct i2c_algo_bit_data *algo = dev;
struct ivtv *itv = algo->data;
- int curdir, curout;
+ u32 curout;
if (cmd != XC2028_TUNER_RESET)
return 0;
IVTV_DEBUG_INFO("Resetting tuner\n");
curout = read_reg(IVTV_REG_GPIO_OUT);
- curdir = read_reg(IVTV_REG_GPIO_DIR);
- curdir |= (1 << 12); /* GPIO bit 12 */
-
- curout &= ~(1 << 12);
+ curout &= ~(1 << itv->card->xceive_pin);
write_reg(curout, IVTV_REG_GPIO_OUT);
schedule_timeout_interruptible(msecs_to_jiffies(1));
- curout |= (1 << 12);
+ curout |= 1 << itv->card->xceive_pin;
write_reg(curout, IVTV_REG_GPIO_OUT);
schedule_timeout_interruptible(msecs_to_jiffies(1));
return 0;
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index 9824eaf..771adf4 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -167,7 +167,8 @@
return -1;
id = hw_driverids[idx];
memset(&info, 0, sizeof(info));
- strcpy(info.driver_name, hw_drivernames[idx]);
+ strlcpy(info.driver_name, hw_drivernames[idx],
+ sizeof(info.driver_name));
info.addr = hw_addrs[idx];
for (i = 0; itv->i2c_clients[i] && i < I2C_CLIENTS_MAX; i++) {}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index 15cac18..d508b5d 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -243,20 +243,31 @@
int fact = new_speed < 0 ? -1 : 1;
int s;
- if (new_speed < 0) new_speed = -new_speed;
- if (cur_speed < 0) cur_speed = -cur_speed;
+ if (cur_speed == 0)
+ cur_speed = 1000;
+ if (new_speed < 0)
+ new_speed = -new_speed;
+ if (cur_speed < 0)
+ cur_speed = -cur_speed;
if (cur_speed <= new_speed) {
- if (new_speed > 1500) return fact * 2000;
- if (new_speed > 1000) return fact * 1500;
+ if (new_speed > 1500)
+ return fact * 2000;
+ if (new_speed > 1000)
+ return fact * 1500;
}
else {
- if (new_speed >= 2000) return fact * 2000;
- if (new_speed >= 1500) return fact * 1500;
- if (new_speed >= 1000) return fact * 1000;
+ if (new_speed >= 2000)
+ return fact * 2000;
+ if (new_speed >= 1500)
+ return fact * 1500;
+ if (new_speed >= 1000)
+ return fact * 1000;
}
- if (new_speed == 0) return 1000;
- if (new_speed == 1 || new_speed == 1000) return fact * new_speed;
+ if (new_speed == 0)
+ return 1000;
+ if (new_speed == 1 || new_speed == 1000)
+ return fact * new_speed;
s = new_speed;
new_speed = 1000 / new_speed;
@@ -741,10 +752,9 @@
struct v4l2_capability *vcap = arg;
memset(vcap, 0, sizeof(*vcap));
- strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */
- strncpy(vcap->card, itv->card_name,
- sizeof(vcap->card)-1); /* card type */
- strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */
+ strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
+ strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
+ strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
vcap->version = IVTV_DRIVER_VERSION; /* version */
vcap->capabilities = itv->v4l2_cap; /* capabilities */
@@ -1018,7 +1028,7 @@
ivtv_std_60hz : ivtv_std_50hz;
vs->index = idx;
vs->id = enum_stds[idx].std;
- strcpy(vs->name, enum_stds[idx].name);
+ strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
break;
}
@@ -1102,10 +1112,10 @@
ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
- strcpy(vt->name, "ivtv Radio Tuner");
+ strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_RADIO;
} else {
- strcpy(vt->name, "ivtv TV Tuner");
+ strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_ANALOG_TV;
}
break;
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index a329c46..d8ba3a4 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -384,7 +384,7 @@
ivtv_stream_sync_for_device(s);
write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
- itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
add_timer(&itv->dma_timer);
}
@@ -400,7 +400,7 @@
ivtv_stream_sync_for_device(s);
write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
- itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(300);
add_timer(&itv->dma_timer);
}
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index 0f1d4cc..02c5ab0 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -23,7 +23,7 @@
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
#define IVTV_DRIVER_VERSION_MINOR 2
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 0
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 3b23fc0..df789f6 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -532,7 +532,7 @@
IVTVFB_DEBUG_INFO("ivtvfb_get_fix\n");
memset(fix, 0, sizeof(struct fb_fix_screeninfo));
- strcpy(fix->id, "cx23415 TV out");
+ strlcpy(fix->id, "cx23415 TV out", sizeof(fix->id));
fix->smem_start = oi->video_pbase;
fix->smem_len = oi->video_buffer_size;
fix->type = FB_TYPE_PACKED_PIXELS;
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
index d4bf14c..5b9dfa2 100644
--- a/drivers/media/video/m52790.c
+++ b/drivers/media/video/m52790.c
@@ -126,7 +126,8 @@
/* i2c implementation */
-static int m52790_probe(struct i2c_client *client)
+static int m52790_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct m52790_state *state;
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index b73c740..e627316 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -805,7 +805,7 @@
/* ----------------------------------------------------------------------- */
-static int msp_probe(struct i2c_client *client)
+static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct msp_state *state;
int (*thread_func)(void *data) = NULL;
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index 3fb5f63..179e470 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -372,7 +372,7 @@
}
#endif
-const struct v4l2_queryctrl mt9m001_controls[] = {
+static const struct v4l2_queryctrl mt9m001_controls[] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -620,7 +620,8 @@
soc_camera_video_stop(&mt9m001->icd);
}
-static int mt9m001_probe(struct i2c_client *client)
+static int mt9m001_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct mt9m001 *mt9m001;
struct soc_camera_device *icd;
@@ -696,12 +697,19 @@
return 0;
}
+static const struct i2c_device_id mt9m001_id[] = {
+ { "mt9m001", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9m001_id);
+
static struct i2c_driver mt9m001_i2c_driver = {
.driver = {
.name = "mt9m001",
},
.probe = mt9m001_probe,
.remove = mt9m001_remove,
+ .id_table = mt9m001_id,
};
static int __init mt9m001_mod_init(void)
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index d4b9e27..d1391ac 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -452,7 +452,7 @@
}
#endif
-const struct v4l2_queryctrl mt9v022_controls[] = {
+static const struct v4l2_queryctrl mt9v022_controls[] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -745,7 +745,8 @@
soc_camera_video_stop(&mt9v022->icd);
}
-static int mt9v022_probe(struct i2c_client *client)
+static int mt9v022_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct mt9v022 *mt9v022;
struct soc_camera_device *icd;
@@ -818,12 +819,19 @@
return 0;
}
+static const struct i2c_device_id mt9v022_id[] = {
+ { "mt9v022", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, mt9v022_id);
+
static struct i2c_driver mt9v022_i2c_driver = {
.driver = {
.name = "mt9v022",
},
.probe = mt9v022_probe,
.remove = mt9v022_remove,
+ .id_table = mt9v022_id,
};
static int __init mt9v022_mod_init(void)
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index 158b3d0..9620c67 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -1,14 +1,15 @@
config VIDEO_PVRUSB2
tristate "Hauppauge WinTV-PVR USB2 support"
- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ depends on VIDEO_V4L2 && I2C
select FW_LOADER
- select VIDEO_TUNER
+ select MEDIA_TUNER
select VIDEO_TVEEPROM
select VIDEO_CX2341X
select VIDEO_SAA711X
select VIDEO_CX25840
select VIDEO_MSP3400
select VIDEO_WM8775
+ select VIDEO_CS53L32A
---help---
This is a video4linux driver for Conexant 23416 based
usb2 personal video recorder devices.
@@ -16,32 +17,6 @@
To compile this driver as a module, choose M here: the
module will be called pvrusb2
-config VIDEO_PVRUSB2_ONAIR_CREATOR
- bool "pvrusb2 driver support for OnAir Creator model"
- depends on VIDEO_PVRUSB2 && EXPERIMENTAL
- select VIDEO_SAA711X
- select VIDEO_CS53L32A
- ---help---
-
- This option enables support for the OnAir Creator USB tuner
- device. This is a hybrid device, however currently only
- analog mode is supported.
-
- If you are in doubt, say Y.
-
-config VIDEO_PVRUSB2_ONAIR_USB2
- bool "pvrusb2 driver support for OnAir USB2 model"
- depends on VIDEO_PVRUSB2 && EXPERIMENTAL
- select VIDEO_SAA711X
- select VIDEO_CS53L32A
- ---help---
-
- This option enables support for the OnAir USB2 tuner device
- (also known as the Sasem tuner). This is a hybrid device,
- however currently only analog mode is supported.
-
- If you are in doubt, say Y.
-
config VIDEO_PVRUSB2_SYSFS
bool "pvrusb2 sysfs support (EXPERIMENTAL)"
default y
@@ -59,29 +34,23 @@
Note: This feature is experimental and subject to change.
config VIDEO_PVRUSB2_DVB
- bool "pvrusb2 DVB support (EXPERIMENTAL)"
- default n
+ bool "pvrusb2 ATSC/DVB support (EXPERIMENTAL)"
+ default y
depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
- select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
- select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
---help---
- This option enables compilation of a DVB interface for the
- pvrusb2 driver. Currently this is very very experimental.
- It is also limiting - the DVB interface can only access the
- digital side of hybrid devices, and there are going to be
- issues if you attempt to mess with the V4L side at the same
- time. Don't turn this on unless you know what you are
- doing.
+ This option enables a DVB interface for the pvrusb2 driver.
+ If your device does not support digital television, this
+ feature will have no affect on the driver's operation.
- If you are in doubt, say N.
-
- Note: This feature is very experimental and might break
+ If you are in doubt, say Y.
config VIDEO_PVRUSB2_DEBUGIFC
bool "pvrusb2 debug interface"
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
index 5b3083c..4fda2de 100644
--- a/drivers/media/video/pvrusb2/Makefile
+++ b/drivers/media/video/pvrusb2/Makefile
@@ -16,5 +16,6 @@
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index 11537dd..707d2d9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -54,6 +54,7 @@
#define PVR2_TRACE_DATA_FLOW (1 << 25) /* Track data flow */
#define PVR2_TRACE_DEBUGIFC (1 << 26) /* Debug interface actions */
#define PVR2_TRACE_GPIO (1 << 27) /* GPIO state bit changes */
+#define PVR2_TRACE_DVB_FEED (1 << 28) /* DVB transport feed debug */
#endif /* __PVRUSB2_HDW_INTERNAL_H */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 3a141d9..5bf6d8f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -153,7 +153,6 @@
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
/*------------------------------------------------------------------------*/
/* OnAir Creator */
@@ -212,11 +211,9 @@
.dvb_props = &pvr2_onair_creator_fe_props,
#endif
};
-#endif
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
/*------------------------------------------------------------------------*/
/* OnAir USB 2.0 */
@@ -274,7 +271,6 @@
.dvb_props = &pvr2_onair_usb2_fe_props,
#endif
};
-#endif
@@ -497,14 +493,10 @@
.driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
{ USB_DEVICE(0x1164, 0x0602),
.driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d},
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
{ USB_DEVICE(0x11ba, 0x1003),
.driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
-#endif
-#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_USB2
{ USB_DEVICE(0x11ba, 0x1001),
.driver_info = (kernel_ulong_t)&pvr2_device_onair_usb2},
-#endif
{ USB_DEVICE(0x2040, 0x7300),
.driver_info = (kernel_ulong_t)&pvr2_device_73xxx},
{ USB_DEVICE(0x2040, 0x7500),
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
index 6504c97..6ec4bf81 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
@@ -21,6 +21,7 @@
#include <linux/kthread.h>
#include <linux/freezer.h>
#include "dvbdev.h"
+#include "pvrusb2-debug.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-io.h"
@@ -35,7 +36,7 @@
struct pvr2_buffer *bp;
struct pvr2_stream *stream;
- printk(KERN_DEBUG "dvb thread started\n");
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread started");
set_freezable();
stream = adap->channel.stream->stream;
@@ -82,7 +83,7 @@
/* If we get here and ret is < 0, then an error has occurred.
Probably would be a good idea to communicate that to DVB core... */
- printk(KERN_DEBUG "dvb thread stopped\n");
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "dvb feed thread stopped");
return 0;
}
@@ -210,7 +211,8 @@
do {
if (onoff) {
if (!adap->feedcount) {
- printk(KERN_DEBUG "start feeding\n");
+ pvr2_trace(PVR2_TRACE_DVB_FEED,
+ "start feeding demux");
ret = pvr2_dvb_stream_start(adap);
if (ret < 0) break;
}
@@ -218,7 +220,8 @@
} else if (adap->feedcount > 0) {
(adap->feedcount)--;
if (!adap->feedcount) {
- printk(KERN_DEBUG "stop feeding\n");
+ pvr2_trace(PVR2_TRACE_DVB_FEED,
+ "stop feeding demux");
pvr2_dvb_stream_end(adap);
}
}
@@ -230,15 +233,13 @@
static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
- printk(KERN_DEBUG "start pid: 0x%04x, feedtype: %d\n",
- dvbdmxfeed->pid, dvbdmxfeed->type);
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "start pid: 0x%04x", dvbdmxfeed->pid);
return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1);
}
static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
- printk(KERN_DEBUG "stop pid: 0x%04x, feedtype: %d\n",
- dvbdmxfeed->pid, dvbdmxfeed->type);
+ pvr2_trace(PVR2_TRACE_DVB_FEED, "stop pid: 0x%04x", dvbdmxfeed->pid);
return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0);
}
@@ -259,7 +260,8 @@
&adap->channel.hdw->usb_dev->dev,
adapter_nr);
if (ret < 0) {
- err("dvb_register_adapter failed: error %d", ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "dvb_register_adapter failed: error %d", ret);
goto err;
}
adap->dvb_adap.priv = adap;
@@ -276,7 +278,8 @@
ret = dvb_dmx_init(&adap->demux);
if (ret < 0) {
- err("dvb_dmx_init failed: error %d", ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "dvb_dmx_init failed: error %d", ret);
goto err_dmx;
}
@@ -286,7 +289,8 @@
ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
if (ret < 0) {
- err("dvb_dmxdev_init failed: error %d", ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "dvb_dmxdev_init failed: error %d", ret);
goto err_dmx_dev;
}
@@ -304,7 +308,7 @@
static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap)
{
- printk(KERN_DEBUG "unregistering DVB devices\n");
+ pvr2_trace(PVR2_TRACE_INFO, "unregistering DVB devices");
dvb_net_release(&adap->dvb_net);
adap->demux.dmx.close(&adap->demux.dmx);
dvb_dmxdev_release(&adap->dmxdev);
@@ -320,7 +324,7 @@
int ret = 0;
if (dvb_props == NULL) {
- err("fe_props not defined!");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS, "fe_props not defined!");
return -EINVAL;
}
@@ -328,13 +332,15 @@
&adap->channel,
(1 << PVR2_CVAL_INPUT_DTV));
if (ret) {
- err("failed to grab control of dtv input (code=%d)",
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "failed to grab control of dtv input (code=%d)",
ret);
return ret;
}
if (dvb_props->frontend_attach == NULL) {
- err("frontend_attach not defined!");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "frontend_attach not defined!");
ret = -EINVAL;
goto done;
}
@@ -342,7 +348,8 @@
if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) {
if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
- err("frontend registration failed!");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "frontend registration failed!");
dvb_frontend_detach(adap->fe);
adap->fe = NULL;
ret = -ENODEV;
@@ -359,7 +366,8 @@
adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
} else {
- err("no frontend was attached!");
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "no frontend was attached!");
ret = -ENODEV;
return ret;
}
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 416d05d..e684108 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1450,7 +1450,8 @@
/* ----------------------------------------------------------------------- */
-static int saa7115_probe(struct i2c_client *client)
+static int saa7115_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct saa711x_state *state;
int i;
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 06c88db..e750cd6 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -661,7 +661,8 @@
/* ----------------------------------------------------------------------- */
-static int saa7127_probe(struct i2c_client *client)
+static int saa7127_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct saa7127_state *state;
struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index e086f14..40e4c3b 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -3,7 +3,7 @@
depends on VIDEO_DEV && PCI && I2C && INPUT
select VIDEOBUF_DMA_SG
select VIDEO_IR
- select VIDEO_TUNER
+ select MEDIA_TUNER
select VIDEO_TVEEPROM
select CRC32
---help---
@@ -35,9 +35,9 @@
select DVB_NXT200X if !DVB_FE_CUSTOMISE
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
- select DVB_TDA827X if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_TDA827X if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
- select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index 9aff937..3dbaa19 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -11,5 +11,6 @@
obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 9837595..b111903 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -47,6 +47,9 @@
/* ------------------------------------------------------------------ */
/* board config info */
+/* If radio_type !=UNSET, radio_addr should be specified
+ */
+
struct saa7134_board saa7134_boards[] = {
[SAA7134_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
@@ -3087,7 +3090,7 @@
.tuner_type = TUNER_PHILIPS_TD1316, /* untested */
.radio_type = TUNER_TEA5767, /* untested */
.tuner_addr = ADDR_UNSET,
- .radio_addr = ADDR_UNSET,
+ .radio_addr = 0x60,
.tda9887_conf = TDA9887_PRESENT,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
@@ -4247,6 +4250,36 @@
.amux = LINE1,
} },
},
+ [SAA7134_BOARD_BEHOLD_H6] = {
+ /* Igor Kuznetsov <igk@igk.ru> */
+ .name = "Beholder BeholdTV H6",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ /* no DVB support for now */
+ /* .mpeg = SAA7134_MPEG_DVB, */
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -5197,6 +5230,12 @@
.subvendor = 0x5ace,
.subdevice = 0x6193,
.driver_data = SAA7134_BOARD_BEHOLD_M6,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6191,
+ .driver_data = SAA7134_BOARD_BEHOLD_M6,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
@@ -5246,6 +5285,12 @@
.subdevice = 0xc900,
.driver_data = SAA7134_BOARD_VIDEOMATE_T750,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace,
+ .subdevice = 0x6290,
+ .driver_data = SAA7134_BOARD_BEHOLD_H6,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -5577,20 +5622,87 @@
return 0;
}
+static void saa7134_tuner_setup(struct saa7134_dev *dev)
+{
+ struct tuner_setup tun_setup;
+ unsigned int mode_mask = T_RADIO |
+ T_ANALOG_TV |
+ T_DIGITAL_TV;
+
+ memset(&tun_setup, 0, sizeof(tun_setup));
+ tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ if (saa7134_boards[dev->board].radio_type != UNSET) {
+ tun_setup.type = saa7134_boards[dev->board].radio_type;
+ tun_setup.addr = saa7134_boards[dev->board].radio_addr;
+
+ tun_setup.mode_mask = T_RADIO;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ mode_mask &= ~T_RADIO;
+ }
+
+ if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type != UNSET)) {
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = dev->tuner_addr;
+ tun_setup.config = saa7134_boards[dev->board].tuner_config;
+ tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ tun_setup.mode_mask = mode_mask;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
+ if (dev->tda9887_conf) {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
+ &tda9887_cfg);
+ }
+
+ if (dev->tuner_type == TUNER_XC2028) {
+ struct v4l2_priv_tun_config xc2028_cfg;
+ struct xc2028_ctrl ctl;
+
+ memset(&xc2028_cfg, 0, sizeof(ctl));
+ memset(&ctl, 0, sizeof(ctl));
+
+ ctl.fname = XC2028_DEFAULT_FIRMWARE;
+ ctl.max_len = 64;
+
+ switch (dev->board) {
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ ctl.demod = XC3028_FE_ZARLINK456;
+ break;
+ default:
+ ctl.demod = XC3028_FE_OREN538;
+ ctl.mts = 1;
+ }
+
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
+ }
+}
+
/* stuff which needs working i2c */
int saa7134_board_init2(struct saa7134_dev *dev)
{
unsigned char buf;
int board;
- struct tuner_setup tun_setup;
- tun_setup.config = 0;
- tun_setup.tuner_callback = saa7134_tuner_callback;
+
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ dev->tuner_addr = saa7134_boards[dev->board].tuner_addr;
switch (dev->board) {
case SAA7134_BOARD_BMK_MPEX_NOTUNER:
case SAA7134_BOARD_BMK_MPEX_TUNER:
dev->i2c_client.addr = 0x60;
- board = (i2c_master_recv(&dev->i2c_client,&buf,0) < 0)
+ board = (i2c_master_recv(&dev->i2c_client, &buf, 0) < 0)
? SAA7134_BOARD_BMK_MPEX_NOTUNER
: SAA7134_BOARD_BMK_MPEX_TUNER;
if (board == dev->board)
@@ -5600,21 +5712,9 @@
saa7134_boards[dev->board].name);
dev->tuner_type = saa7134_boards[dev->board].tuner_type;
- if (TUNER_ABSENT != dev->tuner_type) {
- tun_setup.mode_mask = T_RADIO |
- T_ANALOG_TV |
- T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = ADDR_UNSET;
- tun_setup.tuner_callback = saa7134_tuner_callback;
-
- saa7134_i2c_call_clients(dev,
- TUNER_SET_TYPE_ADDR,
- &tun_setup);
- }
break;
case SAA7134_BOARD_MD7134:
- {
+ {
u8 subaddr;
u8 data[3];
int ret, tuner_t;
@@ -5667,30 +5767,8 @@
}
printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type);
- if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
-
- dev->tda9887_conf = TDA9887_PRESENT |
- TDA9887_PORT1_ACTIVE |
- TDA9887_PORT2_ACTIVE;
-
- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG,
- &tda9887_cfg);
- }
-
- tun_setup.mode_mask = T_RADIO |
- T_ANALOG_TV |
- T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = ADDR_UNSET;
-
- saa7134_i2c_call_clients(dev,
- TUNER_SET_TYPE_ADDR, &tun_setup);
- }
break;
+ }
case SAA7134_BOARD_PHILIPS_EUROPA:
if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) {
/* Reconfigure board as Snake reference design */
@@ -5702,43 +5780,43 @@
}
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+ {
+
/* The Philips EUROPA based hybrid boards have the tuner connected through
* the channel decoder. We have to make it transparent to find it
*/
- {
u8 data[] = { 0x07, 0x02};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = dev->tuner_addr;
-
- saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
- }
break;
+ }
case SAA7134_BOARD_PHILIPS_TIGER:
case SAA7134_BOARD_PHILIPS_TIGER_S:
- {
+ {
u8 data[] = { 0x3c, 0x33, 0x60};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
- if(dev->autodetected && (dev->eedata[0x49] == 0x50)) {
+ if (dev->autodetected && (dev->eedata[0x49] == 0x50)) {
dev->board = SAA7134_BOARD_PHILIPS_TIGER_S;
printk(KERN_INFO "%s: Reconfigured board as %s\n",
dev->name, saa7134_boards[dev->board].name);
}
- if(dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
- tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = TUNER_PHILIPS_TDA8290;
- tun_setup.addr = 0x4b;
- tun_setup.config = 2;
+ if (dev->board == SAA7134_BOARD_PHILIPS_TIGER_S) {
+ dev->tuner_type = TUNER_PHILIPS_TDA8290;
- saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+ saa7134_tuner_setup(dev);
+
data[2] = 0x68;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+
+ /* Tuner setup is handled before I2C transfer.
+ Due to that, there's no need to do it later
+ */
+ return 0;
}
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
hauppauge_eeprom(dev, dev->eedata+0x80);
/* break intentionally omitted */
@@ -5751,52 +5829,55 @@
case SAA7134_BOARD_AVERMEDIA_SUPER_007:
case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
case SAA7134_BOARD_CREATIX_CTX953:
+ {
/* this is a hybrid board, initialize to analog mode
* and configure firmware eeprom address
*/
- {
u8 data[] = { 0x3c, 0x33, 0x60};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_FLYDVB_TRIO:
- {
+ {
u8 data[] = { 0x3c, 0x33, 0x62};
struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
+ {
/* initialize analog mode */
- {
u8 data[] = { 0x3c, 0x33, 0x6a};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
case SAA7134_BOARD_CINERGY_HT_PCI:
+ {
/* initialize analog mode */
- {
u8 data[] = { 0x3c, 0x33, 0x68};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- }
break;
+ }
case SAA7134_BOARD_KWORLD_ATSC110:
- {
- /* enable tuner */
- int i;
- static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 };
- dev->i2c_client.addr = 0x0a;
- for (i = 0; i < 5; i++)
- if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2))
- printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n",
- dev->name, i);
- }
+ {
+ /* enable tuner */
+ int i;
+ static const u8 buffer [] = { 0x10, 0x12, 0x13, 0x04, 0x16,
+ 0x00, 0x14, 0x04, 0x17, 0x00 };
+ dev->i2c_client.addr = 0x0a;
+ for (i = 0; i < 5; i++)
+ if (2 != i2c_master_send(&dev->i2c_client,
+ &buffer[i*2], 2))
+ printk(KERN_WARNING
+ "%s: Unable to enable tuner(%i).\n",
+ dev->name, i);
break;
+ }
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
/* The T200 and the T200A share the same pci id. Consequently,
@@ -5821,7 +5902,7 @@
}
break;
case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
- {
+ {
struct v4l2_priv_tun_config tea5767_cfg;
struct tea5767_ctrl ctl;
@@ -5832,34 +5913,11 @@
tea5767_cfg.tuner = TUNER_TEA5767;
tea5767_cfg.priv = &ctl;
saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg);
- }
break;
}
+ } /* switch() */
- if (dev->tuner_type == TUNER_XC2028) {
- struct v4l2_priv_tun_config xc2028_cfg;
- struct xc2028_ctrl ctl;
-
- memset(&xc2028_cfg, 0, sizeof(ctl));
- memset(&ctl, 0, sizeof(ctl));
-
- ctl.fname = XC2028_DEFAULT_FIRMWARE;
- ctl.max_len = 64;
-
- switch (dev->board) {
- case SAA7134_BOARD_AVERMEDIA_A16D:
- ctl.demod = XC3028_FE_ZARLINK456;
- break;
- default:
- ctl.demod = XC3028_FE_OREN538;
- ctl.mts = 1;
- }
-
- xc2028_cfg.tuner = TUNER_XC2028;
- xc2028_cfg.priv = &ctl;
-
- saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
- }
+ saa7134_tuner_setup(dev);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 2ccfaba..d8af386 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -324,8 +324,6 @@
static int attach_inform(struct i2c_client *client)
{
struct saa7134_dev *dev = client->adapter->algo_data;
- int tuner = dev->tuner_type;
- struct tuner_setup tun_setup;
d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
client->driver->driver.name, client->addr, client->name);
@@ -346,46 +344,6 @@
}
}
- if (!client->driver->command)
- return 0;
-
- if (saa7134_boards[dev->board].radio_type != UNSET) {
-
- tun_setup.type = saa7134_boards[dev->board].radio_type;
- tun_setup.addr = saa7134_boards[dev->board].radio_addr;
-
- if ((tun_setup.addr == ADDR_UNSET) || (tun_setup.addr == client->addr)) {
- tun_setup.mode_mask = T_RADIO;
-
- client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup);
- }
- }
-
- if (tuner != UNSET) {
- tun_setup.type = tuner;
- tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
- tun_setup.config = saa7134_boards[dev->board].tuner_config;
- tun_setup.tuner_callback = saa7134_tuner_callback;
-
- if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
-
- tun_setup.mode_mask = T_ANALOG_TV;
-
- client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
- }
-
- if (tuner == TUNER_TDA9887) {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
-
- client->driver->command(client, TUNER_SET_CONFIG,
- &tda9887_cfg);
- }
- }
-
-
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 767ff30..919632b 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -531,6 +531,7 @@
break;
case SAA7134_BOARD_BEHOLD_607_9FM:
case SAA7134_BOARD_BEHOLD_M6:
+ case SAA7134_BOARD_BEHOLD_H6:
snprintf(ir->c.name, sizeof(ir->c.name), "BeholdTV");
ir->get_key = get_key_beholdm6xx;
ir->ir_codes = ir_codes_behold;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 924ffd1..34ff0d4 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -263,6 +263,7 @@
#define SAA7134_BOARD_VIDEOMATE_T750 139
#define SAA7134_BOARD_AVERMEDIA_A700_PRO 140
#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
+#define SAA7134_BOARD_BEHOLD_H6 142
#define SAA7134_MAXBOARDS 8
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
index 53c5edb..72c4081 100644
--- a/drivers/media/video/saa717x.c
+++ b/drivers/media/video/saa717x.c
@@ -1418,7 +1418,8 @@
/* i2c implementation */
/* ----------------------------------------------------------------------- */
-static int saa717x_probe(struct i2c_client *client)
+static int saa717x_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct saa717x_state *decoder;
u8 id = 0;
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
index 6943b44..e57a646 100644
--- a/drivers/media/video/tcm825x.c
+++ b/drivers/media/video/tcm825x.c
@@ -840,7 +840,8 @@
},
};
-static int tcm825x_probe(struct i2c_client *client)
+static int tcm825x_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
{
struct tcm825x_sensor *sensor = &tcm825x;
int rval;
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
index dc7b9c2..f1db542 100644
--- a/drivers/media/video/tlv320aic23b.c
+++ b/drivers/media/video/tlv320aic23b.c
@@ -125,7 +125,8 @@
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int tlv320aic23b_probe(struct i2c_client *client)
+static int tlv320aic23b_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tlv320aic23b_state *state;
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 2b72e10..6bf104e 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -33,6 +33,46 @@
#define PREFIX t->i2c->driver->driver.name
+/** This macro allows us to probe dynamically, avoiding static links */
+#ifdef CONFIG_MEDIA_ATTACH
+#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
+ int __r = -EINVAL; \
+ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+ if (__a) { \
+ __r = (int) __a(ARGS); \
+ } else { \
+ printk(KERN_ERR "TUNER: Unable to find " \
+ "symbol "#FUNCTION"()\n"); \
+ } \
+ symbol_put(FUNCTION); \
+ __r; \
+})
+
+static void tuner_detach(struct dvb_frontend *fe)
+{
+ if (fe->ops.tuner_ops.release) {
+ fe->ops.tuner_ops.release(fe);
+ symbol_put_addr(fe->ops.tuner_ops.release);
+ }
+ if (fe->ops.analog_ops.release) {
+ fe->ops.analog_ops.release(fe);
+ symbol_put_addr(fe->ops.analog_ops.release);
+ }
+}
+#else
+#define tuner_symbol_probe(FUNCTION, ARGS...) ({ \
+ FUNCTION(ARGS); \
+})
+
+static void tuner_detach(struct dvb_frontend *fe)
+{
+ if (fe->ops.tuner_ops.release)
+ fe->ops.tuner_ops.release(fe);
+ if (fe->ops.analog_ops.release)
+ fe->ops.analog_ops.release(fe);
+}
+#endif
+
struct tuner {
/* device */
struct dvb_frontend fe;
@@ -56,7 +96,7 @@
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
-#if defined(CONFIG_TUNER_TEA5761) || (defined(CONFIG_TUNER_TEA5761_MODULE) && defined(MODULE))
+#if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE))
0x10,
#endif
0x42, 0x43, 0x4a, 0x4b, /* tda8290 */
@@ -139,22 +179,6 @@
fe_tuner_ops->set_analog_params(fe, params);
}
-static void fe_release(struct dvb_frontend *fe)
-{
- if (fe->ops.tuner_ops.release)
- fe->ops.tuner_ops.release(fe);
-
- /* DO NOT kfree(fe->analog_demod_priv)
- *
- * If we are in this function, analog_demod_priv contains a pointer
- * to struct tuner *t. This will be kfree'd in tuner_detach().
- *
- * Otherwise, fe->ops.analog_demod_ops->release will
- * handle the cleanup for analog demodulator modules.
- */
- fe->analog_demod_priv = NULL;
-}
-
static void fe_standby(struct dvb_frontend *fe)
{
struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
@@ -191,7 +215,6 @@
static struct analog_demod_ops tuner_core_ops = {
.set_params = fe_set_params,
.standby = fe_standby,
- .release = fe_release,
.has_signal = fe_has_signal,
.set_config = fe_set_config,
.tuner_status = tuner_status
@@ -323,7 +346,8 @@
.lna_cfg = t->config,
.tuner_callback = t->tuner_callback,
};
- tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
+ dvb_attach(tda829x_attach,
+ &t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
}
static struct xc5000_config xc5000_cfg;
@@ -356,12 +380,13 @@
}
/* discard private data, in case set_type() was previously called */
- if (analog_ops->release)
- analog_ops->release(&t->fe);
+ tuner_detach(&t->fe);
+ t->fe.analog_demod_priv = NULL;
switch (t->type) {
case TUNER_MT2032:
- microtune_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+ dvb_attach(microtune_attach,
+ &t->fe, t->i2c->adapter, t->i2c->addr);
break;
case TUNER_PHILIPS_TDA8290:
{
@@ -369,12 +394,14 @@
break;
}
case TUNER_TEA5767:
- if (!tea5767_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
+ if (!dvb_attach(tea5767_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr))
goto attach_failed;
t->mode_mask = T_RADIO;
break;
case TUNER_TEA5761:
- if (!tea5761_attach(&t->fe, t->i2c->adapter, t->i2c->addr))
+ if (!dvb_attach(tea5761_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr))
goto attach_failed;
t->mode_mask = T_RADIO;
break;
@@ -388,8 +415,8 @@
buffer[2] = 0x86;
buffer[3] = 0x54;
i2c_master_send(c, buffer, 4);
- if (!simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
- t->type))
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
goto attach_failed;
break;
case TUNER_PHILIPS_TD1316:
@@ -397,9 +424,9 @@
buffer[1] = 0xdc;
buffer[2] = 0x86;
buffer[3] = 0xa4;
- i2c_master_send(c,buffer,4);
- if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
- t->i2c->addr, t->type))
+ i2c_master_send(c, buffer, 4);
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
goto attach_failed;
break;
case TUNER_XC2028:
@@ -409,12 +436,13 @@
.i2c_addr = t->i2c->addr,
.callback = t->tuner_callback,
};
- if (!xc2028_attach(&t->fe, &cfg))
+ if (!dvb_attach(xc2028_attach, &t->fe, &cfg))
goto attach_failed;
break;
}
case TUNER_TDA9887:
- tda9887_attach(&t->fe, t->i2c->adapter, t->i2c->addr);
+ dvb_attach(tda9887_attach,
+ &t->fe, t->i2c->adapter, t->i2c->addr);
break;
case TUNER_XC5000:
{
@@ -424,7 +452,8 @@
xc5000_cfg.if_khz = 5380;
xc5000_cfg.priv = c->adapter->algo_data;
xc5000_cfg.tuner_callback = t->tuner_callback;
- if (!xc5000_attach(&t->fe, t->i2c->adapter, &xc5000_cfg))
+ if (!dvb_attach(xc5000_attach,
+ &t->fe, t->i2c->adapter, &xc5000_cfg))
goto attach_failed;
xc_tuner_ops = &t->fe.ops.tuner_ops;
@@ -433,8 +462,8 @@
break;
}
default:
- if (!simple_tuner_attach(&t->fe, t->i2c->adapter,
- t->i2c->addr, t->type))
+ if (!dvb_attach(simple_tuner_attach, &t->fe,
+ t->i2c->adapter, t->i2c->addr, t->type))
goto attach_failed;
break;
@@ -442,12 +471,14 @@
if ((NULL == analog_ops->set_params) &&
(fe_tuner_ops->set_analog_params)) {
+
strlcpy(t->i2c->name, fe_tuner_ops->info.name,
sizeof(t->i2c->name));
t->fe.analog_demod_priv = t;
memcpy(analog_ops, &tuner_core_ops,
sizeof(struct analog_demod_ops));
+
} else {
strlcpy(t->i2c->name, analog_ops->info.name,
sizeof(t->i2c->name));
@@ -645,8 +676,8 @@
{
struct tuner *t = fe->analog_demod_priv;
unsigned long freq, freq_fraction;
- struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
- struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
+ struct dvb_tuner_ops *fe_tuner_ops = &fe->ops.tuner_ops;
+ struct analog_demod_ops *analog_ops = &fe->ops.analog_ops;
const char *p;
switch (t->mode) {
@@ -730,8 +761,10 @@
struct dvb_tuner_ops *fe_tuner_ops = &t->fe.ops.tuner_ops;
struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- if (tuner_debug>1)
+ if (tuner_debug > 1) {
v4l_i2c_print_ioctl(client,cmd);
+ printk("\n");
+ }
switch (cmd) {
/* --- configuration --- */
@@ -1073,7 +1106,8 @@
/* During client attach, set_type is called by adapter's attach_inform callback.
set_type must then be completed by tuner_probe.
*/
-static int tuner_probe(struct i2c_client *client)
+static int tuner_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct tuner *t;
struct tuner *radio;
@@ -1111,8 +1145,9 @@
if (!no_autodetect) {
switch (client->addr) {
case 0x10:
- if (tea5761_autodetection(t->i2c->adapter,
- t->i2c->addr) >= 0) {
+ if (tuner_symbol_probe(tea5761_autodetection,
+ t->i2c->adapter,
+ t->i2c->addr) >= 0) {
t->type = TUNER_TEA5761;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
@@ -1131,8 +1166,8 @@
case 0x4b:
/* If chip is not tda8290, don't register.
since it can be tda9887*/
- if (tda829x_probe(t->i2c->adapter,
- t->i2c->addr) == 0) {
+ if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter,
+ t->i2c->addr) == 0) {
tuner_dbg("tda829x detected\n");
} else {
/* Default is being tda9887 */
@@ -1144,7 +1179,8 @@
}
break;
case 0x60:
- if (tea5767_autodetection(t->i2c->adapter, t->i2c->addr)
+ if (tuner_symbol_probe(tea5767_autodetection,
+ t->i2c->adapter, t->i2c->addr)
!= EINVAL) {
t->type = TUNER_TEA5767;
t->mode_mask = T_RADIO;
@@ -1233,10 +1269,9 @@
static int tuner_remove(struct i2c_client *client)
{
struct tuner *t = i2c_get_clientdata(client);
- struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops;
- if (analog_ops->release)
- analog_ops->release(&t->fe);
+ tuner_detach(&t->fe);
+ t->fe.analog_demod_priv = NULL;
list_del(&t->list);
kfree(t);
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index f29a2cd..6f9945b 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -1461,7 +1461,7 @@
/* ---------------------------------------------------------------------- */
/* i2c registration */
-static int chip_probe(struct i2c_client *client)
+static int chip_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct CHIPSTATE *chip;
struct CHIPDESC *desc;
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index bd20139..93bfd19d 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -195,7 +195,8 @@
/* i2c implementation */
-static int upd64031a_probe(struct i2c_client *client)
+static int upd64031a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct upd64031a_state *state;
int i;
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index 2d9a88f..9ab712a 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -172,7 +172,8 @@
/* i2c implementation */
-static int upd64083_probe(struct i2c_client *client)
+static int upd64083_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct upd64083_state *state;
int i;
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 6481935..17f542d 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -70,12 +70,6 @@
#define VICAM_HEADER_SIZE 64
-#define clamp( x, l, h ) max_t( __typeof__( x ), \
- ( l ), \
- min_t( __typeof__( x ), \
- ( h ), \
- ( x ) ) )
-
/* Not sure what all the bytes in these char
* arrays do, but they're necessary to make
* the camera work.
diff --git a/drivers/media/video/usbvision/Kconfig b/drivers/media/video/usbvision/Kconfig
index fc24ef0..74e1d30 100644
--- a/drivers/media/video/usbvision/Kconfig
+++ b/drivers/media/video/usbvision/Kconfig
@@ -1,7 +1,7 @@
config VIDEO_USBVISION
tristate "USB video devices based on Nogatech NT1003/1004/1005"
depends on I2C && VIDEO_V4L2
- select VIDEO_TUNER
+ select MEDIA_TUNER
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
---help---
There are more than 50 different USB video devices based on
diff --git a/drivers/media/video/usbvision/Makefile b/drivers/media/video/usbvision/Makefile
index 9ac92a8..3387187 100644
--- a/drivers/media/video/usbvision/Makefile
+++ b/drivers/media/video/usbvision/Makefile
@@ -3,3 +3,4 @@
obj-$(CONFIG_VIDEO_USBVISION) += usbvision.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 7cc42c1..e9dd996 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -710,7 +710,8 @@
/* Helper function for I2C legacy drivers */
int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
- const char *name, int (*probe)(struct i2c_client *))
+ const char *name,
+ int (*probe)(struct i2c_client *, const struct i2c_device_id *))
{
struct i2c_client *client;
int err;
@@ -724,7 +725,7 @@
client->driver = driver;
strlcpy(client->name, name, sizeof(client->name));
- err = probe(client);
+ err = probe(client, NULL);
if (err == 0) {
i2c_attach_client(client);
} else {
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
index 282c8140..fac0deb 100644
--- a/drivers/media/video/vp27smpx.c
+++ b/drivers/media/video/vp27smpx.c
@@ -121,7 +121,8 @@
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int vp27smpx_probe(struct i2c_client *client)
+static int vp27smpx_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct vp27smpx_state *state;
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index 31795b4f..0f8ed84 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -261,7 +261,8 @@
/* i2c implementation */
-static int wm8739_probe(struct i2c_client *client)
+static int wm8739_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct wm8739_state *state;
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 869f9e7..67a409e 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -159,7 +159,8 @@
* concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
*/
-static int wm8775_probe(struct i2c_client *client)
+static int wm8775_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct wm8775_state *state;
diff --git a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c
index 328ed6e..870bc5a 100644
--- a/drivers/media/video/zoran_procfs.c
+++ b/drivers/media/video/zoran_procfs.c
@@ -180,6 +180,7 @@
}
static const struct file_operations zoran_operations = {
+ .owner = THIS_MODULE,
.open = zoran_open,
.read = seq_read,
.write = zoran_write,
@@ -195,10 +196,8 @@
char name[8];
snprintf(name, 7, "zoran%d", zr->id);
- if ((zr->zoran_proc = create_proc_entry(name, 0, NULL))) {
- zr->zoran_proc->data = zr;
- zr->zoran_proc->owner = THIS_MODULE;
- zr->zoran_proc->proc_fops = &zoran_operations;
+ zr->zoran_proc = proc_create_data(name, 0, NULL, &zoran_operations, zr);
+ if (zr->zoran_proc != NULL) {
dprintk(2,
KERN_INFO
"%s: procfs entry /proc/%s allocated. data=%p\n",
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index a953148..81483de 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -371,7 +371,7 @@
/* connect the i2o_block_request to the request */
if (!req->special) {
ireq = i2o_block_request_alloc();
- if (unlikely(IS_ERR(ireq))) {
+ if (IS_ERR(ireq)) {
osm_debug("unable to allocate i2o_block_request!\n");
return BLKPREP_DEFER;
}
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
index 6fdd072..54a3016 100644
--- a/drivers/message/i2o/i2o_proc.c
+++ b/drivers/message/i2o/i2o_proc.c
@@ -1893,13 +1893,11 @@
struct proc_dir_entry *tmp;
while (i2o_pe->name) {
- tmp = create_proc_entry(i2o_pe->name, i2o_pe->mode, dir);
+ tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir,
+ i2o_pe->fops, data);
if (!tmp)
return -1;
- tmp->data = data;
- tmp->proc_fops = i2o_pe->fops;
-
i2o_pe++;
}
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index f6f2d96..ef8a492 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -132,7 +132,7 @@
if (iter >= MAX_ASIC_ISR_LOOPS)
printk(KERN_ERR "%s: interrupt processing overrun\n",
- __FUNCTION__);
+ __func__);
}
static inline int asic3_irq_to_bank(struct asic3 *asic, int irq)
@@ -409,7 +409,7 @@
return asic3_get_gpio_d(asic, Status) & mask;
default:
printk(KERN_ERR "%s: invalid GPIO value 0x%x",
- __FUNCTION__, gpio);
+ __func__, gpio);
return -EINVAL;
}
}
@@ -437,7 +437,7 @@
return;
default:
printk(KERN_ERR "%s: invalid GPIO value 0x%x",
- __FUNCTION__, gpio);
+ __func__, gpio);
return;
}
}
diff --git a/drivers/mfd/htc-pasic3.c b/drivers/mfd/htc-pasic3.c
index 4edc120..633cbba 100644
--- a/drivers/mfd/htc-pasic3.c
+++ b/drivers/mfd/htc-pasic3.c
@@ -132,8 +132,9 @@
.disable = ds1wm_disable,
};
-static int ds1wm_device_add(struct device *pasic3_dev, int bus_shift)
+static int ds1wm_device_add(struct platform_device *pasic3_pdev, int bus_shift)
{
+ struct device *pasic3_dev = &pasic3_pdev->dev;
struct pasic3_data *asic = pasic3_dev->driver_data;
struct platform_device *pdev;
int ret;
@@ -144,8 +145,8 @@
return -ENOMEM;
}
- ret = platform_device_add_resources(pdev, pdev->resource,
- pdev->num_resources);
+ ret = platform_device_add_resources(pdev, pasic3_pdev->resource,
+ pasic3_pdev->num_resources);
if (ret < 0) {
dev_dbg(pasic3_dev, "failed to add DS1WM resources\n");
goto exit_pdev_put;
@@ -207,7 +208,7 @@
return -ENOMEM;
}
- ret = ds1wm_device_add(dev, asic->bus_shift);
+ ret = ds1wm_device_add(pdev, asic->bus_shift);
if (ret < 0)
dev_warn(dev, "failed to register DS1WM\n");
diff --git a/drivers/mfd/sm501.c b/drivers/mfd/sm501.c
index 6e655b4..2fe6473 100644
--- a/drivers/mfd/sm501.c
+++ b/drivers/mfd/sm501.c
@@ -349,11 +349,11 @@
mode &= 3; /* get current power mode */
if (unit >= ARRAY_SIZE(sm->unit_power)) {
- dev_err(dev, "%s: bad unit %d\n", __FUNCTION__, unit);
+ dev_err(dev, "%s: bad unit %d\n", __func__, unit);
goto already;
}
- dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __FUNCTION__, unit,
+ dev_dbg(sm->dev, "%s: unit %d, cur %d, to %d\n", __func__, unit,
sm->unit_power[unit], to);
if (to == 0 && sm->unit_power[unit] == 0) {
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 297a48f..636af28 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -140,6 +140,7 @@
depends on EXPERIMENTAL
depends on ACPI
depends on LEDS_CLASS
+ depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
depends on SERIO_I8042
select ACPI_WMI
@@ -160,6 +161,7 @@
depends on ACPI
depends on EXPERIMENTAL && !ACPI_ASUS
depends on LEDS_CLASS
+ depends on NEW_LEDS
depends on BACKLIGHT_CLASS_DEVICE
---help---
This is the new Linux driver for Asus laptops. It may also support some
@@ -241,10 +243,13 @@
config THINKPAD_ACPI
tristate "ThinkPad ACPI Laptop Extras"
depends on X86 && ACPI
+ select BACKLIGHT_LCD_SUPPORT
select BACKLIGHT_CLASS_DEVICE
select HWMON
select NVRAM
- depends on INPUT
+ select INPUT
+ select NEW_LEDS
+ select LEDS_CLASS
---help---
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
support for Fn-Fx key combinations, Bluetooth control, video
@@ -344,6 +349,7 @@
config INTEL_MENLOW
tristate "Thermal Management driver for Intel menlow platform"
depends on ACPI_THERMAL
+ select THERMAL
depends on X86
---help---
ACPI thermal management enhancement driver on
@@ -351,6 +357,19 @@
If unsure, say N.
+config EEEPC_LAPTOP
+ tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
+ depends on X86
+ depends on ACPI
+ depends on BACKLIGHT_CLASS_DEVICE
+ depends on HWMON
+ depends on EXPERIMENTAL
+ ---help---
+ This driver supports the Fn-Fx keys on Eee PC laptops.
+ It also adds the ability to switch camera/wlan on/off.
+
+ If you have an Eee PC laptop, say Y or M here.
+
config ENCLOSURE_SERVICES
tristate "Enclosure Services"
default n
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 5914da4..1952875 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -7,7 +7,8 @@
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
-obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
+obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o
obj-$(CONFIG_ATMEL_PWM) += atmel_pwm.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
diff --git a/drivers/misc/eeepc-laptop.c b/drivers/misc/eeepc-laptop.c
new file mode 100644
index 0000000..6d72760
--- /dev/null
+++ b/drivers/misc/eeepc-laptop.c
@@ -0,0 +1,666 @@
+/*
+ * eepc-laptop.c - Asus Eee PC extras
+ *
+ * Based on asus_acpi.c as patched for the Eee PC by Asus:
+ * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar
+ * Based on eee.c from eeepc-linux
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/platform_device.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <linux/uaccess.h>
+
+#define EEEPC_LAPTOP_VERSION "0.1"
+
+#define EEEPC_HOTK_NAME "Eee PC Hotkey Driver"
+#define EEEPC_HOTK_FILE "eeepc"
+#define EEEPC_HOTK_CLASS "hotkey"
+#define EEEPC_HOTK_DEVICE_NAME "Hotkey"
+#define EEEPC_HOTK_HID "ASUS010"
+
+#define EEEPC_LOG EEEPC_HOTK_FILE ": "
+#define EEEPC_ERR KERN_ERR EEEPC_LOG
+#define EEEPC_WARNING KERN_WARNING EEEPC_LOG
+#define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG
+#define EEEPC_INFO KERN_INFO EEEPC_LOG
+
+/*
+ * Definitions for Asus EeePC
+ */
+#define NOTIFY_WLAN_ON 0x10
+#define NOTIFY_BRN_MIN 0x20
+#define NOTIFY_BRN_MAX 0x2f
+
+enum {
+ DISABLE_ASL_WLAN = 0x0001,
+ DISABLE_ASL_BLUETOOTH = 0x0002,
+ DISABLE_ASL_IRDA = 0x0004,
+ DISABLE_ASL_CAMERA = 0x0008,
+ DISABLE_ASL_TV = 0x0010,
+ DISABLE_ASL_GPS = 0x0020,
+ DISABLE_ASL_DISPLAYSWITCH = 0x0040,
+ DISABLE_ASL_MODEM = 0x0080,
+ DISABLE_ASL_CARDREADER = 0x0100
+};
+
+enum {
+ CM_ASL_WLAN = 0,
+ CM_ASL_BLUETOOTH,
+ CM_ASL_IRDA,
+ CM_ASL_1394,
+ CM_ASL_CAMERA,
+ CM_ASL_TV,
+ CM_ASL_GPS,
+ CM_ASL_DVDROM,
+ CM_ASL_DISPLAYSWITCH,
+ CM_ASL_PANELBRIGHT,
+ CM_ASL_BIOSFLASH,
+ CM_ASL_ACPIFLASH,
+ CM_ASL_CPUFV,
+ CM_ASL_CPUTEMPERATURE,
+ CM_ASL_FANCPU,
+ CM_ASL_FANCHASSIS,
+ CM_ASL_USBPORT1,
+ CM_ASL_USBPORT2,
+ CM_ASL_USBPORT3,
+ CM_ASL_MODEM,
+ CM_ASL_CARDREADER,
+ CM_ASL_LID
+};
+
+const char *cm_getv[] = {
+ "WLDG", NULL, NULL, NULL,
+ "CAMG", NULL, NULL, NULL,
+ NULL, "PBLG", NULL, NULL,
+ "CFVG", NULL, NULL, NULL,
+ "USBG", NULL, NULL, "MODG",
+ "CRDG", "LIDG"
+};
+
+const char *cm_setv[] = {
+ "WLDS", NULL, NULL, NULL,
+ "CAMS", NULL, NULL, NULL,
+ "SDSP", "PBLS", "HDPS", NULL,
+ "CFVS", NULL, NULL, NULL,
+ "USBG", NULL, NULL, "MODS",
+ "CRDS", NULL
+};
+
+#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0."
+
+#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */
+#define EEEPC_EC_SC02 0x63
+#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */
+#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */
+#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */
+#define EEEPC_EC_SFB3 0xD3
+
+/*
+ * This is the main structure, we can use it to store useful information
+ * about the hotk device
+ */
+struct eeepc_hotk {
+ struct acpi_device *device; /* the device we are in */
+ acpi_handle handle; /* the handle of the hotk device */
+ u32 cm_supported; /* the control methods supported
+ by this BIOS */
+ uint init_flag; /* Init flags */
+ u16 event_count[128]; /* count for each event */
+};
+
+/* The actual device the driver binds to */
+static struct eeepc_hotk *ehotk;
+
+/* Platform device/driver */
+static struct platform_driver platform_driver = {
+ .driver = {
+ .name = EEEPC_HOTK_FILE,
+ .owner = THIS_MODULE,
+ }
+};
+
+static struct platform_device *platform_device;
+
+/*
+ * The hotkey driver declaration
+ */
+static int eeepc_hotk_add(struct acpi_device *device);
+static int eeepc_hotk_remove(struct acpi_device *device, int type);
+
+static const struct acpi_device_id eeepc_device_ids[] = {
+ {EEEPC_HOTK_HID, 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
+
+static struct acpi_driver eeepc_hotk_driver = {
+ .name = EEEPC_HOTK_NAME,
+ .class = EEEPC_HOTK_CLASS,
+ .ids = eeepc_device_ids,
+ .ops = {
+ .add = eeepc_hotk_add,
+ .remove = eeepc_hotk_remove,
+ },
+};
+
+/* The backlight device /sys/class/backlight */
+static struct backlight_device *eeepc_backlight_device;
+
+/* The hwmon device */
+static struct device *eeepc_hwmon_device;
+
+/*
+ * The backlight class declaration
+ */
+static int read_brightness(struct backlight_device *bd);
+static int update_bl_status(struct backlight_device *bd);
+static struct backlight_ops eeepcbl_ops = {
+ .get_brightness = read_brightness,
+ .update_status = update_bl_status,
+};
+
+MODULE_AUTHOR("Corentin Chary, Eric Cooper");
+MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+/*
+ * ACPI Helpers
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+ struct acpi_buffer *output)
+{
+ struct acpi_object_list params;
+ union acpi_object in_obj;
+ acpi_status status;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = val;
+
+ status = acpi_evaluate_object(handle, (char *)method, ¶ms, output);
+ return (status == AE_OK ? 0 : -1);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val)
+{
+ acpi_status status;
+ ulong result;
+
+ status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
+ if (ACPI_FAILURE(status)) {
+ *val = -1;
+ return -1;
+ } else {
+ *val = result;
+ return 0;
+ }
+}
+
+static int set_acpi(int cm, int value)
+{
+ if (ehotk->cm_supported & (0x1 << cm)) {
+ const char *method = cm_setv[cm];
+ if (method == NULL)
+ return -ENODEV;
+ if (write_acpi_int(ehotk->handle, method, value, NULL))
+ printk(EEEPC_WARNING "Error writing %s\n", method);
+ }
+ return 0;
+}
+
+static int get_acpi(int cm)
+{
+ int value = -1;
+ if ((ehotk->cm_supported & (0x1 << cm))) {
+ const char *method = cm_getv[cm];
+ if (method == NULL)
+ return -ENODEV;
+ if (read_acpi_int(ehotk->handle, method, &value))
+ printk(EEEPC_WARNING "Error reading %s\n", method);
+ }
+ return value;
+}
+
+/*
+ * Backlight
+ */
+static int read_brightness(struct backlight_device *bd)
+{
+ return get_acpi(CM_ASL_PANELBRIGHT);
+}
+
+static int set_brightness(struct backlight_device *bd, int value)
+{
+ value = max(0, min(15, value));
+ return set_acpi(CM_ASL_PANELBRIGHT, value);
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+ return set_brightness(bd, bd->props.brightness);
+}
+
+/*
+ * Sys helpers
+ */
+static int parse_arg(const char *buf, unsigned long count, int *val)
+{
+ if (!count)
+ return 0;
+ if (sscanf(buf, "%i", val) != 1)
+ return -EINVAL;
+ return count;
+}
+
+static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set_acpi(cm, value);
+ return rv;
+}
+
+static ssize_t show_sys_acpi(int cm, char *buf)
+{
+ return sprintf(buf, "%d\n", get_acpi(cm));
+}
+
+#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
+ static ssize_t show_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ return show_sys_acpi(_cm, buf); \
+ } \
+ static ssize_t store_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ return store_sys_acpi(_cm, buf, count); \
+ } \
+ static struct device_attribute dev_attr_##_name = { \
+ .attr = { \
+ .name = __stringify(_name), \
+ .mode = 0644 }, \
+ .show = show_##_name, \
+ .store = store_##_name, \
+ }
+
+EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
+EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
+EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
+EEEPC_CREATE_DEVICE_ATTR(wlan, CM_ASL_WLAN);
+
+static struct attribute *platform_attributes[] = {
+ &dev_attr_camera.attr,
+ &dev_attr_cardr.attr,
+ &dev_attr_disp.attr,
+ &dev_attr_wlan.attr,
+ NULL
+};
+
+static struct attribute_group platform_attribute_group = {
+ .attrs = platform_attributes
+};
+
+/*
+ * Hotkey functions
+ */
+static int eeepc_hotk_check(void)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ int result;
+
+ result = acpi_bus_get_status(ehotk->device);
+ if (result)
+ return result;
+ if (ehotk->device->status.present) {
+ if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
+ &buffer)) {
+ printk(EEEPC_ERR "Hotkey initialization failed\n");
+ return -ENODEV;
+ } else {
+ printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
+ ehotk->init_flag);
+ }
+ /* get control methods supported */
+ if (read_acpi_int(ehotk->handle, "CMSG"
+ , &ehotk->cm_supported)) {
+ printk(EEEPC_ERR
+ "Get control methods supported failed\n");
+ return -ENODEV;
+ } else {
+ printk(EEEPC_INFO
+ "Get control methods supported: 0x%x\n",
+ ehotk->cm_supported);
+ }
+ } else {
+ printk(EEEPC_ERR "Hotkey device not present, aborting\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void notify_wlan(u32 *event)
+{
+ /* if DISABLE_ASL_WLAN is set, the notify code for fn+f2
+ will always be 0x10 */
+ if (ehotk->cm_supported & (0x1 << CM_ASL_WLAN)) {
+ const char *method = cm_getv[CM_ASL_WLAN];
+ int value;
+ if (read_acpi_int(ehotk->handle, method, &value))
+ printk(EEEPC_WARNING "Error reading %s\n",
+ method);
+ else if (value == 1)
+ *event = 0x11;
+ }
+}
+
+static void notify_brn(void)
+{
+ struct backlight_device *bd = eeepc_backlight_device;
+ bd->props.brightness = read_brightness(bd);
+}
+
+static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+ if (!ehotk)
+ return;
+ if (event == NOTIFY_WLAN_ON && (DISABLE_ASL_WLAN & ehotk->init_flag))
+ notify_wlan(&event);
+ if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
+ notify_brn();
+ acpi_bus_generate_proc_event(ehotk->device, event,
+ ehotk->event_count[event % 128]++);
+}
+
+static int eeepc_hotk_add(struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+ printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
+ ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
+ if (!ehotk)
+ return -ENOMEM;
+ ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
+ ehotk->handle = device->handle;
+ strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
+ strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
+ acpi_driver_data(device) = ehotk;
+ ehotk->device = device;
+ result = eeepc_hotk_check();
+ if (result)
+ goto end;
+ status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
+ eeepc_hotk_notify, ehotk);
+ if (ACPI_FAILURE(status))
+ printk(EEEPC_ERR "Error installing notify handler\n");
+ end:
+ if (result) {
+ kfree(ehotk);
+ ehotk = NULL;
+ }
+ return result;
+}
+
+static int eeepc_hotk_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+ status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
+ eeepc_hotk_notify);
+ if (ACPI_FAILURE(status))
+ printk(EEEPC_ERR "Error removing notify handler\n");
+ kfree(ehotk);
+ return 0;
+}
+
+/*
+ * Hwmon
+ */
+static int eeepc_get_fan_pwm(void)
+{
+ int value = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
+ return (value);
+}
+
+static void eeepc_set_fan_pwm(int value)
+{
+ value = SENSORS_LIMIT(value, 0, 100);
+ ec_write(EEEPC_EC_SC02, value);
+}
+
+static int eeepc_get_fan_rpm(void)
+{
+ int high = 0;
+ int low = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
+ read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
+ return (high << 8 | low);
+}
+
+static int eeepc_get_fan_ctrl(void)
+{
+ int value = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
+ return ((value & 0x02 ? 1 : 0));
+}
+
+static void eeepc_set_fan_ctrl(int manual)
+{
+ int value = 0;
+
+ read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
+ if (manual)
+ value |= 0x02;
+ else
+ value &= ~0x02;
+ ec_write(EEEPC_EC_SFB3, value);
+}
+
+static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
+{
+ int rv, value;
+
+ rv = parse_arg(buf, count, &value);
+ if (rv > 0)
+ set(value);
+ return rv;
+}
+
+static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
+{
+ return sprintf(buf, "%d\n", get());
+}
+
+#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
+ static ssize_t show_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
+ return show_sys_hwmon(_set, buf); \
+ } \
+ static ssize_t store_##_name(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+ { \
+ return store_sys_hwmon(_get, buf, count); \
+ } \
+ static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
+
+EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
+EEEPC_CREATE_SENSOR_ATTR(fan1_pwm, S_IRUGO | S_IWUSR,
+ eeepc_get_fan_pwm, eeepc_set_fan_pwm);
+EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
+ eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
+
+static struct attribute *hwmon_attributes[] = {
+ &sensor_dev_attr_fan1_pwm.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ NULL
+};
+
+static struct attribute_group hwmon_attribute_group = {
+ .attrs = hwmon_attributes
+};
+
+/*
+ * exit/init
+ */
+static void eeepc_backlight_exit(void)
+{
+ if (eeepc_backlight_device)
+ backlight_device_unregister(eeepc_backlight_device);
+ eeepc_backlight_device = NULL;
+}
+
+static void eeepc_hwmon_exit(void)
+{
+ struct device *hwmon;
+
+ hwmon = eeepc_hwmon_device;
+ if (!hwmon)
+ return ;
+ hwmon_device_unregister(hwmon);
+ sysfs_remove_group(&hwmon->kobj,
+ &hwmon_attribute_group);
+ eeepc_hwmon_device = NULL;
+}
+
+static void __exit eeepc_laptop_exit(void)
+{
+ eeepc_backlight_exit();
+ eeepc_hwmon_exit();
+ acpi_bus_unregister_driver(&eeepc_hotk_driver);
+ sysfs_remove_group(&platform_device->dev.kobj,
+ &platform_attribute_group);
+ platform_device_unregister(platform_device);
+ platform_driver_unregister(&platform_driver);
+}
+
+static int eeepc_backlight_init(struct device *dev)
+{
+ struct backlight_device *bd;
+
+ bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
+ NULL, &eeepcbl_ops);
+ if (IS_ERR(bd)) {
+ printk(EEEPC_ERR
+ "Could not register eeepc backlight device\n");
+ eeepc_backlight_device = NULL;
+ return PTR_ERR(bd);
+ }
+ eeepc_backlight_device = bd;
+ bd->props.max_brightness = 15;
+ bd->props.brightness = read_brightness(NULL);
+ bd->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(bd);
+ return 0;
+}
+
+static int eeepc_hwmon_init(struct device *dev)
+{
+ struct device *hwmon;
+ int result;
+
+ hwmon = hwmon_device_register(dev);
+ if (IS_ERR(hwmon)) {
+ printk(EEEPC_ERR
+ "Could not register eeepc hwmon device\n");
+ eeepc_hwmon_device = NULL;
+ return PTR_ERR(hwmon);
+ }
+ eeepc_hwmon_device = hwmon;
+ result = sysfs_create_group(&hwmon->kobj,
+ &hwmon_attribute_group);
+ if (result)
+ eeepc_hwmon_exit();
+ return result;
+}
+
+static int __init eeepc_laptop_init(void)
+{
+ struct device *dev;
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+ result = acpi_bus_register_driver(&eeepc_hotk_driver);
+ if (result < 0)
+ return result;
+ if (!ehotk) {
+ acpi_bus_unregister_driver(&eeepc_hotk_driver);
+ return -ENODEV;
+ }
+ dev = acpi_get_physical_device(ehotk->device->handle);
+ result = eeepc_backlight_init(dev);
+ if (result)
+ goto fail_backlight;
+ result = eeepc_hwmon_init(dev);
+ if (result)
+ goto fail_hwmon;
+ /* Register platform stuff */
+ result = platform_driver_register(&platform_driver);
+ if (result)
+ goto fail_platform_driver;
+ platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
+ if (!platform_device) {
+ result = -ENOMEM;
+ goto fail_platform_device1;
+ }
+ result = platform_device_add(platform_device);
+ if (result)
+ goto fail_platform_device2;
+ result = sysfs_create_group(&platform_device->dev.kobj,
+ &platform_attribute_group);
+ if (result)
+ goto fail_sysfs;
+ return 0;
+fail_sysfs:
+ platform_device_del(platform_device);
+fail_platform_device2:
+ platform_device_put(platform_device);
+fail_platform_device1:
+ platform_driver_unregister(&platform_driver);
+fail_platform_driver:
+ eeepc_hwmon_exit();
+fail_hwmon:
+ eeepc_backlight_exit();
+fail_backlight:
+ return result;
+}
+
+module_init(eeepc_laptop_init);
+module_exit(eeepc_laptop_exit);
diff --git a/drivers/misc/hdpuftrs/hdpu_cpustate.c b/drivers/misc/hdpuftrs/hdpu_cpustate.c
index 302e924..ff51ab6 100644
--- a/drivers/misc/hdpuftrs/hdpu_cpustate.c
+++ b/drivers/misc/hdpuftrs/hdpu_cpustate.c
@@ -210,13 +210,10 @@
return ret;
}
- proc_de = create_proc_entry("sky_cpustate", 0666, &proc_root);
+ proc_de = proc_create("sky_cpustate", 0666, NULL, &proc_cpustate);
if (!proc_de) {
printk(KERN_WARNING "sky_cpustate: "
"Unable to create proc entry\n");
- } else {
- proc_de->proc_fops = &proc_cpustate;
- proc_de->owner = THIS_MODULE;
}
printk(KERN_INFO "Sky CPU State Driver v" SKY_CPUSTATE_VERSION "\n");
diff --git a/drivers/misc/hdpuftrs/hdpu_nexus.c b/drivers/misc/hdpuftrs/hdpu_nexus.c
index 2fa36f7..08e26be 100644
--- a/drivers/misc/hdpuftrs/hdpu_nexus.c
+++ b/drivers/misc/hdpuftrs/hdpu_nexus.c
@@ -102,22 +102,17 @@
printk(KERN_ERR "sky_nexus: Could not map slot id\n");
}
- hdpu_slot_id = create_proc_entry("sky_slot_id", 0666, &proc_root);
+ hdpu_slot_id = proc_create("sky_slot_id", 0666, NULL, &proc_slot_id);
if (!hdpu_slot_id) {
printk(KERN_WARNING "sky_nexus: "
"Unable to create proc dir entry: sky_slot_id\n");
- } else {
- hdpu_slot_id->proc_fops = &proc_slot_id;
- hdpu_slot_id->owner = THIS_MODULE;
}
- hdpu_chassis_id = create_proc_entry("sky_chassis_id", 0666, &proc_root);
- if (!hdpu_chassis_id) {
+ hdpu_chassis_id = proc_create("sky_chassis_id", 0666, NULL,
+ &proc_chassis_id);
+ if (!hdpu_chassis_id)
printk(KERN_WARNING "sky_nexus: "
"Unable to create proc dir entry: sky_chassis_id\n");
- } else {
- hdpu_chassis_id->proc_fops = &proc_chassis_id;
- hdpu_chassis_id->owner = THIS_MODULE;
}
return 0;
@@ -128,8 +123,8 @@
slot_id = -1;
chassis_id = -1;
- remove_proc_entry("sky_slot_id", &proc_root);
- remove_proc_entry("sky_chassis_id", &proc_root);
+ remove_proc_entry("sky_slot_id", NULL);
+ remove_proc_entry("sky_chassis_id", NULL);
hdpu_slot_id = 0;
hdpu_chassis_id = 0;
diff --git a/drivers/misc/ibmasm/command.c b/drivers/misc/ibmasm/command.c
index 1a0e797..276d3fb 100644
--- a/drivers/misc/ibmasm/command.c
+++ b/drivers/misc/ibmasm/command.c
@@ -96,7 +96,7 @@
{
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
if (ibmasm_send_i2o_message(sp)) {
sp->current_command->status = IBMASM_CMD_FAILED;
@@ -119,7 +119,7 @@
unsigned long flags;
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
spin_lock_irqsave(&sp->lock, flags);
@@ -139,7 +139,7 @@
unsigned long flags;
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
spin_lock_irqsave(&sp->lock, flags);
sp->current_command = dequeue_command(sp);
diff --git a/drivers/misc/ibmasm/heartbeat.c b/drivers/misc/ibmasm/heartbeat.c
index 3036e78..1bc4306 100644
--- a/drivers/misc/ibmasm/heartbeat.c
+++ b/drivers/misc/ibmasm/heartbeat.c
@@ -75,9 +75,9 @@
{
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
ibmasm_wait_for_response(sp->heartbeat, IBMASM_CMD_TIMEOUT_NORMAL);
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
suspend_heartbeats = 1;
command_put(sp->heartbeat);
}
@@ -88,7 +88,7 @@
struct dot_command_header *header = (struct dot_command_header *)cmd->buffer;
char tsbuf[32];
- dbg("%s:%d at %s\n", __FUNCTION__, __LINE__, get_timestamp(tsbuf));
+ dbg("%s:%d at %s\n", __func__, __LINE__, get_timestamp(tsbuf));
if (suspend_heartbeats)
return;
diff --git a/drivers/misc/intel_menlow.c b/drivers/misc/intel_menlow.c
index 0c0bb30..80a1363 100644
--- a/drivers/misc/intel_menlow.c
+++ b/drivers/misc/intel_menlow.c
@@ -175,19 +175,17 @@
goto end;
}
- if (cdev) {
- acpi_driver_data(device) = cdev;
- result = sysfs_create_link(&device->dev.kobj,
- &cdev->device.kobj, "thermal_cooling");
- if (result)
- goto unregister;
+ acpi_driver_data(device) = cdev;
+ result = sysfs_create_link(&device->dev.kobj,
+ &cdev->device.kobj, "thermal_cooling");
+ if (result)
+ goto unregister;
- result = sysfs_create_link(&cdev->device.kobj,
- &device->dev.kobj, "device");
- if (result) {
- sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
- goto unregister;
- }
+ result = sysfs_create_link(&cdev->device.kobj,
+ &device->dev.kobj, "device");
+ if (result) {
+ sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
+ goto unregister;
}
end:
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
index 05172d2..6f76573 100644
--- a/drivers/misc/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -75,7 +75,7 @@
printk(KERN_WARNING
"%s: IOC4 submodule %s probe failed "
"for pci_dev %s",
- __FUNCTION__, module_name(is->is_owner),
+ __func__, module_name(is->is_owner),
pci_name(idd->idd_pdev));
}
}
@@ -102,7 +102,7 @@
printk(KERN_WARNING
"%s: IOC4 submodule %s remove failed "
"for pci_dev %s.\n",
- __FUNCTION__, module_name(is->is_owner),
+ __func__, module_name(is->is_owner),
pci_name(idd->idd_pdev));
}
}
@@ -282,7 +282,7 @@
if ((ret = pci_enable_device(pdev))) {
printk(KERN_WARNING
"%s: Failed to enable IOC4 device for pci_dev %s.\n",
- __FUNCTION__, pci_name(pdev));
+ __func__, pci_name(pdev));
goto out;
}
pci_set_master(pdev);
@@ -292,7 +292,7 @@
if (!idd) {
printk(KERN_WARNING
"%s: Failed to allocate IOC4 data for pci_dev %s.\n",
- __FUNCTION__, pci_name(pdev));
+ __func__, pci_name(pdev));
ret = -ENODEV;
goto out_idd;
}
@@ -307,7 +307,7 @@
printk(KERN_WARNING
"%s: Unable to find IOC4 misc resource "
"for pci_dev %s.\n",
- __FUNCTION__, pci_name(idd->idd_pdev));
+ __func__, pci_name(idd->idd_pdev));
ret = -ENODEV;
goto out_pci;
}
@@ -316,7 +316,7 @@
printk(KERN_WARNING
"%s: Unable to request IOC4 misc region "
"for pci_dev %s.\n",
- __FUNCTION__, pci_name(idd->idd_pdev));
+ __func__, pci_name(idd->idd_pdev));
ret = -ENODEV;
goto out_pci;
}
@@ -326,7 +326,7 @@
printk(KERN_WARNING
"%s: Unable to remap IOC4 misc region "
"for pci_dev %s.\n",
- __FUNCTION__, pci_name(idd->idd_pdev));
+ __func__, pci_name(idd->idd_pdev));
ret = -ENODEV;
goto out_misc_region;
}
@@ -372,7 +372,7 @@
printk(KERN_WARNING
"%s: IOC4 submodule 0x%s probe failed "
"for pci_dev %s.\n",
- __FUNCTION__, module_name(is->is_owner),
+ __func__, module_name(is->is_owner),
pci_name(idd->idd_pdev));
}
}
@@ -406,7 +406,7 @@
printk(KERN_WARNING
"%s: IOC4 submodule 0x%s remove failed "
"for pci_dev %s.\n",
- __FUNCTION__, module_name(is->is_owner),
+ __func__, module_name(is->is_owner),
pci_name(idd->idd_pdev));
}
}
@@ -418,7 +418,7 @@
printk(KERN_WARNING
"%s: Unable to get IOC4 misc mapping for pci_dev %s. "
"Device removal may be incomplete.\n",
- __FUNCTION__, pci_name(idd->idd_pdev));
+ __func__, pci_name(idd->idd_pdev));
}
release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
diff --git a/drivers/misc/kgdbts.c b/drivers/misc/kgdbts.c
index 6d6286c..30a1af8 100644
--- a/drivers/misc/kgdbts.c
+++ b/drivers/misc/kgdbts.c
@@ -132,7 +132,7 @@
static int final_ack;
static int hw_break_val;
static int hw_break_val2;
-#if defined(CONFIG_ARM) || defined(CONFIG_MIPS)
+#if defined(CONFIG_ARM) || defined(CONFIG_MIPS) || defined(CONFIG_SPARC)
static int arch_needs_sstep_emulation = 1;
#else
static int arch_needs_sstep_emulation;
diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c
index 7fa61e9..71d1c84 100644
--- a/drivers/misc/phantom.c
+++ b/drivers/misc/phantom.c
@@ -12,6 +12,7 @@
* or alternatively, you might use OpenHaptics provided by Sensable.
*/
+#include <linux/compat.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
@@ -91,11 +92,8 @@
unsigned long flags;
unsigned int i;
- if (_IOC_TYPE(cmd) != PH_IOC_MAGIC ||
- _IOC_NR(cmd) > PH_IOC_MAXNR)
- return -ENOTTY;
-
switch (cmd) {
+ case PHN_SETREG:
case PHN_SET_REG:
if (copy_from_user(&r, argp, sizeof(r)))
return -EFAULT;
@@ -126,6 +124,7 @@
phantom_status(dev, dev->status & ~PHB_RUNNING);
spin_unlock_irqrestore(&dev->regs_lock, flags);
break;
+ case PHN_SETREGS:
case PHN_SET_REGS:
if (copy_from_user(&rs, argp, sizeof(rs)))
return -EFAULT;
@@ -143,6 +142,7 @@
}
spin_unlock_irqrestore(&dev->regs_lock, flags);
break;
+ case PHN_GETREG:
case PHN_GET_REG:
if (copy_from_user(&r, argp, sizeof(r)))
return -EFAULT;
@@ -155,6 +155,7 @@
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
break;
+ case PHN_GETREGS:
case PHN_GET_REGS: {
u32 m;
@@ -168,6 +169,7 @@
for (i = 0; i < m; i++)
if (rs.mask & BIT(i))
rs.values[i] = ioread32(dev->iaddr + i);
+ atomic_set(&dev->counter, 0);
spin_unlock_irqrestore(&dev->regs_lock, flags);
if (copy_to_user(argp, &rs, sizeof(rs)))
@@ -191,6 +193,20 @@
return 0;
}
+#ifdef CONFIG_COMPAT
+static long phantom_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ if (_IOC_NR(cmd) <= 3 && _IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
+ cmd &= ~(_IOC_SIZEMASK << _IOC_SIZESHIFT);
+ cmd |= sizeof(void *) << _IOC_SIZESHIFT;
+ }
+ return phantom_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#else
+#define phantom_compat_ioctl NULL
+#endif
+
static int phantom_open(struct inode *inode, struct file *file)
{
struct phantom_device *dev = container_of(inode->i_cdev,
@@ -239,11 +255,12 @@
pr_debug("phantom_poll: %d\n", atomic_read(&dev->counter));
poll_wait(file, &dev->wait, wait);
- if (atomic_read(&dev->counter)) {
+
+ if (!(dev->status & PHB_RUNNING))
+ mask = POLLERR;
+ else if (atomic_read(&dev->counter))
mask = POLLIN | POLLRDNORM;
- atomic_dec(&dev->counter);
- } else if ((dev->status & PHB_RUNNING) == 0)
- mask = POLLIN | POLLRDNORM | POLLERR;
+
pr_debug("phantom_poll end: %x/%d\n", mask, atomic_read(&dev->counter));
return mask;
@@ -253,6 +270,7 @@
.open = phantom_open,
.release = phantom_release,
.unlocked_ioctl = phantom_ioctl,
+ .compat_ioctl = phantom_compat_ioctl,
.poll = phantom_poll,
};
diff --git a/drivers/misc/sgi-xp/xpc_partition.c b/drivers/misc/sgi-xp/xpc_partition.c
index 27e200e..acd3fd4 100644
--- a/drivers/misc/sgi-xp/xpc_partition.c
+++ b/drivers/misc/sgi-xp/xpc_partition.c
@@ -211,7 +211,7 @@
*/
amos_page = xpc_vars->amos_page;
if (amos_page == NULL) {
- amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0));
+ amos_page = (AMO_t *)TO_AMO(uncached_alloc_page(0, 1));
if (amos_page == NULL) {
dev_err(xpc_part, "can't allocate page of AMOs\n");
return NULL;
@@ -230,7 +230,7 @@
dev_err(xpc_part, "can't change memory "
"protections\n");
uncached_free_page(__IA64_UNCACHED_OFFSET |
- TO_PHYS((u64)amos_page));
+ TO_PHYS((u64)amos_page), 1);
return NULL;
}
}
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c
index 02ff3d1..00e48e2 100644
--- a/drivers/misc/sony-laptop.c
+++ b/drivers/misc/sony-laptop.c
@@ -961,7 +961,7 @@
ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
item->value, NULL);
if (ret < 0) {
- printk("%s: %d\n", __FUNCTION__, ret);
+ printk("%s: %d\n", __func__, ret);
break;
}
}
@@ -1453,7 +1453,7 @@
udelay(1); \
if (!n) \
dprintk("command failed at %s : %s (line %d)\n", \
- __FILE__, __FUNCTION__, __LINE__); \
+ __FILE__, __func__, __LINE__); \
}
static u8 sony_pic_call1(u8 dev)
diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
index 6cb7812..3f28f6e 100644
--- a/drivers/misc/thinkpad_acpi.c
+++ b/drivers/misc/thinkpad_acpi.c
@@ -21,7 +21,7 @@
* 02110-1301, USA.
*/
-#define TPACPI_VERSION "0.19"
+#define TPACPI_VERSION "0.20"
#define TPACPI_SYSFS_VERSION 0x020200
/*
@@ -67,6 +67,7 @@
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <asm/uaccess.h>
#include <linux/dmi.h>
@@ -85,6 +86,8 @@
#define TP_CMOS_VOLUME_MUTE 2
#define TP_CMOS_BRIGHTNESS_UP 4
#define TP_CMOS_BRIGHTNESS_DOWN 5
+#define TP_CMOS_THINKLIGHT_ON 12
+#define TP_CMOS_THINKLIGHT_OFF 13
/* NVRAM Addresses */
enum tp_nvram_addr {
@@ -133,8 +136,12 @@
#define TPACPI_PROC_DIR "ibm"
#define TPACPI_ACPI_EVENT_PREFIX "ibm"
#define TPACPI_DRVR_NAME TPACPI_FILE
+#define TPACPI_DRVR_SHORTNAME "tpacpi"
#define TPACPI_HWMON_DRVR_NAME TPACPI_NAME "_hwmon"
+#define TPACPI_NVRAM_KTHREAD_NAME "ktpacpi_nvramd"
+#define TPACPI_WORKQUEUE_NAME "ktpacpid"
+
#define TPACPI_MAX_ACPI_ARGS 3
/* Debugging */
@@ -225,6 +232,7 @@
u32 light:1;
u32 light_status:1;
u32 bright_16levels:1;
+ u32 bright_acpimode:1;
u32 wan:1;
u32 fan_ctrl_status_undef:1;
u32 input_device_registered:1;
@@ -236,6 +244,11 @@
u32 hotkey_poll_active:1;
} tp_features;
+static struct {
+ u16 hotkey_mask_ff:1;
+ u16 bright_cmos_ec_unsync:1;
+} tp_warned;
+
struct thinkpad_id_data {
unsigned int vendor; /* ThinkPad vendor:
* PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
@@ -246,7 +259,8 @@
u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
u16 ec_model;
- char *model_str;
+ char *model_str; /* ThinkPad T43 */
+ char *nummodel_str; /* 9384A9C for a 9384-A9C model */
};
static struct thinkpad_id_data thinkpad_id;
@@ -259,6 +273,16 @@
static int experimental;
static u32 dbg_level;
+static struct workqueue_struct *tpacpi_wq;
+
+/* Special LED class that can defer work */
+struct tpacpi_led_classdev {
+ struct led_classdev led_classdev;
+ struct work_struct work;
+ enum led_brightness new_brightness;
+ unsigned int led;
+};
+
/****************************************************************************
****************************************************************************
*
@@ -807,6 +831,80 @@
return 0;
}
+static int __init tpacpi_query_bcl_levels(acpi_handle handle)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ int rc;
+
+ if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
+ obj = (union acpi_object *)buffer.pointer;
+ if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+ printk(TPACPI_ERR "Unknown _BCL data, "
+ "please report this to %s\n", TPACPI_MAIL);
+ rc = 0;
+ } else {
+ rc = obj->package.count;
+ }
+ } else {
+ return 0;
+ }
+
+ kfree(buffer.pointer);
+ return rc;
+}
+
+static acpi_status __init tpacpi_acpi_walk_find_bcl(acpi_handle handle,
+ u32 lvl, void *context, void **rv)
+{
+ char name[ACPI_PATH_SEGMENT_LENGTH];
+ struct acpi_buffer buffer = { sizeof(name), &name };
+
+ if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
+ !strncmp("_BCL", name, sizeof(name) - 1)) {
+ BUG_ON(!rv || !*rv);
+ **(int **)rv = tpacpi_query_bcl_levels(handle);
+ return AE_CTRL_TERMINATE;
+ } else {
+ return AE_OK;
+ }
+}
+
+/*
+ * Returns 0 (no ACPI _BCL or _BCL invalid), or size of brightness map
+ */
+static int __init tpacpi_check_std_acpi_brightness_support(void)
+{
+ int status;
+ int bcl_levels = 0;
+ void *bcl_ptr = &bcl_levels;
+
+ if (!vid_handle) {
+ TPACPI_ACPIHANDLE_INIT(vid);
+ }
+ if (!vid_handle)
+ return 0;
+
+ /*
+ * Search for a _BCL method, and execute it. This is safe on all
+ * ThinkPads, and as a side-effect, _BCL will place a Lenovo Vista
+ * BIOS in ACPI backlight control mode. We do NOT have to care
+ * about calling the _BCL method in an enabled video device, any
+ * will do for our purposes.
+ */
+
+ status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
+ tpacpi_acpi_walk_find_bcl, NULL,
+ &bcl_ptr);
+
+ if (ACPI_SUCCESS(status) && bcl_levels > 2) {
+ tp_features.bright_acpimode = 1;
+ return (bcl_levels - 2);
+ }
+
+ return 0;
+}
+
/*************************************************************************
* thinkpad-acpi driver attributes
*/
@@ -909,12 +1007,14 @@
thinkpad_id.ec_version_str : "unknown");
if (thinkpad_id.vendor && thinkpad_id.model_str)
- printk(TPACPI_INFO "%s %s\n",
+ printk(TPACPI_INFO "%s %s, model %s\n",
(thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
"IBM" : ((thinkpad_id.vendor ==
PCI_VENDOR_ID_LENOVO) ?
"Lenovo" : "Unknown vendor"),
- thinkpad_id.model_str);
+ thinkpad_id.model_str,
+ (thinkpad_id.nummodel_str) ?
+ thinkpad_id.nummodel_str : "unknown");
return 0;
}
@@ -1107,6 +1207,19 @@
int rc = 0;
if (tp_features.hotkey_mask) {
+ if (!tp_warned.hotkey_mask_ff &&
+ (mask == 0xffff || mask == 0xffffff ||
+ mask == 0xffffffff)) {
+ tp_warned.hotkey_mask_ff = 1;
+ printk(TPACPI_NOTICE
+ "setting the hotkey mask to 0x%08x is likely "
+ "not the best way to go about it\n", mask);
+ printk(TPACPI_NOTICE
+ "please consider using the driver defaults, "
+ "and refer to up-to-date thinkpad-acpi "
+ "documentation\n");
+ }
+
HOTKEY_CONFIG_CRITICAL_START
for (i = 0; i < 32; i++) {
u32 m = 1 << i;
@@ -1427,8 +1540,7 @@
(tpacpi_inputdev->users > 0 || hotkey_report_mode < 2)) {
if (!tpacpi_hotkey_task) {
tpacpi_hotkey_task = kthread_run(hotkey_kthread,
- NULL,
- TPACPI_FILE "d");
+ NULL, TPACPI_NVRAM_KTHREAD_NAME);
if (IS_ERR(tpacpi_hotkey_task)) {
tpacpi_hotkey_task = NULL;
printk(TPACPI_ERR
@@ -1887,6 +1999,9 @@
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
+ /* These either have to go through ACPI video, or
+ * act like in the IBM ThinkPads, so don't ever
+ * enable them by default */
KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
KEY_RESERVED, /* 0x10: FN+END (brightness down) */
@@ -2091,6 +2206,32 @@
set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
}
+ /* Do not issue duplicate brightness change events to
+ * userspace */
+ if (!tp_features.bright_acpimode)
+ /* update bright_acpimode... */
+ tpacpi_check_std_acpi_brightness_support();
+
+ if (tp_features.bright_acpimode) {
+ printk(TPACPI_INFO
+ "This ThinkPad has standard ACPI backlight "
+ "brightness control, supported by the ACPI "
+ "video driver\n");
+ printk(TPACPI_NOTICE
+ "Disabling thinkpad-acpi brightness events "
+ "by default...\n");
+
+ /* The hotkey_reserved_mask change below is not
+ * necessary while the keys are at KEY_RESERVED in the
+ * default map, but better safe than sorry, leave it
+ * here as a marker of what we have to do, especially
+ * when we finally become able to set this at runtime
+ * on response to X.org requests */
+ hotkey_reserved_mask |=
+ (1 << TP_ACPI_HOTKEYSCAN_FNHOME)
+ | (1 << TP_ACPI_HOTKEYSCAN_FNEND);
+ }
+
dbg_printk(TPACPI_DBG_INIT,
"enabling hot key handling\n");
res = hotkey_status_set(1);
@@ -3110,13 +3251,82 @@
TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
+static int light_get_status(void)
+{
+ int status = 0;
+
+ if (tp_features.light_status) {
+ if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
+ return -EIO;
+ return (!!status);
+ }
+
+ return -ENXIO;
+}
+
+static int light_set_status(int status)
+{
+ int rc;
+
+ if (tp_features.light) {
+ if (cmos_handle) {
+ rc = acpi_evalf(cmos_handle, NULL, NULL, "vd",
+ (status)?
+ TP_CMOS_THINKLIGHT_ON :
+ TP_CMOS_THINKLIGHT_OFF);
+ } else {
+ rc = acpi_evalf(lght_handle, NULL, NULL, "vd",
+ (status)? 1 : 0);
+ }
+ return (rc)? 0 : -EIO;
+ }
+
+ return -ENXIO;
+}
+
+static void light_set_status_worker(struct work_struct *work)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(work, struct tpacpi_led_classdev, work);
+
+ if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+ light_set_status((data->new_brightness != LED_OFF));
+}
+
+static void light_sysfs_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(led_cdev,
+ struct tpacpi_led_classdev,
+ led_classdev);
+ data->new_brightness = brightness;
+ queue_work(tpacpi_wq, &data->work);
+}
+
+static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
+{
+ return (light_get_status() == 1)? LED_FULL : LED_OFF;
+}
+
+static struct tpacpi_led_classdev tpacpi_led_thinklight = {
+ .led_classdev = {
+ .name = "tpacpi::thinklight",
+ .brightness_set = &light_sysfs_set,
+ .brightness_get = &light_sysfs_get,
+ }
+};
+
static int __init light_init(struct ibm_init_struct *iibm)
{
+ int rc = 0;
+
vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
TPACPI_ACPIHANDLE_INIT(ledb);
TPACPI_ACPIHANDLE_INIT(lght);
TPACPI_ACPIHANDLE_INIT(cmos);
+ INIT_WORK(&tpacpi_led_thinklight.work, light_set_status_worker);
/* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */
tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;
@@ -3130,13 +3340,31 @@
vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",
str_supported(tp_features.light));
- return (tp_features.light)? 0 : 1;
+ if (tp_features.light) {
+ rc = led_classdev_register(&tpacpi_pdev->dev,
+ &tpacpi_led_thinklight.led_classdev);
+ }
+
+ if (rc < 0) {
+ tp_features.light = 0;
+ tp_features.light_status = 0;
+ } else {
+ rc = (tp_features.light)? 0 : 1;
+ }
+ return rc;
+}
+
+static void light_exit(void)
+{
+ led_classdev_unregister(&tpacpi_led_thinklight.led_classdev);
+ if (work_pending(&tpacpi_led_thinklight.work))
+ flush_workqueue(tpacpi_wq);
}
static int light_read(char *p)
{
int len = 0;
- int status = 0;
+ int status;
if (!tp_features.light) {
len += sprintf(p + len, "status:\t\tnot supported\n");
@@ -3144,8 +3372,9 @@
len += sprintf(p + len, "status:\t\tunknown\n");
len += sprintf(p + len, "commands:\ton, off\n");
} else {
- if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
- return -EIO;
+ status = light_get_status();
+ if (status < 0)
+ return status;
len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
len += sprintf(p + len, "commands:\ton, off\n");
}
@@ -3155,37 +3384,29 @@
static int light_write(char *buf)
{
- int cmos_cmd, lght_cmd;
char *cmd;
- int success;
+ int newstatus = 0;
if (!tp_features.light)
return -ENODEV;
while ((cmd = next_cmd(&buf))) {
if (strlencmp(cmd, "on") == 0) {
- cmos_cmd = 0x0c;
- lght_cmd = 1;
+ newstatus = 1;
} else if (strlencmp(cmd, "off") == 0) {
- cmos_cmd = 0x0d;
- lght_cmd = 0;
+ newstatus = 0;
} else
return -EINVAL;
-
- success = cmos_handle ?
- acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
- acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
- if (!success)
- return -EIO;
}
- return 0;
+ return light_set_status(newstatus);
}
static struct ibm_struct light_driver_data = {
.name = "light",
.read = light_read,
.write = light_write,
+ .exit = light_exit,
};
/*************************************************************************
@@ -3583,6 +3804,12 @@
TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
};
+enum led_status_t {
+ TPACPI_LED_OFF = 0,
+ TPACPI_LED_ON,
+ TPACPI_LED_BLINK,
+};
+
static enum led_access_mode led_supported;
TPACPI_HANDLE(led, ec, "SLED", /* 570 */
@@ -3591,8 +3818,174 @@
"LED", /* all others */
); /* R30, R31 */
+#define TPACPI_LED_NUMLEDS 8
+static struct tpacpi_led_classdev *tpacpi_leds;
+static enum led_status_t tpacpi_led_state_cache[TPACPI_LED_NUMLEDS];
+static const char const *tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
+ /* there's a limit of 19 chars + NULL before 2.6.26 */
+ "tpacpi::power",
+ "tpacpi:orange:batt",
+ "tpacpi:green:batt",
+ "tpacpi::dock_active",
+ "tpacpi::bay_active",
+ "tpacpi::dock_batt",
+ "tpacpi::unknown_led",
+ "tpacpi::standby",
+};
+
+static int led_get_status(unsigned int led)
+{
+ int status;
+ enum led_status_t led_s;
+
+ switch (led_supported) {
+ case TPACPI_LED_570:
+ if (!acpi_evalf(ec_handle,
+ &status, "GLED", "dd", 1 << led))
+ return -EIO;
+ led_s = (status == 0)?
+ TPACPI_LED_OFF :
+ ((status == 1)?
+ TPACPI_LED_ON :
+ TPACPI_LED_BLINK);
+ tpacpi_led_state_cache[led] = led_s;
+ return led_s;
+ default:
+ return -ENXIO;
+ }
+
+ /* not reached */
+}
+
+static int led_set_status(unsigned int led, enum led_status_t ledstatus)
+{
+ /* off, on, blink. Index is led_status_t */
+ static const int const led_sled_arg1[] = { 0, 1, 3 };
+ static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
+ static const int const led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
+ static const int const led_led_arg1[] = { 0, 0x80, 0xc0 };
+
+ int rc = 0;
+
+ switch (led_supported) {
+ case TPACPI_LED_570:
+ /* 570 */
+ led = 1 << led;
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_sled_arg1[ledstatus]))
+ rc = -EIO;
+ break;
+ case TPACPI_LED_OLD:
+ /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
+ led = 1 << led;
+ rc = ec_write(TPACPI_LED_EC_HLMS, led);
+ if (rc >= 0)
+ rc = ec_write(TPACPI_LED_EC_HLBL,
+ led * led_exp_hlbl[ledstatus]);
+ if (rc >= 0)
+ rc = ec_write(TPACPI_LED_EC_HLCL,
+ led * led_exp_hlcl[ledstatus]);
+ break;
+ case TPACPI_LED_NEW:
+ /* all others */
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_led_arg1[ledstatus]))
+ rc = -EIO;
+ break;
+ default:
+ rc = -ENXIO;
+ }
+
+ if (!rc)
+ tpacpi_led_state_cache[led] = ledstatus;
+
+ return rc;
+}
+
+static void led_sysfs_set_status(unsigned int led,
+ enum led_brightness brightness)
+{
+ led_set_status(led,
+ (brightness == LED_OFF) ?
+ TPACPI_LED_OFF :
+ (tpacpi_led_state_cache[led] == TPACPI_LED_BLINK) ?
+ TPACPI_LED_BLINK : TPACPI_LED_ON);
+}
+
+static void led_set_status_worker(struct work_struct *work)
+{
+ struct tpacpi_led_classdev *data =
+ container_of(work, struct tpacpi_led_classdev, work);
+
+ if (likely(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))
+ led_sysfs_set_status(data->led, data->new_brightness);
+}
+
+static void led_sysfs_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct tpacpi_led_classdev *data = container_of(led_cdev,
+ struct tpacpi_led_classdev, led_classdev);
+
+ data->new_brightness = brightness;
+ queue_work(tpacpi_wq, &data->work);
+}
+
+static int led_sysfs_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on, unsigned long *delay_off)
+{
+ struct tpacpi_led_classdev *data = container_of(led_cdev,
+ struct tpacpi_led_classdev, led_classdev);
+
+ /* Can we choose the flash rate? */
+ if (*delay_on == 0 && *delay_off == 0) {
+ /* yes. set them to the hardware blink rate (1 Hz) */
+ *delay_on = 500; /* ms */
+ *delay_off = 500; /* ms */
+ } else if ((*delay_on != 500) || (*delay_off != 500))
+ return -EINVAL;
+
+ data->new_brightness = TPACPI_LED_BLINK;
+ queue_work(tpacpi_wq, &data->work);
+
+ return 0;
+}
+
+static enum led_brightness led_sysfs_get(struct led_classdev *led_cdev)
+{
+ int rc;
+
+ struct tpacpi_led_classdev *data = container_of(led_cdev,
+ struct tpacpi_led_classdev, led_classdev);
+
+ rc = led_get_status(data->led);
+
+ if (rc == TPACPI_LED_OFF || rc < 0)
+ rc = LED_OFF; /* no error handling in led class :( */
+ else
+ rc = LED_FULL;
+
+ return rc;
+}
+
+static void led_exit(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
+ if (tpacpi_leds[i].led_classdev.name)
+ led_classdev_unregister(&tpacpi_leds[i].led_classdev);
+ }
+
+ kfree(tpacpi_leds);
+ tpacpi_leds = NULL;
+}
+
static int __init led_init(struct ibm_init_struct *iibm)
{
+ unsigned int i;
+ int rc;
+
vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
TPACPI_ACPIHANDLE_INIT(led);
@@ -3613,10 +4006,41 @@
vdbg_printk(TPACPI_DBG_INIT, "LED commands are %s, mode %d\n",
str_supported(led_supported), led_supported);
+ tpacpi_leds = kzalloc(sizeof(*tpacpi_leds) * TPACPI_LED_NUMLEDS,
+ GFP_KERNEL);
+ if (!tpacpi_leds) {
+ printk(TPACPI_ERR "Out of memory for LED data\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < TPACPI_LED_NUMLEDS; i++) {
+ tpacpi_leds[i].led = i;
+
+ tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set;
+ tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set;
+ if (led_supported == TPACPI_LED_570)
+ tpacpi_leds[i].led_classdev.brightness_get =
+ &led_sysfs_get;
+
+ tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i];
+
+ INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker);
+
+ rc = led_classdev_register(&tpacpi_pdev->dev,
+ &tpacpi_leds[i].led_classdev);
+ if (rc < 0) {
+ tpacpi_leds[i].led_classdev.name = NULL;
+ led_exit();
+ return rc;
+ }
+ }
+
return (led_supported != TPACPI_LED_NONE)? 0 : 1;
}
-#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
+#define str_led_status(s) \
+ ((s) == TPACPI_LED_OFF ? "off" : \
+ ((s) == TPACPI_LED_ON ? "on" : "blinking"))
static int led_read(char *p)
{
@@ -3632,11 +4056,11 @@
/* 570 */
int i, status;
for (i = 0; i < 8; i++) {
- if (!acpi_evalf(ec_handle,
- &status, "GLED", "dd", 1 << i))
+ status = led_get_status(i);
+ if (status < 0)
return -EIO;
len += sprintf(p + len, "%d:\t\t%s\n",
- i, led_status(status));
+ i, str_led_status(status));
}
}
@@ -3646,16 +4070,11 @@
return len;
}
-/* off, on, blink */
-static const int led_sled_arg1[] = { 0, 1, 3 };
-static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
-static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
-static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
-
static int led_write(char *buf)
{
char *cmd;
- int led, ind, ret;
+ int led, rc;
+ enum led_status_t s;
if (!led_supported)
return -ENODEV;
@@ -3665,38 +4084,18 @@
return -EINVAL;
if (strstr(cmd, "off")) {
- ind = 0;
+ s = TPACPI_LED_OFF;
} else if (strstr(cmd, "on")) {
- ind = 1;
+ s = TPACPI_LED_ON;
} else if (strstr(cmd, "blink")) {
- ind = 2;
- } else
- return -EINVAL;
-
- if (led_supported == TPACPI_LED_570) {
- /* 570 */
- led = 1 << led;
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_sled_arg1[ind]))
- return -EIO;
- } else if (led_supported == TPACPI_LED_OLD) {
- /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
- led = 1 << led;
- ret = ec_write(TPACPI_LED_EC_HLMS, led);
- if (ret >= 0)
- ret = ec_write(TPACPI_LED_EC_HLBL,
- led * led_exp_hlbl[ind]);
- if (ret >= 0)
- ret = ec_write(TPACPI_LED_EC_HLCL,
- led * led_exp_hlcl[ind]);
- if (ret < 0)
- return ret;
+ s = TPACPI_LED_BLINK;
} else {
- /* all others */
- if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
- led, led_led_arg1[ind]))
- return -EIO;
+ return -EINVAL;
}
+
+ rc = led_set_status(led, s);
+ if (rc < 0)
+ return rc;
}
return 0;
@@ -3706,6 +4105,7 @@
.name = "led",
.read = led_read,
.write = led_write,
+ .exit = led_exit,
};
/*************************************************************************
@@ -4170,8 +4570,16 @@
#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
+enum {
+ TP_EC_BACKLIGHT = 0x31,
+
+ /* TP_EC_BACKLIGHT bitmasks */
+ TP_EC_BACKLIGHT_LVLMSK = 0x1F,
+ TP_EC_BACKLIGHT_CMDMSK = 0xE0,
+ TP_EC_BACKLIGHT_MAPSW = 0x20,
+};
+
static struct backlight_device *ibm_backlight_device;
-static int brightness_offset = 0x31;
static int brightness_mode;
static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */
@@ -4180,16 +4588,24 @@
/*
* ThinkPads can read brightness from two places: EC 0x31, or
* CMOS NVRAM byte 0x5E, bits 0-3.
+ *
+ * EC 0x31 has the following layout
+ * Bit 7: unknown function
+ * Bit 6: unknown function
+ * Bit 5: Z: honour scale changes, NZ: ignore scale changes
+ * Bit 4: must be set to zero to avoid problems
+ * Bit 3-0: backlight brightness level
+ *
+ * brightness_get_raw returns status data in the EC 0x31 layout
*/
-static int brightness_get(struct backlight_device *bd)
+static int brightness_get_raw(int *status)
{
u8 lec = 0, lcmos = 0, level = 0;
if (brightness_mode & 1) {
- if (!acpi_ec_read(brightness_offset, &lec))
+ if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec))
return -EIO;
- lec &= (tp_features.bright_16levels)? 0x0f : 0x07;
- level = lec;
+ level = lec & TP_EC_BACKLIGHT_LVLMSK;
};
if (brightness_mode & 2) {
lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
@@ -4199,16 +4615,27 @@
level = lcmos;
}
- if (brightness_mode == 3 && lec != lcmos) {
- printk(TPACPI_ERR
- "CMOS NVRAM (%u) and EC (%u) do not agree "
- "on display brightness level\n",
- (unsigned int) lcmos,
- (unsigned int) lec);
- return -EIO;
+ if (brightness_mode == 3) {
+ *status = lec; /* Prefer EC, CMOS is just a backing store */
+ lec &= TP_EC_BACKLIGHT_LVLMSK;
+ if (lec == lcmos)
+ tp_warned.bright_cmos_ec_unsync = 0;
+ else {
+ if (!tp_warned.bright_cmos_ec_unsync) {
+ printk(TPACPI_ERR
+ "CMOS NVRAM (%u) and EC (%u) do not "
+ "agree on display brightness level\n",
+ (unsigned int) lcmos,
+ (unsigned int) lec);
+ tp_warned.bright_cmos_ec_unsync = 1;
+ }
+ return -EIO;
+ }
+ } else {
+ *status = level;
}
- return level;
+ return 0;
}
/* May return EINTR which can always be mapped to ERESTARTSYS */
@@ -4216,19 +4643,22 @@
{
int cmos_cmd, inc, i, res;
int current_value;
+ int command_bits;
- if (value > ((tp_features.bright_16levels)? 15 : 7))
+ if (value > ((tp_features.bright_16levels)? 15 : 7) ||
+ value < 0)
return -EINVAL;
res = mutex_lock_interruptible(&brightness_mutex);
if (res < 0)
return res;
- current_value = brightness_get(NULL);
- if (current_value < 0) {
- res = current_value;
+ res = brightness_get_raw(¤t_value);
+ if (res < 0)
goto errout;
- }
+
+ command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK;
+ current_value &= TP_EC_BACKLIGHT_LVLMSK;
cmos_cmd = value > current_value ?
TP_CMOS_BRIGHTNESS_UP :
@@ -4243,7 +4673,8 @@
goto errout;
}
if ((brightness_mode & 1) &&
- !acpi_ec_write(brightness_offset, i + inc)) {
+ !acpi_ec_write(TP_EC_BACKLIGHT,
+ (i + inc) | command_bits)) {
res = -EIO;
goto errout;;
}
@@ -4266,6 +4697,17 @@
bd->props.brightness : 0);
}
+static int brightness_get(struct backlight_device *bd)
+{
+ int status, res;
+
+ res = brightness_get_raw(&status);
+ if (res < 0)
+ return 0; /* FIXME: teach backlight about error handling */
+
+ return status & TP_EC_BACKLIGHT_LVLMSK;
+}
+
static struct backlight_ops ibm_backlight_data = {
.get_brightness = brightness_get,
.update_status = brightness_update_status,
@@ -4273,100 +4715,6 @@
/* --------------------------------------------------------------------- */
-static int __init tpacpi_query_bcll_levels(acpi_handle handle)
-{
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- int rc;
-
- if (ACPI_SUCCESS(acpi_evaluate_object(handle, NULL, NULL, &buffer))) {
- obj = (union acpi_object *)buffer.pointer;
- if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
- printk(TPACPI_ERR "Unknown BCLL data, "
- "please report this to %s\n", TPACPI_MAIL);
- rc = 0;
- } else {
- rc = obj->package.count;
- }
- } else {
- return 0;
- }
-
- kfree(buffer.pointer);
- return rc;
-}
-
-static acpi_status __init brightness_find_bcll(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- char name[ACPI_PATH_SEGMENT_LENGTH];
- struct acpi_buffer buffer = { sizeof(name), &name };
-
- if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
- !strncmp("BCLL", name, sizeof(name) - 1)) {
- if (tpacpi_query_bcll_levels(handle) == 16) {
- *rv = handle;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
- } else {
- return AE_OK;
- }
-}
-
-static int __init brightness_check_levels(void)
-{
- int status;
- void *found_node = NULL;
-
- if (!vid_handle) {
- TPACPI_ACPIHANDLE_INIT(vid);
- }
- if (!vid_handle)
- return 0;
-
- /* Search for a BCLL package with 16 levels */
- status = acpi_walk_namespace(ACPI_TYPE_PACKAGE, vid_handle, 3,
- brightness_find_bcll, NULL,
- &found_node);
-
- return (ACPI_SUCCESS(status) && found_node != NULL);
-}
-
-static acpi_status __init brightness_find_bcl(acpi_handle handle, u32 lvl,
- void *context, void **rv)
-{
- char name[ACPI_PATH_SEGMENT_LENGTH];
- struct acpi_buffer buffer = { sizeof(name), &name };
-
- if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)) &&
- !strncmp("_BCL", name, sizeof(name) - 1)) {
- *rv = handle;
- return AE_CTRL_TERMINATE;
- } else {
- return AE_OK;
- }
-}
-
-static int __init brightness_check_std_acpi_support(void)
-{
- int status;
- void *found_node = NULL;
-
- if (!vid_handle) {
- TPACPI_ACPIHANDLE_INIT(vid);
- }
- if (!vid_handle)
- return 0;
-
- /* Search for a _BCL method, but don't execute it */
- status = acpi_walk_namespace(ACPI_TYPE_METHOD, vid_handle, 3,
- brightness_find_bcl, NULL, &found_node);
-
- return (ACPI_SUCCESS(status) && found_node != NULL);
-}
-
static int __init brightness_init(struct ibm_init_struct *iibm)
{
int b;
@@ -4375,13 +4723,19 @@
mutex_init(&brightness_mutex);
- if (!brightness_enable) {
- dbg_printk(TPACPI_DBG_INIT,
- "brightness support disabled by "
- "module parameter\n");
- return 1;
- } else if (brightness_enable > 1) {
- if (brightness_check_std_acpi_support()) {
+ /*
+ * We always attempt to detect acpi support, so as to switch
+ * Lenovo Vista BIOS to ACPI brightness mode even if we are not
+ * going to publish a backlight interface
+ */
+ b = tpacpi_check_std_acpi_brightness_support();
+ if (b > 0) {
+ if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
+ printk(TPACPI_NOTICE
+ "Lenovo BIOS switched to ACPI backlight "
+ "control mode\n");
+ }
+ if (brightness_enable > 1) {
printk(TPACPI_NOTICE
"standard ACPI backlight interface "
"available, not loading native one...\n");
@@ -4389,6 +4743,22 @@
}
}
+ if (!brightness_enable) {
+ dbg_printk(TPACPI_DBG_INIT,
+ "brightness support disabled by "
+ "module parameter\n");
+ return 1;
+ }
+
+ if (b > 16) {
+ printk(TPACPI_ERR
+ "Unsupported brightness interface, "
+ "please contact %s\n", TPACPI_MAIL);
+ return 1;
+ }
+ if (b == 16)
+ tp_features.bright_16levels = 1;
+
if (!brightness_mode) {
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
brightness_mode = 2;
@@ -4402,12 +4772,7 @@
if (brightness_mode > 3)
return -EINVAL;
- tp_features.bright_16levels =
- thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO &&
- brightness_check_levels();
-
- b = brightness_get(NULL);
- if (b < 0)
+ if (brightness_get_raw(&b) < 0)
return 1;
if (tp_features.bright_16levels)
@@ -4425,7 +4790,7 @@
ibm_backlight_device->props.max_brightness =
(tp_features.bright_16levels)? 15 : 7;
- ibm_backlight_device->props.brightness = b;
+ ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK;
backlight_update_status(ibm_backlight_device);
return 0;
@@ -5046,11 +5411,11 @@
if (fan_watchdog_maxinterval > 0 &&
tpacpi_lifecycle != TPACPI_LIFE_EXITING) {
fan_watchdog_active = 1;
- if (!schedule_delayed_work(&fan_watchdog_task,
+ if (!queue_delayed_work(tpacpi_wq, &fan_watchdog_task,
msecs_to_jiffies(fan_watchdog_maxinterval
* 1000))) {
printk(TPACPI_ERR
- "failed to schedule the fan watchdog, "
+ "failed to queue the fan watchdog, "
"watchdog will not trigger\n");
}
} else
@@ -5420,7 +5785,7 @@
&driver_attr_fan_watchdog);
cancel_delayed_work(&fan_watchdog_task);
- flush_scheduled_work();
+ flush_workqueue(tpacpi_wq);
}
static int fan_read(char *p)
@@ -5826,10 +6191,13 @@
tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
GFP_KERNEL);
- if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+ if (tp->model_str && strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
kfree(tp->model_str);
tp->model_str = NULL;
}
+
+ tp->nummodel_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_NAME),
+ GFP_KERNEL);
}
static int __init probe_for_thinkpad(void)
@@ -6071,6 +6439,9 @@
if (proc_dir)
remove_proc_entry(TPACPI_PROC_DIR, acpi_root_dir);
+ if (tpacpi_wq)
+ destroy_workqueue(tpacpi_wq);
+
kfree(thinkpad_id.bios_version_str);
kfree(thinkpad_id.ec_version_str);
kfree(thinkpad_id.model_str);
@@ -6101,6 +6472,12 @@
TPACPI_ACPIHANDLE_INIT(ecrd);
TPACPI_ACPIHANDLE_INIT(ecwr);
+ tpacpi_wq = create_singlethread_workqueue(TPACPI_WORKQUEUE_NAME);
+ if (!tpacpi_wq) {
+ thinkpad_acpi_module_exit();
+ return -ENOMEM;
+ }
+
proc_dir = proc_mkdir(TPACPI_PROC_DIR, acpi_root_dir);
if (!proc_dir) {
printk(TPACPI_ERR
@@ -6223,6 +6600,8 @@
/* Please remove this in year 2009 */
MODULE_ALIAS("ibm_acpi");
+MODULE_ALIAS(TPACPI_DRVR_SHORTNAME);
+
/*
* DMI matching for module autoloading
*
diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
index 365024b8..3550858 100644
--- a/drivers/mmc/host/mmc_spi.c
+++ b/drivers/mmc/host/mmc_spi.c
@@ -340,7 +340,7 @@
/* SPI R3, R4, or R7 == R1 + 4 bytes */
case MMC_RSP_SPI_R3:
- cmd->resp[1] = be32_to_cpu(get_unaligned((u32 *)cp));
+ cmd->resp[1] = get_unaligned_be32(cp);
break;
/* SPI R1 == just one status byte */
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 95244a7..626ac08 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -213,9 +213,10 @@
void __iomem *base = host->base;
char *ptr = buffer;
u32 status;
+ int host_remain = host->size;
do {
- int count = host->size - (readl(base + MMCIFIFOCNT) << 2);
+ int count = host_remain - (readl(base + MMCIFIFOCNT) << 2);
if (count > remain)
count = remain;
@@ -227,6 +228,7 @@
ptr += count;
remain -= count;
+ host_remain -= count;
if (remain == 0)
break;
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index e812df6..fcd1aec 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -82,9 +82,8 @@
static int cfi_intelext_partition_fixup(struct mtd_info *, struct cfi_private **);
static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf);
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len);
+ size_t *retlen, void **virt, resource_size_t *phys);
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len);
static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
@@ -1240,7 +1239,8 @@
return ret;
}
-static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int cfi_intelext_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
@@ -1257,8 +1257,10 @@
chipnum = (from >> cfi->chipshift);
ofs = from - (chipnum << cfi->chipshift);
- *mtdbuf = (void *)map->virt + cfi->chips[chipnum].start + ofs;
+ *virt = map->virt + cfi->chips[chipnum].start + ofs;
*retlen = 0;
+ if (phys)
+ *phys = map->phys + cfi->chips[chipnum].start + ofs;
while (len) {
unsigned long thislen;
@@ -1291,7 +1293,7 @@
return 0;
}
-static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void cfi_intelext_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index bf485ff..0399be1 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -48,18 +48,21 @@
}
static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = mtd->priv + from;
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
+ *virt = mtd->priv + from;
*retlen = len;
return 0;
}
-static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
- size_t len)
+static void ram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
}
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 5f96018..c7987b1 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -57,20 +57,21 @@
}
static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
- u_char *start = mtd->priv;
-
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = start + from;
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
+ *virt = mtd->priv + from;
*retlen = len;
return 0;
}
-static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len)
+static void phram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
}
diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c
index 7060a08..bc99817 100644
--- a/drivers/mtd/devices/pmc551.c
+++ b/drivers/mtd/devices/pmc551.c
@@ -134,7 +134,8 @@
eoff_lo = end & (priv->asize - 1);
soff_lo = instr->addr & (priv->asize - 1);
- pmc551_point(mtd, instr->addr, instr->len, &retlen, &ptr);
+ pmc551_point(mtd, instr->addr, instr->len, &retlen,
+ (void **)&ptr, NULL);
if (soff_hi == eoff_hi || mtd->size == priv->asize) {
/* The whole thing fits within one access, so just one shot
@@ -154,7 +155,8 @@
}
soff_hi += priv->asize;
pmc551_point(mtd, (priv->base_map0 | soff_hi),
- priv->asize, &retlen, &ptr);
+ priv->asize, &retlen,
+ (void **)&ptr, NULL);
}
memset(ptr, 0xff, eoff_lo);
}
@@ -170,7 +172,7 @@
}
static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t * retlen, u_char ** mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct mypriv *priv = mtd->priv;
u32 soff_hi;
@@ -188,6 +190,10 @@
return -EINVAL;
}
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
soff_hi = from & ~(priv->asize - 1);
soff_lo = from & (priv->asize - 1);
@@ -198,13 +204,12 @@
priv->curr_map0 = soff_hi;
}
- *mtdbuf = priv->start + soff_lo;
+ *virt = priv->start + soff_lo;
*retlen = len;
return 0;
}
-static void pmc551_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
- size_t len)
+static void pmc551_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
#ifdef CONFIG_MTD_PMC551_DEBUG
printk(KERN_DEBUG "pmc551_unpoint()\n");
@@ -242,7 +247,7 @@
soff_lo = from & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
- pmc551_point(mtd, from, len, retlen, &ptr);
+ pmc551_point(mtd, from, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
@@ -263,7 +268,8 @@
goto out;
}
soff_hi += priv->asize;
- pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+ pmc551_point(mtd, soff_hi, priv->asize, retlen,
+ (void **)&ptr, NULL);
}
memcpy(copyto, ptr, eoff_lo);
copyto += eoff_lo;
@@ -308,7 +314,7 @@
soff_lo = to & (priv->asize - 1);
eoff_lo = end & (priv->asize - 1);
- pmc551_point(mtd, to, len, retlen, &ptr);
+ pmc551_point(mtd, to, len, retlen, (void **)&ptr, NULL);
if (soff_hi == eoff_hi) {
/* The whole thing fits within one access, so just one shot
@@ -329,7 +335,8 @@
goto out;
}
soff_hi += priv->asize;
- pmc551_point(mtd, soff_hi, priv->asize, retlen, &ptr);
+ pmc551_point(mtd, soff_hi, priv->asize, retlen,
+ (void **)&ptr, NULL);
}
memcpy(ptr, copyfrom, eoff_lo);
copyfrom += eoff_lo;
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index d293add..cb86db7 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -76,8 +76,9 @@
static slram_mtd_list_t *slram_mtdlist = NULL;
static int slram_erase(struct mtd_info *, struct erase_info *);
-static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **);
-static void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
+static int slram_point(struct mtd_info *, loff_t, size_t, size_t *, void **,
+ resource_size_t *);
+static void slram_unpoint(struct mtd_info *, loff_t, size_t);
static int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -104,19 +105,23 @@
}
static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
slram_priv_t *priv = mtd->priv;
+ /* can we return a physical address with this driver? */
+ if (phys)
+ return -EINVAL;
+
if (from + len > mtd->size)
return -EINVAL;
- *mtdbuf = priv->start + from;
+ *virt = priv->start + from;
*retlen = len;
return(0);
}
-static void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void slram_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
}
diff --git a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c
index 14ffb1a..c42f4b8 100644
--- a/drivers/mtd/maps/uclinux.c
+++ b/drivers/mtd/maps/uclinux.c
@@ -40,10 +40,12 @@
/****************************************************************************/
int uclinux_point(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **mtdbuf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct map_info *map = mtd->priv;
- *mtdbuf = (u_char *) (map->virt + ((int) from));
+ *virt = map->virt + from;
+ if (phys)
+ *phys = map->phys + from;
*retlen = len;
return(0);
}
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index c66902d..07c7011 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -68,7 +68,7 @@
}
static int part_point (struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char **buf)
+ size_t *retlen, void **virt, resource_size_t *phys)
{
struct mtd_part *part = PART(mtd);
if (from >= mtd->size)
@@ -76,14 +76,14 @@
else if (from + len > mtd->size)
len = mtd->size - from;
return part->master->point (part->master, from + part->offset,
- len, retlen, buf);
+ len, retlen, virt, phys);
}
-static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
{
struct mtd_part *part = PART(mtd);
- part->master->unpoint (part->master, addr, from + part->offset, len);
+ part->master->unpoint(part->master, from + part->offset, len);
}
static int part_read_oob(struct mtd_info *mtd, loff_t from,
diff --git a/drivers/mtd/nand/at91_nand.c b/drivers/mtd/nand/at91_nand.c
index 414ceae..0adb287 100644
--- a/drivers/mtd/nand/at91_nand.c
+++ b/drivers/mtd/nand/at91_nand.c
@@ -94,6 +94,24 @@
};
/*
+ * Enable NAND.
+ */
+static void at91_nand_enable(struct at91_nand_host *host)
+{
+ if (host->board->enable_pin)
+ at91_set_gpio_value(host->board->enable_pin, 0);
+}
+
+/*
+ * Disable NAND.
+ */
+static void at91_nand_disable(struct at91_nand_host *host)
+{
+ if (host->board->enable_pin)
+ at91_set_gpio_value(host->board->enable_pin, 1);
+}
+
+/*
* Hardware specific access to control-lines
*/
static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
@@ -101,11 +119,11 @@
struct nand_chip *nand_chip = mtd->priv;
struct at91_nand_host *host = nand_chip->priv;
- if (host->board->enable_pin && (ctrl & NAND_CTRL_CHANGE)) {
+ if (ctrl & NAND_CTRL_CHANGE) {
if (ctrl & NAND_NCE)
- at91_set_gpio_value(host->board->enable_pin, 0);
+ at91_nand_enable(host);
else
- at91_set_gpio_value(host->board->enable_pin, 1);
+ at91_nand_disable(host);
}
if (cmd == NAND_CMD_NONE)
return;
@@ -128,24 +146,6 @@
}
/*
- * Enable NAND.
- */
-static void at91_nand_enable(struct at91_nand_host *host)
-{
- if (host->board->enable_pin)
- at91_set_gpio_value(host->board->enable_pin, 0);
-}
-
-/*
- * Disable NAND.
- */
-static void at91_nand_disable(struct at91_nand_host *host)
-{
- if (host->board->enable_pin)
- at91_set_gpio_value(host->board->enable_pin, 1);
-}
-
-/*
* write oob for small pages
*/
static int at91_nand_write_oob_512(struct mtd_info *mtd,
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 9c65734..fdfb2b2 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -670,7 +670,7 @@
memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
}
skb->protocol = eth_type_trans(skb,dev);
- adapter->stats.rx_bytes += skb->len;
+ dev->stats.rx_bytes += skb->len;
netif_rx(skb);
dev->last_rx = jiffies;
}
@@ -773,12 +773,12 @@
* received board statistics
*/
case CMD_NETWORK_STATISTICS_RESPONSE:
- adapter->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
- adapter->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
- adapter->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
- adapter->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
- adapter->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
- adapter->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
+ dev->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv;
+ dev->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit;
+ dev->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC;
+ dev->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align;
+ dev->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun;
+ dev->stats.rx_over_errors += adapter->irx_pcb.data.netstat.err_res;
adapter->got[CMD_NETWORK_STATISTICS] = 1;
if (elp_debug >= 3)
printk(KERN_DEBUG "%s: interrupt - statistics response received\n", dev->name);
@@ -794,11 +794,11 @@
break;
switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
case 0xffff:
- adapter->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
printk(KERN_INFO "%s: transmit timed out, network cable problem?\n", dev->name);
break;
case 0xfffe:
- adapter->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);
break;
}
@@ -986,7 +986,7 @@
return false;
}
- adapter->stats.tx_bytes += nlen;
+ dev->stats.tx_bytes += nlen;
/*
* send the adapter a transmit packet command. Ignore segment and offset
@@ -1041,7 +1041,6 @@
static void elp_timeout(struct net_device *dev)
{
- elp_device *adapter = dev->priv;
int stat;
stat = inb_status(dev->base_addr);
@@ -1049,7 +1048,7 @@
if (elp_debug >= 1)
printk(KERN_DEBUG "%s: status %#02x\n", dev->name, stat);
dev->trans_start = jiffies;
- adapter->stats.tx_dropped++;
+ dev->stats.tx_dropped++;
netif_wake_queue(dev);
}
@@ -1113,7 +1112,7 @@
/* If the device is closed, just return the latest stats we have,
- we cannot ask from the adapter without interrupts */
if (!netif_running(dev))
- return &adapter->stats;
+ return &dev->stats;
/* send a get statistics command to the board */
adapter->tx_pcb.command = CMD_NETWORK_STATISTICS;
@@ -1126,12 +1125,12 @@
while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && time_before(jiffies, timeout));
if (time_after_eq(jiffies, timeout)) {
TIMEOUT_MSG(__LINE__);
- return &adapter->stats;
+ return &dev->stats;
}
}
/* statistics are now up to date */
- return &adapter->stats;
+ return &dev->stats;
}
@@ -1571,7 +1570,6 @@
dev->set_multicast_list = elp_set_mc_list; /* local */
dev->ethtool_ops = &netdev_ethtool_ops; /* local */
- memset(&(adapter->stats), 0, sizeof(struct net_device_stats));
dev->mem_start = dev->mem_end = 0;
err = register_netdev(dev);
diff --git a/drivers/net/3c505.h b/drivers/net/3c505.h
index 1910cb1..04df2a9 100644
--- a/drivers/net/3c505.h
+++ b/drivers/net/3c505.h
@@ -264,7 +264,6 @@
pcb_struct rx_pcb; /* PCB for foreground receiving */
pcb_struct itx_pcb; /* PCB for background sending */
pcb_struct irx_pcb; /* PCB for background receiving */
- struct net_device_stats stats;
void *dma_buffer;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 54dac06..e6c545f 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -167,7 +167,6 @@
enum el3_cardtype { EL3_ISA, EL3_PNP, EL3_MCA, EL3_EISA };
struct el3_private {
- struct net_device_stats stats;
spinlock_t lock;
/* skb send-queue */
int head, size;
@@ -794,7 +793,6 @@
static void
el3_tx_timeout (struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
/* Transmitter timeout, serious problems. */
@@ -802,7 +800,7 @@
"Tx FIFO room %d.\n",
dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS),
inw(ioaddr + TX_FREE));
- lp->stats.tx_errors++;
+ dev->stats.tx_errors++;
dev->trans_start = jiffies;
/* Issue TX_RESET and TX_START commands. */
outw(TxReset, ioaddr + EL3_CMD);
@@ -820,7 +818,7 @@
netif_stop_queue (dev);
- lp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
if (el3_debug > 4) {
printk(KERN_DEBUG "%s: el3_start_xmit(length = %u) called, status %4.4x.\n",
@@ -881,7 +879,7 @@
int i = 4;
while (--i > 0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
- if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
+ if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
@@ -931,12 +929,11 @@
outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
}
if (status & TxComplete) { /* Really Tx error. */
- struct el3_private *lp = netdev_priv(dev);
short tx_status;
int i = 4;
while (--i>0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) {
- if (tx_status & 0x38) lp->stats.tx_aborted_errors++;
+ if (tx_status & 0x38) dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) outw(TxReset, ioaddr + EL3_CMD);
if (tx_status & 0x3C) outw(TxEnable, ioaddr + EL3_CMD);
outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
@@ -1002,7 +999,7 @@
spin_lock_irqsave(&lp->lock, flags);
update_stats(dev);
spin_unlock_irqrestore(&lp->lock, flags);
- return &lp->stats;
+ return &dev->stats;
}
/* Update statistics. We change to register window 6, so this should be run
@@ -1012,7 +1009,6 @@
*/
static void update_stats(struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
if (el3_debug > 5)
@@ -1021,13 +1017,13 @@
outw(StatsDisable, ioaddr + EL3_CMD);
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
- lp->stats.tx_carrier_errors += inb(ioaddr + 0);
- lp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
+ dev->stats.tx_carrier_errors += inb(ioaddr + 0);
+ dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
/* Multiple collisions. */ inb(ioaddr + 2);
- lp->stats.collisions += inb(ioaddr + 3);
- lp->stats.tx_window_errors += inb(ioaddr + 4);
- lp->stats.rx_fifo_errors += inb(ioaddr + 5);
- lp->stats.tx_packets += inb(ioaddr + 6);
+ dev->stats.collisions += inb(ioaddr + 3);
+ dev->stats.tx_window_errors += inb(ioaddr + 4);
+ dev->stats.rx_fifo_errors += inb(ioaddr + 5);
+ dev->stats.tx_packets += inb(ioaddr + 6);
/* Rx packets */ inb(ioaddr + 7);
/* Tx deferrals */ inb(ioaddr + 8);
inw(ioaddr + 10); /* Total Rx and Tx octets. */
@@ -1042,7 +1038,6 @@
static int
el3_rx(struct net_device *dev)
{
- struct el3_private *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
short rx_status;
@@ -1054,21 +1049,21 @@
short error = rx_status & 0x3800;
outw(RxDiscard, ioaddr + EL3_CMD);
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
switch (error) {
- case 0x0000: lp->stats.rx_over_errors++; break;
- case 0x0800: lp->stats.rx_length_errors++; break;
- case 0x1000: lp->stats.rx_frame_errors++; break;
- case 0x1800: lp->stats.rx_length_errors++; break;
- case 0x2000: lp->stats.rx_frame_errors++; break;
- case 0x2800: lp->stats.rx_crc_errors++; break;
+ case 0x0000: dev->stats.rx_over_errors++; break;
+ case 0x0800: dev->stats.rx_length_errors++; break;
+ case 0x1000: dev->stats.rx_frame_errors++; break;
+ case 0x1800: dev->stats.rx_length_errors++; break;
+ case 0x2000: dev->stats.rx_frame_errors++; break;
+ case 0x2800: dev->stats.rx_crc_errors++; break;
}
} else {
short pkt_len = rx_status & 0x7ff;
struct sk_buff *skb;
skb = dev_alloc_skb(pkt_len+5);
- lp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
if (el3_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@@ -1083,11 +1078,11 @@
skb->protocol = eth_type_trans(skb,dev);
netif_rx(skb);
dev->last_rx = jiffies;
- lp->stats.rx_packets++;
+ dev->stats.rx_packets++;
continue;
}
outw(RxDiscard, ioaddr + EL3_CMD);
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
if (el3_debug)
printk("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, pkt_len);
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 6ab84b6..105a8c7 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -310,7 +310,6 @@
struct sk_buff *tx_skbuff[TX_RING_SIZE];
unsigned int cur_rx, cur_tx; /* The next free ring entry */
unsigned int dirty_rx, dirty_tx;/* The ring entries to be free()ed. */
- struct net_device_stats stats;
struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */
struct timer_list timer; /* Media selection timer. */
int capabilities ; /* Adapter capabilities word. */
@@ -983,8 +982,8 @@
break;
outw(TxEnable, ioaddr + EL3_CMD);
dev->trans_start = jiffies;
- vp->stats.tx_errors++;
- vp->stats.tx_dropped++;
+ dev->stats.tx_errors++;
+ dev->stats.tx_dropped++;
netif_wake_queue(dev);
}
@@ -1050,7 +1049,7 @@
}
/* Put out the doubleword header... */
outl(skb->len, ioaddr + TX_FIFO);
- vp->stats.tx_bytes += skb->len;
+ dev->stats.tx_bytes += skb->len;
#ifdef VORTEX_BUS_MASTER
if (vp->bus_master) {
/* Set the bus-master controller to transfer the packet. */
@@ -1094,9 +1093,9 @@
printk("%s: Tx error, status %2.2x.\n",
dev->name, tx_status);
if (tx_status & 0x04)
- vp->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (tx_status & 0x38)
- vp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (tx_status & 0x30) {
int j;
outw(TxReset, ioaddr + EL3_CMD);
@@ -1257,7 +1256,6 @@
static int corkscrew_rx(struct net_device *dev)
{
- struct corkscrew_private *vp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int i;
short rx_status;
@@ -1271,17 +1269,17 @@
if (corkscrew_debug > 2)
printk(" Rx error: status %2.2x.\n",
rx_error);
- vp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_error & 0x01)
- vp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rx_error & 0x02)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rx_error & 0x04)
- vp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_error & 0x08)
- vp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_error & 0x10)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
@@ -1301,8 +1299,8 @@
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- vp->stats.rx_packets++;
- vp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += pkt_len;
/* Wait a limited time to go to next packet. */
for (i = 200; i >= 0; i--)
if (! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
@@ -1312,7 +1310,7 @@
printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, pkt_len);
}
outw(RxDiscard, ioaddr + EL3_CMD);
- vp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
/* Wait a limited time to skip this packet. */
for (i = 200; i >= 0; i--)
if (!(inw(ioaddr + EL3_STATUS) & CmdInProgress))
@@ -1337,23 +1335,23 @@
if (corkscrew_debug > 2)
printk(" Rx error: status %2.2x.\n",
rx_error);
- vp->stats.rx_errors++;
+ dev->stats.rx_errors++;
if (rx_error & 0x01)
- vp->stats.rx_over_errors++;
+ dev->stats.rx_over_errors++;
if (rx_error & 0x02)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
if (rx_error & 0x04)
- vp->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
if (rx_error & 0x08)
- vp->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
if (rx_error & 0x10)
- vp->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
} else {
/* The packet length: up to 4.5K!. */
short pkt_len = rx_status & 0x1fff;
struct sk_buff *skb;
- vp->stats.rx_bytes += pkt_len;
+ dev->stats.rx_bytes += pkt_len;
if (corkscrew_debug > 4)
printk("Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@@ -1388,7 +1386,7 @@
skb->protocol = eth_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
- vp->stats.rx_packets++;
+ dev->stats.rx_packets++;
}
entry = (++vp->cur_rx) % RX_RING_SIZE;
}
@@ -1475,7 +1473,7 @@
update_stats(dev->base_addr, dev);
spin_unlock_irqrestore(&vp->lock, flags);
}
- return &vp->stats;
+ return &dev->stats;
}
/* Update statistics.
@@ -1487,19 +1485,17 @@
*/
static void update_stats(int ioaddr, struct net_device *dev)
{
- struct corkscrew_private *vp = netdev_priv(dev);
-
/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
/* Switch to the stats window, and read everything. */
EL3WINDOW(6);
- vp->stats.tx_carrier_errors += inb(ioaddr + 0);
- vp->stats.tx_heartbeat_errors += inb(ioaddr + 1);
+ dev->stats.tx_carrier_errors += inb(ioaddr + 0);
+ dev->stats.tx_heartbeat_errors += inb(ioaddr + 1);
/* Multiple collisions. */ inb(ioaddr + 2);
- vp->stats.collisions += inb(ioaddr + 3);
- vp->stats.tx_window_errors += inb(ioaddr + 4);
- vp->stats.rx_fifo_errors += inb(ioaddr + 5);
- vp->stats.tx_packets += inb(ioaddr + 6);
- vp->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
+ dev->stats.collisions += inb(ioaddr + 3);
+ dev->stats.tx_window_errors += inb(ioaddr + 4);
+ dev->stats.rx_fifo_errors += inb(ioaddr + 5);
+ dev->stats.tx_packets += inb(ioaddr + 6);
+ dev->stats.tx_packets += (inb(ioaddr + 9) & 0x30) << 4;
/* Rx packets */ inb(ioaddr + 7);
/* Must read to clear */
/* Tx deferrals */ inb(ioaddr + 8);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index f90a86b..af46341 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2593,6 +2593,7 @@
To compile this driver as a module, choose M here: the module
will be called bnx2x. This is recommended.
+source "drivers/net/sfc/Kconfig"
endif # NETDEV_10000
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 2f1f3f2..dcbfe84 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -253,3 +253,5 @@
obj-$(CONFIG_NETXEN_NIC) += netxen/
obj-$(CONFIG_NIU) += niu.o
obj-$(CONFIG_VIRTIO_NET) += virtio_net.o
+obj-$(CONFIG_SFC) += sfc/
+
diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
index f9cc2b6..8eda6ee 100644
--- a/drivers/net/arm/Kconfig
+++ b/drivers/net/arm/Kconfig
@@ -47,3 +47,11 @@
help
This is a driver for the ethernet hardware included in EP93xx CPUs.
Say Y if you are building a kernel for EP93xx based devices.
+
+config IXP4XX_ETH
+ tristate "Intel IXP4xx Ethernet support"
+ depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR
+ select MII
+ help
+ Say Y here if you want to use built-in Ethernet ports
+ on IXP4xx processor.
diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile
index a4c8682..7c812ac 100644
--- a/drivers/net/arm/Makefile
+++ b/drivers/net/arm/Makefile
@@ -9,3 +9,4 @@
obj-$(CONFIG_ARM_ETHER1) += ether1.o
obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o
obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o
+obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index ba6bd03..a637910 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -693,11 +693,15 @@
* done by the ether bootp loader.
*/
dev->base_addr = res->start;
- dev->irq = platform_get_irq(pdev, 0);
+ ret = platform_get_irq(pdev, 0);
+
+ if (ret < 0) {
+ ret = -ENODEV;
+ goto nodev;
+ }
+ dev->irq = ret;
ret = -ENODEV;
- if (dev->irq < 0)
- goto nodev;
if (!request_region(dev->base_addr, 0x18, dev->name))
goto nodev;
diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
new file mode 100644
index 0000000..c617b64
--- /dev/null
+++ b/drivers/net/arm/ixp4xx_eth.c
@@ -0,0 +1,1265 @@
+/*
+ * Intel IXP4xx Ethernet driver for Linux
+ *
+ * Copyright (C) 2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * 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.
+ *
+ * Ethernet port config (0x00 is not present on IXP42X):
+ *
+ * logical port 0x00 0x10 0x20
+ * NPE 0 (NPE-A) 1 (NPE-B) 2 (NPE-C)
+ * physical PortId 2 0 1
+ * TX queue 23 24 25
+ * RX-free queue 26 27 28
+ * TX-done queue is always 31, per-port RX and TX-ready queues are configurable
+ *
+ *
+ * Queue entries:
+ * bits 0 -> 1 - NPE ID (RX and TX-done)
+ * bits 0 -> 2 - priority (TX, per 802.1D)
+ * bits 3 -> 4 - port ID (user-set?)
+ * bits 5 -> 31 - physical descriptor address
+ */
+
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/etherdevice.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mii.h>
+#include <linux/platform_device.h>
+#include <asm/arch/npe.h>
+#include <asm/arch/qmgr.h>
+
+#define DEBUG_QUEUES 0
+#define DEBUG_DESC 0
+#define DEBUG_RX 0
+#define DEBUG_TX 0
+#define DEBUG_PKT_BYTES 0
+#define DEBUG_MDIO 0
+#define DEBUG_CLOSE 0
+
+#define DRV_NAME "ixp4xx_eth"
+
+#define MAX_NPES 3
+
+#define RX_DESCS 64 /* also length of all RX queues */
+#define TX_DESCS 16 /* also length of all TX queues */
+#define TXDONE_QUEUE_LEN 64 /* dwords */
+
+#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS))
+#define REGS_SIZE 0x1000
+#define MAX_MRU 1536 /* 0x600 */
+#define RX_BUFF_SIZE ALIGN((NET_IP_ALIGN) + MAX_MRU, 4)
+
+#define NAPI_WEIGHT 16
+#define MDIO_INTERVAL (3 * HZ)
+#define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */
+#define MAX_MII_RESET_RETRIES 100 /* mdio_read() cycles, typically 4 */
+#define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */
+
+#define NPE_ID(port_id) ((port_id) >> 4)
+#define PHYSICAL_ID(port_id) ((NPE_ID(port_id) + 2) % 3)
+#define TX_QUEUE(port_id) (NPE_ID(port_id) + 23)
+#define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26)
+#define TXDONE_QUEUE 31
+
+/* TX Control Registers */
+#define TX_CNTRL0_TX_EN 0x01
+#define TX_CNTRL0_HALFDUPLEX 0x02
+#define TX_CNTRL0_RETRY 0x04
+#define TX_CNTRL0_PAD_EN 0x08
+#define TX_CNTRL0_APPEND_FCS 0x10
+#define TX_CNTRL0_2DEFER 0x20
+#define TX_CNTRL0_RMII 0x40 /* reduced MII */
+#define TX_CNTRL1_RETRIES 0x0F /* 4 bits */
+
+/* RX Control Registers */
+#define RX_CNTRL0_RX_EN 0x01
+#define RX_CNTRL0_PADSTRIP_EN 0x02
+#define RX_CNTRL0_SEND_FCS 0x04
+#define RX_CNTRL0_PAUSE_EN 0x08
+#define RX_CNTRL0_LOOP_EN 0x10
+#define RX_CNTRL0_ADDR_FLTR_EN 0x20
+#define RX_CNTRL0_RX_RUNT_EN 0x40
+#define RX_CNTRL0_BCAST_DIS 0x80
+#define RX_CNTRL1_DEFER_EN 0x01
+
+/* Core Control Register */
+#define CORE_RESET 0x01
+#define CORE_RX_FIFO_FLUSH 0x02
+#define CORE_TX_FIFO_FLUSH 0x04
+#define CORE_SEND_JAM 0x08
+#define CORE_MDC_EN 0x10 /* MDIO using NPE-B ETH-0 only */
+
+#define DEFAULT_TX_CNTRL0 (TX_CNTRL0_TX_EN | TX_CNTRL0_RETRY | \
+ TX_CNTRL0_PAD_EN | TX_CNTRL0_APPEND_FCS | \
+ TX_CNTRL0_2DEFER)
+#define DEFAULT_RX_CNTRL0 RX_CNTRL0_RX_EN
+#define DEFAULT_CORE_CNTRL CORE_MDC_EN
+
+
+/* NPE message codes */
+#define NPE_GETSTATUS 0x00
+#define NPE_EDB_SETPORTADDRESS 0x01
+#define NPE_EDB_GETMACADDRESSDATABASE 0x02
+#define NPE_EDB_SETMACADDRESSSDATABASE 0x03
+#define NPE_GETSTATS 0x04
+#define NPE_RESETSTATS 0x05
+#define NPE_SETMAXFRAMELENGTHS 0x06
+#define NPE_VLAN_SETRXTAGMODE 0x07
+#define NPE_VLAN_SETDEFAULTRXVID 0x08
+#define NPE_VLAN_SETPORTVLANTABLEENTRY 0x09
+#define NPE_VLAN_SETPORTVLANTABLERANGE 0x0A
+#define NPE_VLAN_SETRXQOSENTRY 0x0B
+#define NPE_VLAN_SETPORTIDEXTRACTIONMODE 0x0C
+#define NPE_STP_SETBLOCKINGSTATE 0x0D
+#define NPE_FW_SETFIREWALLMODE 0x0E
+#define NPE_PC_SETFRAMECONTROLDURATIONID 0x0F
+#define NPE_PC_SETAPMACTABLE 0x11
+#define NPE_SETLOOPBACK_MODE 0x12
+#define NPE_PC_SETBSSIDTABLE 0x13
+#define NPE_ADDRESS_FILTER_CONFIG 0x14
+#define NPE_APPENDFCSCONFIG 0x15
+#define NPE_NOTIFY_MAC_RECOVERY_DONE 0x16
+#define NPE_MAC_RECOVERY_START 0x17
+
+
+#ifdef __ARMEB__
+typedef struct sk_buff buffer_t;
+#define free_buffer dev_kfree_skb
+#define free_buffer_irq dev_kfree_skb_irq
+#else
+typedef void buffer_t;
+#define free_buffer kfree
+#define free_buffer_irq kfree
+#endif
+
+struct eth_regs {
+ u32 tx_control[2], __res1[2]; /* 000 */
+ u32 rx_control[2], __res2[2]; /* 010 */
+ u32 random_seed, __res3[3]; /* 020 */
+ u32 partial_empty_threshold, __res4; /* 030 */
+ u32 partial_full_threshold, __res5; /* 038 */
+ u32 tx_start_bytes, __res6[3]; /* 040 */
+ u32 tx_deferral, rx_deferral, __res7[2];/* 050 */
+ u32 tx_2part_deferral[2], __res8[2]; /* 060 */
+ u32 slot_time, __res9[3]; /* 070 */
+ u32 mdio_command[4]; /* 080 */
+ u32 mdio_status[4]; /* 090 */
+ u32 mcast_mask[6], __res10[2]; /* 0A0 */
+ u32 mcast_addr[6], __res11[2]; /* 0C0 */
+ u32 int_clock_threshold, __res12[3]; /* 0E0 */
+ u32 hw_addr[6], __res13[61]; /* 0F0 */
+ u32 core_control; /* 1FC */
+};
+
+struct port {
+ struct resource *mem_res;
+ struct eth_regs __iomem *regs;
+ struct npe *npe;
+ struct net_device *netdev;
+ struct napi_struct napi;
+ struct net_device_stats stat;
+ struct mii_if_info mii;
+ struct delayed_work mdio_thread;
+ struct eth_plat_info *plat;
+ buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS];
+ struct desc *desc_tab; /* coherent */
+ u32 desc_tab_phys;
+ int id; /* logical port ID */
+ u16 mii_bmcr;
+};
+
+/* NPE message structure */
+struct msg {
+#ifdef __ARMEB__
+ u8 cmd, eth_id, byte2, byte3;
+ u8 byte4, byte5, byte6, byte7;
+#else
+ u8 byte3, byte2, eth_id, cmd;
+ u8 byte7, byte6, byte5, byte4;
+#endif
+};
+
+/* Ethernet packet descriptor */
+struct desc {
+ u32 next; /* pointer to next buffer, unused */
+
+#ifdef __ARMEB__
+ u16 buf_len; /* buffer length */
+ u16 pkt_len; /* packet length */
+ u32 data; /* pointer to data buffer in RAM */
+ u8 dest_id;
+ u8 src_id;
+ u16 flags;
+ u8 qos;
+ u8 padlen;
+ u16 vlan_tci;
+#else
+ u16 pkt_len; /* packet length */
+ u16 buf_len; /* buffer length */
+ u32 data; /* pointer to data buffer in RAM */
+ u16 flags;
+ u8 src_id;
+ u8 dest_id;
+ u16 vlan_tci;
+ u8 padlen;
+ u8 qos;
+#endif
+
+#ifdef __ARMEB__
+ u8 dst_mac_0, dst_mac_1, dst_mac_2, dst_mac_3;
+ u8 dst_mac_4, dst_mac_5, src_mac_0, src_mac_1;
+ u8 src_mac_2, src_mac_3, src_mac_4, src_mac_5;
+#else
+ u8 dst_mac_3, dst_mac_2, dst_mac_1, dst_mac_0;
+ u8 src_mac_1, src_mac_0, dst_mac_5, dst_mac_4;
+ u8 src_mac_5, src_mac_4, src_mac_3, src_mac_2;
+#endif
+};
+
+
+#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \
+ (n) * sizeof(struct desc))
+#define rx_desc_ptr(port, n) (&(port)->desc_tab[n])
+
+#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \
+ ((n) + RX_DESCS) * sizeof(struct desc))
+#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS])
+
+#ifndef __ARMEB__
+static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt)
+{
+ int i;
+ for (i = 0; i < cnt; i++)
+ dest[i] = swab32(src[i]);
+}
+#endif
+
+static spinlock_t mdio_lock;
+static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */
+static int ports_open;
+static struct port *npe_port_tab[MAX_NPES];
+static struct dma_pool *dma_pool;
+
+
+static u16 mdio_cmd(struct net_device *dev, int phy_id, int location,
+ int write, u16 cmd)
+{
+ int cycles = 0;
+
+ if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) {
+ printk(KERN_ERR "%s: MII not ready to transmit\n", dev->name);
+ return 0;
+ }
+
+ if (write) {
+ __raw_writel(cmd & 0xFF, &mdio_regs->mdio_command[0]);
+ __raw_writel(cmd >> 8, &mdio_regs->mdio_command[1]);
+ }
+ __raw_writel(((phy_id << 5) | location) & 0xFF,
+ &mdio_regs->mdio_command[2]);
+ __raw_writel((phy_id >> 3) | (write << 2) | 0x80 /* GO */,
+ &mdio_regs->mdio_command[3]);
+
+ while ((cycles < MAX_MDIO_RETRIES) &&
+ (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80)) {
+ udelay(1);
+ cycles++;
+ }
+
+ if (cycles == MAX_MDIO_RETRIES) {
+ printk(KERN_ERR "%s: MII write failed\n", dev->name);
+ return 0;
+ }
+
+#if DEBUG_MDIO
+ printk(KERN_DEBUG "%s: mdio_cmd() took %i cycles\n", dev->name,
+ cycles);
+#endif
+
+ if (write)
+ return 0;
+
+ if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) {
+ printk(KERN_ERR "%s: MII read failed\n", dev->name);
+ return 0;
+ }
+
+ return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) |
+ (__raw_readl(&mdio_regs->mdio_status[1]) << 8);
+}
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+ unsigned long flags;
+ u16 val;
+
+ spin_lock_irqsave(&mdio_lock, flags);
+ val = mdio_cmd(dev, phy_id, location, 0, 0);
+ spin_unlock_irqrestore(&mdio_lock, flags);
+ return val;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location,
+ int val)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&mdio_lock, flags);
+ mdio_cmd(dev, phy_id, location, 1, val);
+ spin_unlock_irqrestore(&mdio_lock, flags);
+}
+
+static void phy_reset(struct net_device *dev, int phy_id)
+{
+ struct port *port = netdev_priv(dev);
+ int cycles = 0;
+
+ mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET);
+
+ while (cycles < MAX_MII_RESET_RETRIES) {
+ if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) {
+#if DEBUG_MDIO
+ printk(KERN_DEBUG "%s: phy_reset() took %i cycles\n",
+ dev->name, cycles);
+#endif
+ return;
+ }
+ udelay(1);
+ cycles++;
+ }
+
+ printk(KERN_ERR "%s: MII reset failed\n", dev->name);
+}
+
+static void eth_set_duplex(struct port *port)
+{
+ if (port->mii.full_duplex)
+ __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+ else
+ __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX,
+ &port->regs->tx_control[0]);
+}
+
+
+static void phy_check_media(struct port *port, int init)
+{
+ if (mii_check_media(&port->mii, 1, init))
+ eth_set_duplex(port);
+ if (port->mii.force_media) { /* mii_check_media() doesn't work */
+ struct net_device *dev = port->netdev;
+ int cur_link = mii_link_ok(&port->mii);
+ int prev_link = netif_carrier_ok(dev);
+
+ if (!prev_link && cur_link) {
+ printk(KERN_INFO "%s: link up\n", dev->name);
+ netif_carrier_on(dev);
+ } else if (prev_link && !cur_link) {
+ printk(KERN_INFO "%s: link down\n", dev->name);
+ netif_carrier_off(dev);
+ }
+ }
+}
+
+
+static void mdio_thread(struct work_struct *work)
+{
+ struct port *port = container_of(work, struct port, mdio_thread.work);
+
+ phy_check_media(port, 0);
+ schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);
+}
+
+
+static inline void debug_pkt(struct net_device *dev, const char *func,
+ u8 *data, int len)
+{
+#if DEBUG_PKT_BYTES
+ int i;
+
+ printk(KERN_DEBUG "%s: %s(%i) ", dev->name, func, len);
+ for (i = 0; i < len; i++) {
+ if (i >= DEBUG_PKT_BYTES)
+ break;
+ printk("%s%02X",
+ ((i == 6) || (i == 12) || (i >= 14)) ? " " : "",
+ data[i]);
+ }
+ printk("\n");
+#endif
+}
+
+
+static inline void debug_desc(u32 phys, struct desc *desc)
+{
+#if DEBUG_DESC
+ printk(KERN_DEBUG "%X: %X %3X %3X %08X %2X < %2X %4X %X"
+ " %X %X %02X%02X%02X%02X%02X%02X < %02X%02X%02X%02X%02X%02X\n",
+ phys, desc->next, desc->buf_len, desc->pkt_len,
+ desc->data, desc->dest_id, desc->src_id, desc->flags,
+ desc->qos, desc->padlen, desc->vlan_tci,
+ desc->dst_mac_0, desc->dst_mac_1, desc->dst_mac_2,
+ desc->dst_mac_3, desc->dst_mac_4, desc->dst_mac_5,
+ desc->src_mac_0, desc->src_mac_1, desc->src_mac_2,
+ desc->src_mac_3, desc->src_mac_4, desc->src_mac_5);
+#endif
+}
+
+static inline void debug_queue(unsigned int queue, int is_get, u32 phys)
+{
+#if DEBUG_QUEUES
+ static struct {
+ int queue;
+ char *name;
+ } names[] = {
+ { TX_QUEUE(0x10), "TX#0 " },
+ { TX_QUEUE(0x20), "TX#1 " },
+ { TX_QUEUE(0x00), "TX#2 " },
+ { RXFREE_QUEUE(0x10), "RX-free#0 " },
+ { RXFREE_QUEUE(0x20), "RX-free#1 " },
+ { RXFREE_QUEUE(0x00), "RX-free#2 " },
+ { TXDONE_QUEUE, "TX-done " },
+ };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(names); i++)
+ if (names[i].queue == queue)
+ break;
+
+ printk(KERN_DEBUG "Queue %i %s%s %X\n", queue,
+ i < ARRAY_SIZE(names) ? names[i].name : "",
+ is_get ? "->" : "<-", phys);
+#endif
+}
+
+static inline u32 queue_get_entry(unsigned int queue)
+{
+ u32 phys = qmgr_get_entry(queue);
+ debug_queue(queue, 1, phys);
+ return phys;
+}
+
+static inline int queue_get_desc(unsigned int queue, struct port *port,
+ int is_tx)
+{
+ u32 phys, tab_phys, n_desc;
+ struct desc *tab;
+
+ if (!(phys = queue_get_entry(queue)))
+ return -1;
+
+ phys &= ~0x1F; /* mask out non-address bits */
+ tab_phys = is_tx ? tx_desc_phys(port, 0) : rx_desc_phys(port, 0);
+ tab = is_tx ? tx_desc_ptr(port, 0) : rx_desc_ptr(port, 0);
+ n_desc = (phys - tab_phys) / sizeof(struct desc);
+ BUG_ON(n_desc >= (is_tx ? TX_DESCS : RX_DESCS));
+ debug_desc(phys, &tab[n_desc]);
+ BUG_ON(tab[n_desc].next);
+ return n_desc;
+}
+
+static inline void queue_put_desc(unsigned int queue, u32 phys,
+ struct desc *desc)
+{
+ debug_queue(queue, 0, phys);
+ debug_desc(phys, desc);
+ BUG_ON(phys & 0x1F);
+ qmgr_put_entry(queue, phys);
+ BUG_ON(qmgr_stat_overflow(queue));
+}
+
+
+static inline void dma_unmap_tx(struct port *port, struct desc *desc)
+{
+#ifdef __ARMEB__
+ dma_unmap_single(&port->netdev->dev, desc->data,
+ desc->buf_len, DMA_TO_DEVICE);
+#else
+ dma_unmap_single(&port->netdev->dev, desc->data & ~3,
+ ALIGN((desc->data & 3) + desc->buf_len, 4),
+ DMA_TO_DEVICE);
+#endif
+}
+
+
+static void eth_rx_irq(void *pdev)
+{
+ struct net_device *dev = pdev;
+ struct port *port = netdev_priv(dev);
+
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_rx_irq\n", dev->name);
+#endif
+ qmgr_disable_irq(port->plat->rxq);
+ netif_rx_schedule(dev, &port->napi);
+}
+
+static int eth_poll(struct napi_struct *napi, int budget)
+{
+ struct port *port = container_of(napi, struct port, napi);
+ struct net_device *dev = port->netdev;
+ unsigned int rxq = port->plat->rxq, rxfreeq = RXFREE_QUEUE(port->id);
+ int received = 0;
+
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll\n", dev->name);
+#endif
+
+ while (received < budget) {
+ struct sk_buff *skb;
+ struct desc *desc;
+ int n;
+#ifdef __ARMEB__
+ struct sk_buff *temp;
+ u32 phys;
+#endif
+
+ if ((n = queue_get_desc(rxq, port, 0)) < 0) {
+ received = 0; /* No packet received */
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll netif_rx_complete\n",
+ dev->name);
+#endif
+ netif_rx_complete(dev, napi);
+ qmgr_enable_irq(rxq);
+ if (!qmgr_stat_empty(rxq) &&
+ netif_rx_reschedule(dev, napi)) {
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll"
+ " netif_rx_reschedule successed\n",
+ dev->name);
+#endif
+ qmgr_disable_irq(rxq);
+ continue;
+ }
+#if DEBUG_RX
+ printk(KERN_DEBUG "%s: eth_poll all done\n",
+ dev->name);
+#endif
+ return 0; /* all work done */
+ }
+
+ desc = rx_desc_ptr(port, n);
+
+#ifdef __ARMEB__
+ if ((skb = netdev_alloc_skb(dev, RX_BUFF_SIZE))) {
+ phys = dma_map_single(&dev->dev, skb->data,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(phys)) {
+ dev_kfree_skb(skb);
+ skb = NULL;
+ }
+ }
+#else
+ skb = netdev_alloc_skb(dev,
+ ALIGN(NET_IP_ALIGN + desc->pkt_len, 4));
+#endif
+
+ if (!skb) {
+ port->stat.rx_dropped++;
+ /* put the desc back on RX-ready queue */
+ desc->buf_len = MAX_MRU;
+ desc->pkt_len = 0;
+ queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
+ continue;
+ }
+
+ /* process received frame */
+#ifdef __ARMEB__
+ temp = skb;
+ skb = port->rx_buff_tab[n];
+ dma_unmap_single(&dev->dev, desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+#else
+ dma_sync_single(&dev->dev, desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n],
+ ALIGN(NET_IP_ALIGN + desc->pkt_len, 4) / 4);
+#endif
+ skb_reserve(skb, NET_IP_ALIGN);
+ skb_put(skb, desc->pkt_len);
+
+ debug_pkt(dev, "eth_poll", skb->data, skb->len);
+
+ skb->protocol = eth_type_trans(skb, dev);
+ dev->last_rx = jiffies;
+ port->stat.rx_packets++;
+ port->stat.rx_bytes += skb->len;
+ netif_receive_skb(skb);
+
+ /* put the new buffer on RX-free queue */
+#ifdef __ARMEB__
+ port->rx_buff_tab[n] = temp;
+ desc->data = phys + NET_IP_ALIGN;
+#endif
+ desc->buf_len = MAX_MRU;
+ desc->pkt_len = 0;
+ queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc);
+ received++;
+ }
+
+#if DEBUG_RX
+ printk(KERN_DEBUG "eth_poll(): end, not all work done\n");
+#endif
+ return received; /* not all work done */
+}
+
+
+static void eth_txdone_irq(void *unused)
+{
+ u32 phys;
+
+#if DEBUG_TX
+ printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n");
+#endif
+ while ((phys = queue_get_entry(TXDONE_QUEUE)) != 0) {
+ u32 npe_id, n_desc;
+ struct port *port;
+ struct desc *desc;
+ int start;
+
+ npe_id = phys & 3;
+ BUG_ON(npe_id >= MAX_NPES);
+ port = npe_port_tab[npe_id];
+ BUG_ON(!port);
+ phys &= ~0x1F; /* mask out non-address bits */
+ n_desc = (phys - tx_desc_phys(port, 0)) / sizeof(struct desc);
+ BUG_ON(n_desc >= TX_DESCS);
+ desc = tx_desc_ptr(port, n_desc);
+ debug_desc(phys, desc);
+
+ if (port->tx_buff_tab[n_desc]) { /* not the draining packet */
+ port->stat.tx_packets++;
+ port->stat.tx_bytes += desc->pkt_len;
+
+ dma_unmap_tx(port, desc);
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_txdone_irq free %p\n",
+ port->netdev->name, port->tx_buff_tab[n_desc]);
+#endif
+ free_buffer_irq(port->tx_buff_tab[n_desc]);
+ port->tx_buff_tab[n_desc] = NULL;
+ }
+
+ start = qmgr_stat_empty(port->plat->txreadyq);
+ queue_put_desc(port->plat->txreadyq, phys, desc);
+ if (start) {
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_txdone_irq xmit ready\n",
+ port->netdev->name);
+#endif
+ netif_wake_queue(port->netdev);
+ }
+ }
+}
+
+static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ unsigned int txreadyq = port->plat->txreadyq;
+ int len, offset, bytes, n;
+ void *mem;
+ u32 phys;
+ struct desc *desc;
+
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit\n", dev->name);
+#endif
+
+ if (unlikely(skb->len > MAX_MRU)) {
+ dev_kfree_skb(skb);
+ port->stat.tx_errors++;
+ return NETDEV_TX_OK;
+ }
+
+ debug_pkt(dev, "eth_xmit", skb->data, skb->len);
+
+ len = skb->len;
+#ifdef __ARMEB__
+ offset = 0; /* no need to keep alignment */
+ bytes = len;
+ mem = skb->data;
+#else
+ offset = (int)skb->data & 3; /* keep 32-bit alignment */
+ bytes = ALIGN(offset + len, 4);
+ if (!(mem = kmalloc(bytes, GFP_ATOMIC))) {
+ dev_kfree_skb(skb);
+ port->stat.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+ memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4);
+ dev_kfree_skb(skb);
+#endif
+
+ phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE);
+ if (dma_mapping_error(phys)) {
+#ifdef __ARMEB__
+ dev_kfree_skb(skb);
+#else
+ kfree(mem);
+#endif
+ port->stat.tx_dropped++;
+ return NETDEV_TX_OK;
+ }
+
+ n = queue_get_desc(txreadyq, port, 1);
+ BUG_ON(n < 0);
+ desc = tx_desc_ptr(port, n);
+
+#ifdef __ARMEB__
+ port->tx_buff_tab[n] = skb;
+#else
+ port->tx_buff_tab[n] = mem;
+#endif
+ desc->data = phys + offset;
+ desc->buf_len = desc->pkt_len = len;
+
+ /* NPE firmware pads short frames with zeros internally */
+ wmb();
+ queue_put_desc(TX_QUEUE(port->id), tx_desc_phys(port, n), desc);
+ dev->trans_start = jiffies;
+
+ if (qmgr_stat_empty(txreadyq)) {
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit queue full\n", dev->name);
+#endif
+ netif_stop_queue(dev);
+ /* we could miss TX ready interrupt */
+ if (!qmgr_stat_empty(txreadyq)) {
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit ready again\n",
+ dev->name);
+#endif
+ netif_wake_queue(dev);
+ }
+ }
+
+#if DEBUG_TX
+ printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name);
+#endif
+ return NETDEV_TX_OK;
+}
+
+
+static struct net_device_stats *eth_stats(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ return &port->stat;
+}
+
+static void eth_set_mcast_list(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ struct dev_mc_list *mclist = dev->mc_list;
+ u8 diffs[ETH_ALEN], *addr;
+ int cnt = dev->mc_count, i;
+
+ if ((dev->flags & IFF_PROMISC) || !mclist || !cnt) {
+ __raw_writel(DEFAULT_RX_CNTRL0 & ~RX_CNTRL0_ADDR_FLTR_EN,
+ &port->regs->rx_control[0]);
+ return;
+ }
+
+ memset(diffs, 0, ETH_ALEN);
+ addr = mclist->dmi_addr; /* first MAC address */
+
+ while (--cnt && (mclist = mclist->next))
+ for (i = 0; i < ETH_ALEN; i++)
+ diffs[i] |= addr[i] ^ mclist->dmi_addr[i];
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ __raw_writel(addr[i], &port->regs->mcast_addr[i]);
+ __raw_writel(~diffs[i], &port->regs->mcast_mask[i]);
+ }
+
+ __raw_writel(DEFAULT_RX_CNTRL0 | RX_CNTRL0_ADDR_FLTR_EN,
+ &port->regs->rx_control[0]);
+}
+
+
+static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+ struct port *port = netdev_priv(dev);
+ unsigned int duplex_chg;
+ int err;
+
+ if (!netif_running(dev))
+ return -EINVAL;
+ err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg);
+ if (duplex_chg)
+ eth_set_duplex(port);
+ return err;
+}
+
+
+static int request_queues(struct port *port)
+{
+ int err;
+
+ err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0);
+ if (err)
+ return err;
+
+ err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0);
+ if (err)
+ goto rel_rxfree;
+
+ err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0);
+ if (err)
+ goto rel_rx;
+
+ err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0);
+ if (err)
+ goto rel_tx;
+
+ /* TX-done queue handles skbs sent out by the NPEs */
+ if (!ports_open) {
+ err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0);
+ if (err)
+ goto rel_txready;
+ }
+ return 0;
+
+rel_txready:
+ qmgr_release_queue(port->plat->txreadyq);
+rel_tx:
+ qmgr_release_queue(TX_QUEUE(port->id));
+rel_rx:
+ qmgr_release_queue(port->plat->rxq);
+rel_rxfree:
+ qmgr_release_queue(RXFREE_QUEUE(port->id));
+ printk(KERN_DEBUG "%s: unable to request hardware queues\n",
+ port->netdev->name);
+ return err;
+}
+
+static void release_queues(struct port *port)
+{
+ qmgr_release_queue(RXFREE_QUEUE(port->id));
+ qmgr_release_queue(port->plat->rxq);
+ qmgr_release_queue(TX_QUEUE(port->id));
+ qmgr_release_queue(port->plat->txreadyq);
+
+ if (!ports_open)
+ qmgr_release_queue(TXDONE_QUEUE);
+}
+
+static int init_queues(struct port *port)
+{
+ int i;
+
+ if (!ports_open)
+ if (!(dma_pool = dma_pool_create(DRV_NAME, NULL,
+ POOL_ALLOC_SIZE, 32, 0)))
+ return -ENOMEM;
+
+ if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL,
+ &port->desc_tab_phys)))
+ return -ENOMEM;
+ memset(port->desc_tab, 0, POOL_ALLOC_SIZE);
+ memset(port->rx_buff_tab, 0, sizeof(port->rx_buff_tab)); /* tables */
+ memset(port->tx_buff_tab, 0, sizeof(port->tx_buff_tab));
+
+ /* Setup RX buffers */
+ for (i = 0; i < RX_DESCS; i++) {
+ struct desc *desc = rx_desc_ptr(port, i);
+ buffer_t *buff; /* skb or kmalloc()ated memory */
+ void *data;
+#ifdef __ARMEB__
+ if (!(buff = netdev_alloc_skb(port->netdev, RX_BUFF_SIZE)))
+ return -ENOMEM;
+ data = buff->data;
+#else
+ if (!(buff = kmalloc(RX_BUFF_SIZE, GFP_KERNEL)))
+ return -ENOMEM;
+ data = buff;
+#endif
+ desc->buf_len = MAX_MRU;
+ desc->data = dma_map_single(&port->netdev->dev, data,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(desc->data)) {
+ free_buffer(buff);
+ return -EIO;
+ }
+ desc->data += NET_IP_ALIGN;
+ port->rx_buff_tab[i] = buff;
+ }
+
+ return 0;
+}
+
+static void destroy_queues(struct port *port)
+{
+ int i;
+
+ if (port->desc_tab) {
+ for (i = 0; i < RX_DESCS; i++) {
+ struct desc *desc = rx_desc_ptr(port, i);
+ buffer_t *buff = port->rx_buff_tab[i];
+ if (buff) {
+ dma_unmap_single(&port->netdev->dev,
+ desc->data - NET_IP_ALIGN,
+ RX_BUFF_SIZE, DMA_FROM_DEVICE);
+ free_buffer(buff);
+ }
+ }
+ for (i = 0; i < TX_DESCS; i++) {
+ struct desc *desc = tx_desc_ptr(port, i);
+ buffer_t *buff = port->tx_buff_tab[i];
+ if (buff) {
+ dma_unmap_tx(port, desc);
+ free_buffer(buff);
+ }
+ }
+ dma_pool_free(dma_pool, port->desc_tab, port->desc_tab_phys);
+ port->desc_tab = NULL;
+ }
+
+ if (!ports_open && dma_pool) {
+ dma_pool_destroy(dma_pool);
+ dma_pool = NULL;
+ }
+}
+
+static int eth_open(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ struct npe *npe = port->npe;
+ struct msg msg;
+ int i, err;
+
+ if (!npe_running(npe)) {
+ err = npe_load_firmware(npe, npe_name(npe), &dev->dev);
+ if (err)
+ return err;
+
+ if (npe_recv_message(npe, &msg, "ETH_GET_STATUS")) {
+ printk(KERN_ERR "%s: %s not responding\n", dev->name,
+ npe_name(npe));
+ return -EIO;
+ }
+ }
+
+ mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr);
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_VLAN_SETRXQOSENTRY;
+ msg.eth_id = port->id;
+ msg.byte5 = port->plat->rxq | 0x80;
+ msg.byte7 = port->plat->rxq << 4;
+ for (i = 0; i < 8; i++) {
+ msg.byte3 = i;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_RXQ"))
+ return -EIO;
+ }
+
+ msg.cmd = NPE_EDB_SETPORTADDRESS;
+ msg.eth_id = PHYSICAL_ID(port->id);
+ msg.byte2 = dev->dev_addr[0];
+ msg.byte3 = dev->dev_addr[1];
+ msg.byte4 = dev->dev_addr[2];
+ msg.byte5 = dev->dev_addr[3];
+ msg.byte6 = dev->dev_addr[4];
+ msg.byte7 = dev->dev_addr[5];
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_MAC"))
+ return -EIO;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_FW_SETFIREWALLMODE;
+ msg.eth_id = port->id;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_SET_FIREWALL_MODE"))
+ return -EIO;
+
+ if ((err = request_queues(port)) != 0)
+ return err;
+
+ if ((err = init_queues(port)) != 0) {
+ destroy_queues(port);
+ release_queues(port);
+ return err;
+ }
+
+ for (i = 0; i < ETH_ALEN; i++)
+ __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]);
+ __raw_writel(0x08, &port->regs->random_seed);
+ __raw_writel(0x12, &port->regs->partial_empty_threshold);
+ __raw_writel(0x30, &port->regs->partial_full_threshold);
+ __raw_writel(0x08, &port->regs->tx_start_bytes);
+ __raw_writel(0x15, &port->regs->tx_deferral);
+ __raw_writel(0x08, &port->regs->tx_2part_deferral[0]);
+ __raw_writel(0x07, &port->regs->tx_2part_deferral[1]);
+ __raw_writel(0x80, &port->regs->slot_time);
+ __raw_writel(0x01, &port->regs->int_clock_threshold);
+
+ /* Populate queues with buffers, no failure after this point */
+ for (i = 0; i < TX_DESCS; i++)
+ queue_put_desc(port->plat->txreadyq,
+ tx_desc_phys(port, i), tx_desc_ptr(port, i));
+
+ for (i = 0; i < RX_DESCS; i++)
+ queue_put_desc(RXFREE_QUEUE(port->id),
+ rx_desc_phys(port, i), rx_desc_ptr(port, i));
+
+ __raw_writel(TX_CNTRL1_RETRIES, &port->regs->tx_control[1]);
+ __raw_writel(DEFAULT_TX_CNTRL0, &port->regs->tx_control[0]);
+ __raw_writel(0, &port->regs->rx_control[1]);
+ __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]);
+
+ napi_enable(&port->napi);
+ phy_check_media(port, 1);
+ eth_set_mcast_list(dev);
+ netif_start_queue(dev);
+ schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL);
+
+ qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_rx_irq, dev);
+ if (!ports_open) {
+ qmgr_set_irq(TXDONE_QUEUE, QUEUE_IRQ_SRC_NOT_EMPTY,
+ eth_txdone_irq, NULL);
+ qmgr_enable_irq(TXDONE_QUEUE);
+ }
+ ports_open++;
+ /* we may already have RX data, enables IRQ */
+ netif_rx_schedule(dev, &port->napi);
+ return 0;
+}
+
+static int eth_close(struct net_device *dev)
+{
+ struct port *port = netdev_priv(dev);
+ struct msg msg;
+ int buffs = RX_DESCS; /* allocated RX buffers */
+ int i;
+
+ ports_open--;
+ qmgr_disable_irq(port->plat->rxq);
+ napi_disable(&port->napi);
+ netif_stop_queue(dev);
+
+ while (queue_get_desc(RXFREE_QUEUE(port->id), port, 0) >= 0)
+ buffs--;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd = NPE_SETLOOPBACK_MODE;
+ msg.eth_id = port->id;
+ msg.byte3 = 1;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_ENABLE_LOOPBACK"))
+ printk(KERN_CRIT "%s: unable to enable loopback\n", dev->name);
+
+ i = 0;
+ do { /* drain RX buffers */
+ while (queue_get_desc(port->plat->rxq, port, 0) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ if (qmgr_stat_empty(TX_QUEUE(port->id))) {
+ /* we have to inject some packet */
+ struct desc *desc;
+ u32 phys;
+ int n = queue_get_desc(port->plat->txreadyq, port, 1);
+ BUG_ON(n < 0);
+ desc = tx_desc_ptr(port, n);
+ phys = tx_desc_phys(port, n);
+ desc->buf_len = desc->pkt_len = 1;
+ wmb();
+ queue_put_desc(TX_QUEUE(port->id), phys, desc);
+ }
+ udelay(1);
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ printk(KERN_CRIT "%s: unable to drain RX queue, %i buffer(s)"
+ " left in NPE\n", dev->name, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ printk(KERN_DEBUG "Draining RX queue took %i cycles\n", i);
+#endif
+
+ buffs = TX_DESCS;
+ while (queue_get_desc(TX_QUEUE(port->id), port, 1) >= 0)
+ buffs--; /* cancel TX */
+
+ i = 0;
+ do {
+ while (queue_get_desc(port->plat->txreadyq, port, 1) >= 0)
+ buffs--;
+ if (!buffs)
+ break;
+ } while (++i < MAX_CLOSE_WAIT);
+
+ if (buffs)
+ printk(KERN_CRIT "%s: unable to drain TX queue, %i buffer(s) "
+ "left in NPE\n", dev->name, buffs);
+#if DEBUG_CLOSE
+ if (!buffs)
+ printk(KERN_DEBUG "Draining TX queues took %i cycles\n", i);
+#endif
+
+ msg.byte3 = 0;
+ if (npe_send_recv_message(port->npe, &msg, "ETH_DISABLE_LOOPBACK"))
+ printk(KERN_CRIT "%s: unable to disable loopback\n",
+ dev->name);
+
+ port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) &
+ ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */
+ mdio_write(dev, port->plat->phy, MII_BMCR,
+ port->mii_bmcr | BMCR_PDOWN);
+
+ if (!ports_open)
+ qmgr_disable_irq(TXDONE_QUEUE);
+ cancel_rearming_delayed_work(&port->mdio_thread);
+ destroy_queues(port);
+ release_queues(port);
+ return 0;
+}
+
+static int __devinit eth_init_one(struct platform_device *pdev)
+{
+ struct port *port;
+ struct net_device *dev;
+ struct eth_plat_info *plat = pdev->dev.platform_data;
+ u32 regs_phys;
+ int err;
+
+ if (!(dev = alloc_etherdev(sizeof(struct port))))
+ return -ENOMEM;
+
+ SET_NETDEV_DEV(dev, &pdev->dev);
+ port = netdev_priv(dev);
+ port->netdev = dev;
+ port->id = pdev->id;
+
+ switch (port->id) {
+ case IXP4XX_ETH_NPEA:
+ port->regs = (struct eth_regs __iomem *)IXP4XX_EthA_BASE_VIRT;
+ regs_phys = IXP4XX_EthA_BASE_PHYS;
+ break;
+ case IXP4XX_ETH_NPEB:
+ port->regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
+ regs_phys = IXP4XX_EthB_BASE_PHYS;
+ break;
+ case IXP4XX_ETH_NPEC:
+ port->regs = (struct eth_regs __iomem *)IXP4XX_EthC_BASE_VIRT;
+ regs_phys = IXP4XX_EthC_BASE_PHYS;
+ break;
+ default:
+ err = -ENOSYS;
+ goto err_free;
+ }
+
+ dev->open = eth_open;
+ dev->hard_start_xmit = eth_xmit;
+ dev->stop = eth_close;
+ dev->get_stats = eth_stats;
+ dev->do_ioctl = eth_ioctl;
+ dev->set_multicast_list = eth_set_mcast_list;
+ dev->tx_queue_len = 100;
+
+ netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT);
+
+ if (!(port->npe = npe_request(NPE_ID(port->id)))) {
+ err = -EIO;
+ goto err_free;
+ }
+
+ if (register_netdev(dev)) {
+ err = -EIO;
+ goto err_npe_rel;
+ }
+
+ port->mem_res = request_mem_region(regs_phys, REGS_SIZE, dev->name);
+ if (!port->mem_res) {
+ err = -EBUSY;
+ goto err_unreg;
+ }
+
+ port->plat = plat;
+ npe_port_tab[NPE_ID(port->id)] = port;
+ memcpy(dev->dev_addr, plat->hwaddr, ETH_ALEN);
+
+ platform_set_drvdata(pdev, dev);
+
+ __raw_writel(DEFAULT_CORE_CNTRL | CORE_RESET,
+ &port->regs->core_control);
+ udelay(50);
+ __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control);
+ udelay(50);
+
+ port->mii.dev = dev;
+ port->mii.mdio_read = mdio_read;
+ port->mii.mdio_write = mdio_write;
+ port->mii.phy_id = plat->phy;
+ port->mii.phy_id_mask = 0x1F;
+ port->mii.reg_num_mask = 0x1F;
+
+ printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy,
+ npe_name(port->npe));
+
+ phy_reset(dev, plat->phy);
+ port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) &
+ ~(BMCR_RESET | BMCR_PDOWN);
+ mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN);
+
+ INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread);
+ return 0;
+
+err_unreg:
+ unregister_netdev(dev);
+err_npe_rel:
+ npe_release(port->npe);
+err_free:
+ free_netdev(dev);
+ return err;
+}
+
+static int __devexit eth_remove_one(struct platform_device *pdev)
+{
+ struct net_device *dev = platform_get_drvdata(pdev);
+ struct port *port = netdev_priv(dev);
+
+ unregister_netdev(dev);
+ npe_port_tab[NPE_ID(port->id)] = NULL;
+ platform_set_drvdata(pdev, NULL);
+ npe_release(port->npe);
+ release_resource(port->mem_res);
+ free_netdev(dev);
+ return 0;
+}
+
+static struct platform_driver drv = {
+ .driver.name = DRV_NAME,
+ .probe = eth_init_one,
+ .remove = eth_remove_one,
+};
+
+static int __init eth_init_module(void)
+{
+ if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0))
+ return -ENOSYS;
+
+ /* All MII PHY accesses use NPE-B Ethernet registers */
+ spin_lock_init(&mdio_lock);
+ mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT;
+ __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control);
+
+ return platform_driver_register(&drv);
+}
+
+static void __exit eth_cleanup_module(void)
+{
+ platform_driver_unregister(&drv);
+}
+
+MODULE_AUTHOR("Krzysztof Halasa");
+MODULE_DESCRIPTION("Intel IXP4xx Ethernet driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:ixp4xx_eth");
+module_init(eth_init_module);
+module_exit(eth_cleanup_module);
diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c
index 4fec858..89c0018 100644
--- a/drivers/net/bfin_mac.c
+++ b/drivers/net/bfin_mac.c
@@ -27,6 +27,7 @@
#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/skbuff.h>
#include <linux/platform_device.h>
@@ -42,7 +43,7 @@
#define DRV_NAME "bfin_mac"
#define DRV_VERSION "1.1"
#define DRV_AUTHOR "Bryan Wu, Luke Yang"
-#define DRV_DESC "Blackfin BF53[67] BF527 on-chip Ethernet MAC driver"
+#define DRV_DESC "Blackfin on-chip Ethernet MAC driver"
MODULE_AUTHOR(DRV_AUTHOR);
MODULE_LICENSE("GPL");
@@ -73,8 +74,14 @@
static struct net_dma_desc_tx *tx_desc;
static struct net_dma_desc_rx *rx_desc;
-static void bf537mac_disable(void);
-static void bf537mac_enable(void);
+#if defined(CONFIG_BFIN_MAC_RMII)
+static u16 pin_req[] = P_RMII0;
+#else
+static u16 pin_req[] = P_MII0;
+#endif
+
+static void bfin_mac_disable(void);
+static void bfin_mac_enable(void);
static void desc_list_free(void)
{
@@ -243,27 +250,6 @@
/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
-/* Set FER regs to MUX in Ethernet pins */
-static int setup_pin_mux(int action)
-{
-#if defined(CONFIG_BFIN_MAC_RMII)
- u16 pin_req[] = P_RMII0;
-#else
- u16 pin_req[] = P_MII0;
-#endif
-
- if (action) {
- if (peripheral_request_list(pin_req, DRV_NAME)) {
- printk(KERN_ERR DRV_NAME
- ": Requesting Peripherals failed\n");
- return -EFAULT;
- }
- } else
- peripheral_free_list(pin_req);
-
- return 0;
-}
-
/*
* MII operations
*/
@@ -322,9 +308,9 @@
return 0;
}
-static void bf537_adjust_link(struct net_device *dev)
+static void bfin_mac_adjust_link(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = lp->phydev;
unsigned long flags;
int new_state = 0;
@@ -395,7 +381,7 @@
static int mii_probe(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
struct phy_device *phydev = NULL;
unsigned short sysctl;
int i;
@@ -431,10 +417,10 @@
}
#if defined(CONFIG_BFIN_MAC_RMII)
- phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
PHY_INTERFACE_MODE_RMII);
#else
- phydev = phy_connect(dev, phydev->dev.bus_id, &bf537_adjust_link, 0,
+ phydev = phy_connect(dev, phydev->dev.bus_id, &bfin_mac_adjust_link, 0,
PHY_INTERFACE_MODE_MII);
#endif
@@ -469,6 +455,51 @@
return 0;
}
+/*
+ * Ethtool support
+ */
+
+static int
+bfin_mac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+
+ if (lp->phydev)
+ return phy_ethtool_gset(lp->phydev, cmd);
+
+ return -EINVAL;
+}
+
+static int
+bfin_mac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+ struct bfin_mac_local *lp = netdev_priv(dev);
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (lp->phydev)
+ return phy_ethtool_sset(lp->phydev, cmd);
+
+ return -EINVAL;
+}
+
+static void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ strcpy(info->driver, DRV_NAME);
+ strcpy(info->version, DRV_VERSION);
+ strcpy(info->fw_version, "N/A");
+ strcpy(info->bus_info, dev->dev.bus_id);
+}
+
+static struct ethtool_ops bfin_mac_ethtool_ops = {
+ .get_settings = bfin_mac_ethtool_getsettings,
+ .set_settings = bfin_mac_ethtool_setsettings,
+ .get_link = ethtool_op_get_link,
+ .get_drvinfo = bfin_mac_ethtool_getdrvinfo,
+};
+
/**************************************************************************/
void setup_system_regs(struct net_device *dev)
{
@@ -511,7 +542,7 @@
bfin_write_EMAC_ADDRHI(addr_hi);
}
-static int bf537mac_set_mac_address(struct net_device *dev, void *p)
+static int bfin_mac_set_mac_address(struct net_device *dev, void *p)
{
struct sockaddr *addr = p;
if (netif_running(dev))
@@ -573,7 +604,7 @@
}
-static int bf537mac_hard_start_xmit(struct sk_buff *skb,
+static int bfin_mac_hard_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
unsigned int data;
@@ -631,7 +662,7 @@
return 0;
}
-static void bf537mac_rx(struct net_device *dev)
+static void bfin_mac_rx(struct net_device *dev)
{
struct sk_buff *skb, *new_skb;
unsigned short len;
@@ -680,7 +711,7 @@
}
/* interrupt routine to handle rx and error signal */
-static irqreturn_t bf537mac_interrupt(int irq, void *dev_id)
+static irqreturn_t bfin_mac_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
int number = 0;
@@ -700,21 +731,21 @@
}
real_rx:
- bf537mac_rx(dev);
+ bfin_mac_rx(dev);
number++;
goto get_one_packet;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
-static void bf537mac_poll(struct net_device *dev)
+static void bfin_mac_poll(struct net_device *dev)
{
disable_irq(IRQ_MAC_RX);
- bf537mac_interrupt(IRQ_MAC_RX, dev);
+ bfin_mac_interrupt(IRQ_MAC_RX, dev);
enable_irq(IRQ_MAC_RX);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
-static void bf537mac_disable(void)
+static void bfin_mac_disable(void)
{
unsigned int opmode;
@@ -728,7 +759,7 @@
/*
* Enable Interrupts, Receive, and Transmit
*/
-static void bf537mac_enable(void)
+static void bfin_mac_enable(void)
{
u32 opmode;
@@ -766,23 +797,23 @@
}
/* Our watchdog timed out. Called by the networking layer */
-static void bf537mac_timeout(struct net_device *dev)
+static void bfin_mac_timeout(struct net_device *dev)
{
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
- bf537mac_disable();
+ bfin_mac_disable();
/* reset tx queue */
tx_list_tail = tx_list_head->next;
- bf537mac_enable();
+ bfin_mac_enable();
/* We can accept TX packets again */
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
-static void bf537mac_multicast_hash(struct net_device *dev)
+static void bfin_mac_multicast_hash(struct net_device *dev)
{
u32 emac_hashhi, emac_hashlo;
struct dev_mc_list *dmi = dev->mc_list;
@@ -821,7 +852,7 @@
* promiscuous mode (for TCPDUMP and cousins) or accept
* a select set of multicast packets
*/
-static void bf537mac_set_multicast_list(struct net_device *dev)
+static void bfin_mac_set_multicast_list(struct net_device *dev)
{
u32 sysctl;
@@ -840,7 +871,7 @@
sysctl = bfin_read_EMAC_OPMODE();
sysctl |= HM;
bfin_write_EMAC_OPMODE(sysctl);
- bf537mac_multicast_hash(dev);
+ bfin_mac_multicast_hash(dev);
} else {
/* clear promisc or multicast mode */
sysctl = bfin_read_EMAC_OPMODE();
@@ -852,7 +883,7 @@
/*
* this puts the device in an inactive state
*/
-static void bf537mac_shutdown(struct net_device *dev)
+static void bfin_mac_shutdown(struct net_device *dev)
{
/* Turn off the EMAC */
bfin_write_EMAC_OPMODE(0x00000000);
@@ -866,9 +897,9 @@
*
* Set up everything, reset the card, etc..
*/
-static int bf537mac_open(struct net_device *dev)
+static int bfin_mac_open(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
int retval;
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
@@ -891,8 +922,8 @@
phy_start(lp->phydev);
phy_write(lp->phydev, MII_BMCR, BMCR_RESET);
setup_system_regs(dev);
- bf537mac_disable();
- bf537mac_enable();
+ bfin_mac_disable();
+ bfin_mac_enable();
pr_debug("hardware init finished\n");
netif_start_queue(dev);
netif_carrier_on(dev);
@@ -906,9 +937,9 @@
* and not talk to the outside world. Caused by
* an 'ifconfig ethX down'
*/
-static int bf537mac_close(struct net_device *dev)
+static int bfin_mac_close(struct net_device *dev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
+ struct bfin_mac_local *lp = netdev_priv(dev);
pr_debug("%s: %s\n", dev->name, __FUNCTION__);
netif_stop_queue(dev);
@@ -918,7 +949,7 @@
phy_write(lp->phydev, MII_BMCR, BMCR_PDOWN);
/* clear everything */
- bf537mac_shutdown(dev);
+ bfin_mac_shutdown(dev);
/* free the rx/tx buffers */
desc_list_free();
@@ -926,46 +957,59 @@
return 0;
}
-static int __init bf537mac_probe(struct net_device *dev)
+static int __init bfin_mac_probe(struct platform_device *pdev)
{
- struct bf537mac_local *lp = netdev_priv(dev);
- int retval;
- int i;
+ struct net_device *ndev;
+ struct bfin_mac_local *lp;
+ int rc, i;
+
+ ndev = alloc_etherdev(sizeof(struct bfin_mac_local));
+ if (!ndev) {
+ dev_err(&pdev->dev, "Cannot allocate net device!\n");
+ return -ENOMEM;
+ }
+
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+ platform_set_drvdata(pdev, ndev);
+ lp = netdev_priv(ndev);
/* Grab the MAC address in the MAC */
- *(__le32 *) (&(dev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
- *(__le16 *) (&(dev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
+ *(__le32 *) (&(ndev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
+ *(__le16 *) (&(ndev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
/* probe mac */
/*todo: how to proble? which is revision_register */
bfin_write_EMAC_ADDRLO(0x12345678);
if (bfin_read_EMAC_ADDRLO() != 0x12345678) {
- pr_debug("can't detect bf537 mac!\n");
- retval = -ENODEV;
- goto err_out;
+ dev_err(&pdev->dev, "Cannot detect Blackfin on-chip ethernet MAC controller!\n");
+ rc = -ENODEV;
+ goto out_err_probe_mac;
}
/* set the GPIO pins to Ethernet mode */
- retval = setup_pin_mux(1);
- if (retval)
- return retval;
-
- /*Is it valid? (Did bootloader initialize it?) */
- if (!is_valid_ether_addr(dev->dev_addr)) {
- /* Grab the MAC from the board somehow - this is done in the
- arch/blackfin/mach-bf537/boards/eth_mac.c */
- bfin_get_ether_addr(dev->dev_addr);
+ rc = peripheral_request_list(pin_req, DRV_NAME);
+ if (rc) {
+ dev_err(&pdev->dev, "Requesting peripherals failed!\n");
+ rc = -EFAULT;
+ goto out_err_setup_pin_mux;
}
+ /*
+ * Is it valid? (Did bootloader initialize it?)
+ * Grab the MAC from the board somehow
+ * this is done in the arch/blackfin/mach-bfxxx/boards/eth_mac.c
+ */
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ bfin_get_ether_addr(ndev->dev_addr);
+
/* If still not valid, get a random one */
- if (!is_valid_ether_addr(dev->dev_addr)) {
- random_ether_addr(dev->dev_addr);
- }
+ if (!is_valid_ether_addr(ndev->dev_addr))
+ random_ether_addr(ndev->dev_addr);
- setup_mac_addr(dev->dev_addr);
+ setup_mac_addr(ndev->dev_addr);
/* MDIO bus initial */
- lp->mii_bus.priv = dev;
+ lp->mii_bus.priv = ndev;
lp->mii_bus.read = mdiobus_read;
lp->mii_bus.write = mdiobus_write;
lp->mii_bus.reset = mdiobus_reset;
@@ -975,86 +1019,86 @@
for (i = 0; i < PHY_MAX_ADDR; ++i)
lp->mii_bus.irq[i] = PHY_POLL;
- mdiobus_register(&lp->mii_bus);
+ rc = mdiobus_register(&lp->mii_bus);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
+ goto out_err_mdiobus_register;
+ }
- retval = mii_probe(dev);
- if (retval)
- return retval;
+ rc = mii_probe(ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "MII Probe failed!\n");
+ goto out_err_mii_probe;
+ }
/* Fill in the fields of the device structure with ethernet values. */
- ether_setup(dev);
+ ether_setup(ndev);
- dev->open = bf537mac_open;
- dev->stop = bf537mac_close;
- dev->hard_start_xmit = bf537mac_hard_start_xmit;
- dev->set_mac_address = bf537mac_set_mac_address;
- dev->tx_timeout = bf537mac_timeout;
- dev->set_multicast_list = bf537mac_set_multicast_list;
+ ndev->open = bfin_mac_open;
+ ndev->stop = bfin_mac_close;
+ ndev->hard_start_xmit = bfin_mac_hard_start_xmit;
+ ndev->set_mac_address = bfin_mac_set_mac_address;
+ ndev->tx_timeout = bfin_mac_timeout;
+ ndev->set_multicast_list = bfin_mac_set_multicast_list;
#ifdef CONFIG_NET_POLL_CONTROLLER
- dev->poll_controller = bf537mac_poll;
+ ndev->poll_controller = bfin_mac_poll;
#endif
+ ndev->ethtool_ops = &bfin_mac_ethtool_ops;
spin_lock_init(&lp->lock);
/* now, enable interrupts */
/* register irq handler */
- if (request_irq
- (IRQ_MAC_RX, bf537mac_interrupt, IRQF_DISABLED | IRQF_SHARED,
- "EMAC_RX", dev)) {
- printk(KERN_WARNING DRV_NAME
- ": Unable to attach BlackFin MAC RX interrupt\n");
- return -EBUSY;
+ rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt,
+ IRQF_DISABLED | IRQF_SHARED, "EMAC_RX", ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n");
+ rc = -EBUSY;
+ goto out_err_request_irq;
}
-
- retval = register_netdev(dev);
- if (retval == 0) {
- /* now, print out the card info, in a short format.. */
- printk(KERN_INFO "%s: Version %s, %s\n",
- DRV_NAME, DRV_VERSION, DRV_DESC);
+ rc = register_netdev(ndev);
+ if (rc) {
+ dev_err(&pdev->dev, "Cannot register net device!\n");
+ goto out_err_reg_ndev;
}
-err_out:
- return retval;
-}
-
-static int bfin_mac_probe(struct platform_device *pdev)
-{
- struct net_device *ndev;
-
- ndev = alloc_etherdev(sizeof(struct bf537mac_local));
- if (!ndev) {
- printk(KERN_WARNING DRV_NAME ": could not allocate device\n");
- return -ENOMEM;
- }
-
- SET_NETDEV_DEV(ndev, &pdev->dev);
-
- platform_set_drvdata(pdev, ndev);
-
- if (bf537mac_probe(ndev) != 0) {
- platform_set_drvdata(pdev, NULL);
- free_netdev(ndev);
- printk(KERN_WARNING DRV_NAME ": not found\n");
- return -ENODEV;
- }
+ /* now, print out the card info, in a short format.. */
+ dev_info(&pdev->dev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
return 0;
+
+out_err_reg_ndev:
+ free_irq(IRQ_MAC_RX, ndev);
+out_err_request_irq:
+out_err_mii_probe:
+ mdiobus_unregister(&lp->mii_bus);
+out_err_mdiobus_register:
+ peripheral_free_list(pin_req);
+out_err_setup_pin_mux:
+out_err_probe_mac:
+ platform_set_drvdata(pdev, NULL);
+ free_netdev(ndev);
+
+ return rc;
}
static int bfin_mac_remove(struct platform_device *pdev)
{
struct net_device *ndev = platform_get_drvdata(pdev);
+ struct bfin_mac_local *lp = netdev_priv(ndev);
platform_set_drvdata(pdev, NULL);
+ mdiobus_unregister(&lp->mii_bus);
+
unregister_netdev(ndev);
free_irq(IRQ_MAC_RX, ndev);
free_netdev(ndev);
- setup_pin_mux(0);
+ peripheral_free_list(pin_req);
return 0;
}
@@ -1065,7 +1109,7 @@
struct net_device *net_dev = platform_get_drvdata(pdev);
if (netif_running(net_dev))
- bf537mac_close(net_dev);
+ bfin_mac_close(net_dev);
return 0;
}
@@ -1075,7 +1119,7 @@
struct net_device *net_dev = platform_get_drvdata(pdev);
if (netif_running(net_dev))
- bf537mac_open(net_dev);
+ bfin_mac_open(net_dev);
return 0;
}
diff --git a/drivers/net/bfin_mac.h b/drivers/net/bfin_mac.h
index f774d5a..beff510 100644
--- a/drivers/net/bfin_mac.h
+++ b/drivers/net/bfin_mac.h
@@ -49,7 +49,7 @@
struct status_area_tx status;
};
-struct bf537mac_local {
+struct bfin_mac_local {
/*
* these are things that the kernel wants me to keep, so users
* can find out semi-useless statistics of how well the card is
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 6e91b4b..6425603 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3282,17 +3282,14 @@
struct net_device *bond_dev = bond->dev;
if (bond_proc_dir) {
- bond->proc_entry = create_proc_entry(bond_dev->name,
- S_IRUGO,
- bond_proc_dir);
+ bond->proc_entry = proc_create_data(bond_dev->name,
+ S_IRUGO, bond_proc_dir,
+ &bond_info_fops, bond);
if (bond->proc_entry == NULL) {
printk(KERN_WARNING DRV_NAME
": Warning: Cannot create /proc/net/%s/%s\n",
DRV_NAME, bond_dev->name);
} else {
- bond->proc_entry->data = bond;
- bond->proc_entry->proc_fops = &bond_info_fops;
- bond->proc_entry->owner = THIS_MODULE;
memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ);
}
}
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
index 229303f..a0177fc 100644
--- a/drivers/net/cxgb3/version.h
+++ b/drivers/net/cxgb3/version.h
@@ -38,7 +38,7 @@
#define DRV_VERSION "1.0-ko"
/* Firmware version */
-#define FW_VERSION_MAJOR 5
+#define FW_VERSION_MAJOR 6
#define FW_VERSION_MINOR 0
#define FW_VERSION_MICRO 0
#endif /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 2d139ec..f3cba5e 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1802,7 +1802,7 @@
* it is protected by the before last buffer's el bit being set */
if (rx->prev->skb) {
struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;
- put_unaligned(cpu_to_le32(rx->dma_addr), &prev_rfd->link);
+ put_unaligned_le32(rx->dma_addr, &prev_rfd->link);
}
return 0;
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 83bda6c..56f5049 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -633,7 +633,7 @@
printk(KERN_DEBUG " PC: %d\n", GetBit(Word,ee_PC));
printk(KERN_DEBUG " TPE/AUI: %d\n", GetBit(Word,ee_TPE_AUI));
printk(KERN_DEBUG " Jabber: %d\n", GetBit(Word,ee_Jabber));
- printk(KERN_DEBUG " AutoPort: %d\n", GetBit(!Word,ee_Jabber));
+ printk(KERN_DEBUG " AutoPort: %d\n", !GetBit(Word,ee_AutoPort));
printk(KERN_DEBUG " Duplex: %d\n", GetBit(Word,ee_Duplex));
}
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index d7a3ea8..32a4f17 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -67,6 +67,10 @@
#define FEC_MAX_PORTS 1
#endif
+#if defined(CONFIG_FADS) || defined(CONFIG_RPXCLASSIC) || defined(CONFIG_M5272)
+#define HAVE_mii_link_interrupt
+#endif
+
/*
* Define the fixed address of the FEC hardware.
*/
@@ -205,7 +209,10 @@
cbd_t *cur_rx, *cur_tx; /* The next free ring entry */
cbd_t *dirty_tx; /* The ring entries to be free()ed. */
uint tx_full;
- spinlock_t lock;
+ /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
+ spinlock_t hw_lock;
+ /* hold while accessing the mii_list_t() elements */
+ spinlock_t mii_lock;
uint phy_id;
uint phy_id_done;
@@ -309,6 +316,7 @@
volatile fec_t *fecp;
volatile cbd_t *bdp;
unsigned short status;
+ unsigned long flags;
fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr;
@@ -318,6 +326,7 @@
return 1;
}
+ spin_lock_irqsave(&fep->hw_lock, flags);
/* Fill in a Tx ring entry */
bdp = fep->cur_tx;
@@ -328,6 +337,7 @@
* This should not happen, since dev->tbusy should be set.
*/
printk("%s: tx queue full!.\n", dev->name);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
return 1;
}
#endif
@@ -366,8 +376,6 @@
flush_dcache_range((unsigned long)skb->data,
(unsigned long)skb->data + skb->len);
- spin_lock_irq(&fep->lock);
-
/* Send it on its way. Tell FEC it's ready, interrupt when done,
* it's the last BD of the frame, and to put the CRC on the end.
*/
@@ -396,7 +404,7 @@
fep->cur_tx = (cbd_t *)bdp;
- spin_unlock_irq(&fep->lock);
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
return 0;
}
@@ -454,19 +462,20 @@
struct net_device *dev = dev_id;
volatile fec_t *fecp;
uint int_events;
- int handled = 0;
+ irqreturn_t ret = IRQ_NONE;
fecp = (volatile fec_t*)dev->base_addr;
/* Get the interrupt events that caused us to be here.
*/
- while ((int_events = fecp->fec_ievent) != 0) {
+ do {
+ int_events = fecp->fec_ievent;
fecp->fec_ievent = int_events;
/* Handle receive event in its own function.
*/
if (int_events & FEC_ENET_RXF) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_rx(dev);
}
@@ -475,17 +484,18 @@
them as part of the transmit process.
*/
if (int_events & FEC_ENET_TXF) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_tx(dev);
}
if (int_events & FEC_ENET_MII) {
- handled = 1;
+ ret = IRQ_HANDLED;
fec_enet_mii(dev);
}
- }
- return IRQ_RETVAL(handled);
+ } while (int_events);
+
+ return ret;
}
@@ -498,7 +508,7 @@
struct sk_buff *skb;
fep = netdev_priv(dev);
- spin_lock(&fep->lock);
+ spin_lock_irq(&fep->hw_lock);
bdp = fep->dirty_tx;
while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
@@ -557,7 +567,7 @@
}
}
fep->dirty_tx = (cbd_t *)bdp;
- spin_unlock(&fep->lock);
+ spin_unlock_irq(&fep->hw_lock);
}
@@ -584,6 +594,8 @@
fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr;
+ spin_lock_irq(&fep->hw_lock);
+
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
*/
@@ -689,6 +701,8 @@
*/
fecp->fec_r_des_active = 0;
#endif
+
+ spin_unlock_irq(&fep->hw_lock);
}
@@ -702,11 +716,11 @@
uint mii_reg;
fep = netdev_priv(dev);
+ spin_lock_irq(&fep->mii_lock);
+
ep = fep->hwp;
mii_reg = ep->fec_mii_data;
- spin_lock(&fep->lock);
-
if ((mip = mii_head) == NULL) {
printk("MII and no head!\n");
goto unlock;
@@ -723,7 +737,7 @@
ep->fec_mii_data = mip->mii_regval;
unlock:
- spin_unlock(&fep->lock);
+ spin_unlock_irq(&fep->mii_lock);
}
static int
@@ -737,12 +751,11 @@
/* Add PHY address to register command.
*/
fep = netdev_priv(dev);
+ spin_lock_irqsave(&fep->mii_lock, flags);
+
regval |= fep->phy_addr << 23;
-
retval = 0;
- spin_lock_irqsave(&fep->lock,flags);
-
if ((mip = mii_free) != NULL) {
mii_free = mip->mii_next;
mip->mii_regval = regval;
@@ -759,9 +772,8 @@
retval = 1;
}
- spin_unlock_irqrestore(&fep->lock,flags);
-
- return(retval);
+ spin_unlock_irqrestore(&fep->mii_lock, flags);
+ return retval;
}
static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
@@ -1222,7 +1234,7 @@
};
/* ------------------------------------------------------------------------- */
-#if !defined(CONFIG_M532x)
+#ifdef HAVE_mii_link_interrupt
#ifdef CONFIG_RPXCLASSIC
static void
mii_link_interrupt(void *dev_id);
@@ -1362,18 +1374,8 @@
unsigned short irq;
} *idp, id[] = {
{ "fec(TXF)", 23 },
- { "fec(TXB)", 24 },
- { "fec(TXFIFO)", 25 },
- { "fec(TXCR)", 26 },
{ "fec(RXF)", 27 },
- { "fec(RXB)", 28 },
{ "fec(MII)", 29 },
- { "fec(LC)", 30 },
- { "fec(HBERR)", 31 },
- { "fec(GRA)", 32 },
- { "fec(EBERR)", 33 },
- { "fec(BABT)", 34 },
- { "fec(BABR)", 35 },
{ NULL },
};
@@ -1533,18 +1535,8 @@
unsigned short irq;
} *idp, id[] = {
{ "fec(TXF)", 23 },
- { "fec(TXB)", 24 },
- { "fec(TXFIFO)", 25 },
- { "fec(TXCR)", 26 },
{ "fec(RXF)", 27 },
- { "fec(RXB)", 28 },
{ "fec(MII)", 29 },
- { "fec(LC)", 30 },
- { "fec(HBERR)", 31 },
- { "fec(GRA)", 32 },
- { "fec(EBERR)", 33 },
- { "fec(BABT)", 34 },
- { "fec(BABR)", 35 },
{ NULL },
};
@@ -1660,18 +1652,8 @@
unsigned short irq;
} *idp, id[] = {
{ "fec(TXF)", 36 },
- { "fec(TXB)", 37 },
- { "fec(TXFIFO)", 38 },
- { "fec(TXCR)", 39 },
{ "fec(RXF)", 40 },
- { "fec(RXB)", 41 },
{ "fec(MII)", 42 },
- { "fec(LC)", 43 },
- { "fec(HBERR)", 44 },
- { "fec(GRA)", 45 },
- { "fec(EBERR)", 46 },
- { "fec(BABT)", 47 },
- { "fec(BABR)", 48 },
{ NULL },
};
@@ -2126,6 +2108,7 @@
/* This interrupt occurs when the PHY detects a link change.
*/
+#ifdef HAVE_mii_link_interrupt
#ifdef CONFIG_RPXCLASSIC
static void
mii_link_interrupt(void *dev_id)
@@ -2148,6 +2131,7 @@
return IRQ_HANDLED;
}
+#endif
static int
fec_enet_open(struct net_device *dev)
@@ -2243,13 +2227,13 @@
/* Catch all multicast addresses, so set the
* filter to all 1's.
*/
- ep->fec_hash_table_high = 0xffffffff;
- ep->fec_hash_table_low = 0xffffffff;
+ ep->fec_grp_hash_table_high = 0xffffffff;
+ ep->fec_grp_hash_table_low = 0xffffffff;
} else {
/* Clear filter and add the addresses in hash register.
*/
- ep->fec_hash_table_high = 0;
- ep->fec_hash_table_low = 0;
+ ep->fec_grp_hash_table_high = 0;
+ ep->fec_grp_hash_table_low = 0;
dmi = dev->mc_list;
@@ -2280,9 +2264,9 @@
hash = (crc >> (32 - HASH_BITS)) & 0x3f;
if (hash > 31)
- ep->fec_hash_table_high |= 1 << (hash - 32);
+ ep->fec_grp_hash_table_high |= 1 << (hash - 32);
else
- ep->fec_hash_table_low |= 1 << hash;
+ ep->fec_grp_hash_table_low |= 1 << hash;
}
}
}
@@ -2332,6 +2316,9 @@
return -ENOMEM;
}
+ spin_lock_init(&fep->hw_lock);
+ spin_lock_init(&fep->mii_lock);
+
/* Create an Ethernet device instance.
*/
fecp = (volatile fec_t *) fec_hw[index];
@@ -2430,11 +2417,15 @@
*/
fec_request_intrs(dev);
- fecp->fec_hash_table_high = 0;
- fecp->fec_hash_table_low = 0;
+ fecp->fec_grp_hash_table_high = 0;
+ fecp->fec_grp_hash_table_low = 0;
fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
fecp->fec_ecntrl = 2;
fecp->fec_r_des_active = 0;
+#ifndef CONFIG_M5272
+ fecp->fec_hash_table_high = 0;
+ fecp->fec_hash_table_low = 0;
+#endif
dev->base_addr = (unsigned long)fecp;
@@ -2455,8 +2446,7 @@
/* Clear and enable interrupts */
fecp->fec_ievent = 0xffc00000;
- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
/* Queue up command to detect the PHY and initialize the
* remainder of the interface.
@@ -2500,8 +2490,8 @@
/* Reset all multicast.
*/
- fecp->fec_hash_table_high = 0;
- fecp->fec_hash_table_low = 0;
+ fecp->fec_grp_hash_table_high = 0;
+ fecp->fec_grp_hash_table_low = 0;
/* Set maximum receive buffer size.
*/
@@ -2583,8 +2573,7 @@
/* Enable interrupts we wish to service.
*/
- fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB |
- FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
+ fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
}
static void
@@ -2624,7 +2613,7 @@
static int __init fec_enet_module_init(void)
{
struct net_device *dev;
- int i, j, err;
+ int i, err;
DECLARE_MAC_BUF(mac);
printk("FEC ENET Version 0.2\n");
diff --git a/drivers/net/fec.h b/drivers/net/fec.h
index 1d42160..292719d 100644
--- a/drivers/net/fec.h
+++ b/drivers/net/fec.h
@@ -88,8 +88,8 @@
unsigned long fec_reserved7[158];
unsigned long fec_addr_low; /* Low 32bits MAC address */
unsigned long fec_addr_high; /* High 16bits MAC address */
- unsigned long fec_hash_table_high; /* High 32bits hash table */
- unsigned long fec_hash_table_low; /* Low 32bits hash table */
+ unsigned long fec_grp_hash_table_high;/* High 32bits hash table */
+ unsigned long fec_grp_hash_table_low; /* Low 32bits hash table */
unsigned long fec_r_des_start; /* Receive descriptor ring */
unsigned long fec_x_des_start; /* Transmit descriptor ring */
unsigned long fec_r_buff_size; /* Maximum receive buff size */
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 99a4b99..587afe7 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -131,8 +131,6 @@
static void gfar_set_multi(struct net_device *dev);
static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr);
static void gfar_configure_serdes(struct net_device *dev);
-extern int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id, int regnum, u16 value);
-extern int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
#ifdef CONFIG_GFAR_NAPI
static int gfar_poll(struct napi_struct *napi, int budget);
#endif
@@ -477,24 +475,30 @@
return 0;
}
+/*
+ * Initialize TBI PHY interface for communicating with the
+ * SERDES lynx PHY on the chip. We communicate with this PHY
+ * through the MDIO bus on each controller, treating it as a
+ * "normal" PHY at the address found in the TBIPA register. We assume
+ * that the TBIPA register is valid. Either the MDIO bus code will set
+ * it to a value that doesn't conflict with other PHYs on the bus, or the
+ * value doesn't matter, as there are no other PHYs on the bus.
+ */
static void gfar_configure_serdes(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar_mii __iomem *regs =
(void __iomem *)&priv->regs->gfar_mii_regs;
+ int tbipa = gfar_read(&priv->regs->tbipa);
- /* Initialise TBI i/f to communicate with serdes (lynx phy) */
+ /* Single clk mode, mii mode off(for serdes communication) */
+ gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT);
- /* Single clk mode, mii mode off(for aerdes communication) */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_TBICON, TBICON_CLK_SELECT);
-
- /* Supported pause and full-duplex, no half-duplex */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_ADVERTISE,
+ gfar_local_mdio_write(regs, tbipa, MII_ADVERTISE,
ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE |
ADVERTISE_1000XPSE_ASYM);
- /* ANEG enable, restart ANEG, full duplex mode, speed[1] set */
- gfar_local_mdio_write(regs, TBIPA_VALUE, MII_BMCR, BMCR_ANENABLE |
+ gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE |
BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000);
}
@@ -541,9 +545,6 @@
/* Initialize the Minimum Frame Length Register */
gfar_write(&priv->regs->minflr, MINFLR_INIT_SETTINGS);
-
- /* Assign the TBI an address which won't conflict with the PHYs */
- gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index 0d08836..fd487be 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -137,7 +137,6 @@
#define DEFAULT_RXCOUNT 0
#endif /* CONFIG_GFAR_NAPI */
-#define TBIPA_VALUE 0x1f
#define MIIMCFG_INIT_VALUE 0x00000007
#define MIIMCFG_RESET 0x80000000
#define MIIMIND_BUSY 0x00000001
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
index b889892..ebcfb27 100644
--- a/drivers/net/gianfar_mii.c
+++ b/drivers/net/gianfar_mii.c
@@ -78,7 +78,6 @@
* same as system mdio bus, used for controlling the external PHYs, for eg.
*/
int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum)
-
{
u16 value;
@@ -122,7 +121,7 @@
}
/* Reset the MIIM registers, and wait for the bus to free */
-int gfar_mdio_reset(struct mii_bus *bus)
+static int gfar_mdio_reset(struct mii_bus *bus)
{
struct gfar_mii __iomem *regs = (void __iomem *)bus->priv;
unsigned int timeout = PHY_INIT_TIMEOUT;
@@ -152,14 +151,15 @@
}
-int gfar_mdio_probe(struct device *dev)
+static int gfar_mdio_probe(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gianfar_mdio_data *pdata;
struct gfar_mii __iomem *regs;
+ struct gfar __iomem *enet_regs;
struct mii_bus *new_bus;
struct resource *r;
- int err = 0;
+ int i, err = 0;
if (NULL == dev)
return -EINVAL;
@@ -199,6 +199,34 @@
new_bus->dev = dev;
dev_set_drvdata(dev, new_bus);
+ /*
+ * This is mildly evil, but so is our hardware for doing this.
+ * Also, we have to cast back to struct gfar_mii because of
+ * definition weirdness done in gianfar.h.
+ */
+ enet_regs = (struct gfar __iomem *)
+ ((char *)regs - offsetof(struct gfar, gfar_mii_regs));
+
+ /* Scan the bus, looking for an empty spot for TBIPA */
+ gfar_write(&enet_regs->tbipa, 0);
+ for (i = PHY_MAX_ADDR; i > 0; i--) {
+ u32 phy_id;
+ int r;
+
+ r = get_phy_id(new_bus, i, &phy_id);
+ if (r)
+ return r;
+
+ if (phy_id == 0xffffffff)
+ break;
+ }
+
+ /* The bus is full. We don't support using 31 PHYs, sorry */
+ if (i == 0)
+ return -EBUSY;
+
+ gfar_write(&enet_regs->tbipa, i);
+
err = mdiobus_register(new_bus);
if (0 != err) {
@@ -218,7 +246,7 @@
}
-int gfar_mdio_remove(struct device *dev)
+static int gfar_mdio_remove(struct device *dev)
{
struct mii_bus *bus = dev_get_drvdata(dev);
diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h
index b373091..2af28b1 100644
--- a/drivers/net/gianfar_mii.h
+++ b/drivers/net/gianfar_mii.h
@@ -41,6 +41,9 @@
int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum);
int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value);
+int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
+ int regnum, u16 value);
+int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum);
int __init gfar_mdio_init(void);
void gfar_mdio_exit(void);
#endif /* GIANFAR_PHY_H */
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index b53f6b6..e5c2380 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1508,7 +1508,7 @@
hmp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
buf_addr = (u8 *) hmp->rx_skbuff[entry]->data;
- frame_status = le32_to_cpu(get_unaligned((__le32*)&(buf_addr[data_size - 12])));
+ frame_status = get_unaligned_le32(&(buf_addr[data_size - 12]));
if (hamachi_debug > 4)
printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n",
frame_status);
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 1da55dd..9d57212 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -148,13 +148,13 @@
if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
sp->led_state = 0x70;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
- actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
+ actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
sp->xleft -= actual;
sp->xhead += actual;
sp->led_state = 0x60;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->status2 = 0;
} else
mod_timer(&sp->tx_t, jiffies + ((when + 1) * HZ) / 100);
@@ -220,13 +220,13 @@
*/
if (sp->duplex == 1) {
sp->led_state = 0x70;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
- actual = sp->tty->driver->write(sp->tty, sp->xbuff, count);
+ actual = sp->tty->ops->write(sp->tty, sp->xbuff, count);
sp->xleft = count - actual;
sp->xhead = sp->xbuff + actual;
sp->led_state = 0x60;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
} else {
sp->xleft = count;
sp->xhead = sp->xbuff;
@@ -444,7 +444,7 @@
}
if (sp->tx_enable) {
- actual = tty->driver->write(tty, sp->xhead, sp->xleft);
+ actual = tty->ops->write(tty, sp->xhead, sp->xleft);
sp->xleft -= actual;
sp->xhead += actual;
}
@@ -491,9 +491,7 @@
sixpack_decode(sp, buf, count1);
sp_put(sp);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
/*
@@ -554,8 +552,8 @@
/* resync the TNC */
sp->led_state = 0x60;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
- sp->tty->driver->write(sp->tty, &resync_cmd, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &resync_cmd, 1);
/* Start resync timer again -- the TNC might be still absent */
@@ -573,7 +571,7 @@
tnc_set_sync_state(sp, TNC_UNSYNC_STARTUP);
- sp->tty->driver->write(sp->tty, &inbyte, 1);
+ sp->tty->ops->write(sp->tty, &inbyte, 1);
del_timer(&sp->resync_t);
sp->resync_t.data = (unsigned long) sp;
@@ -601,6 +599,8 @@
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
if (!dev) {
@@ -914,9 +914,9 @@
} else { /* output watchdog char if idle */
if ((sp->status2 != 0) && (sp->duplex == 1)) {
sp->led_state = 0x70;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
sp->tx_enable = 1;
- actual = sp->tty->driver->write(sp->tty, sp->xbuff, sp->status2);
+ actual = sp->tty->ops->write(sp->tty, sp->xbuff, sp->status2);
sp->xleft -= actual;
sp->xhead += actual;
sp->led_state = 0x60;
@@ -926,7 +926,7 @@
}
/* needed to trigger the TNC watchdog */
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
/* if the state byte has been received, the TNC is present,
so the resync timer can be reset. */
@@ -956,12 +956,12 @@
if ((sp->status & SIXP_RX_DCD_MASK) ==
SIXP_RX_DCD_MASK) {
sp->led_state = 0x68;
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
}
} else {
sp->led_state = 0x60;
/* fill trailing bytes with zeroes */
- sp->tty->driver->write(sp->tty, &sp->led_state, 1);
+ sp->tty->ops->write(sp->tty, &sp->led_state, 1);
rest = sp->rx_count;
if (rest != 0)
for (i = rest; i <= 3; i++)
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index 30c9b3b0..6516603 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -516,7 +516,7 @@
spin_unlock_bh(&ax->buflock);
set_bit(TTY_DO_WRITE_WAKEUP, &ax->tty->flags);
- actual = ax->tty->driver->write(ax->tty, ax->xbuff, count);
+ actual = ax->tty->ops->write(ax->tty, ax->xbuff, count);
ax->stats.tx_packets++;
ax->stats.tx_bytes += actual;
@@ -546,7 +546,7 @@
}
printk(KERN_ERR "mkiss: %s: transmit timed out, %s?\n", dev->name,
- (ax->tty->driver->chars_in_buffer(ax->tty) || ax->xleft) ?
+ (ax->tty->ops->chars_in_buffer(ax->tty) || ax->xleft) ?
"bad line quality" : "driver error");
ax->xleft = 0;
@@ -736,6 +736,8 @@
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
dev = alloc_netdev(sizeof(struct mkiss), "ax%d", ax_setup);
if (!dev) {
@@ -754,8 +756,7 @@
tty->disc_data = ax;
tty->receive_room = 65535;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
/* Restore default settings */
dev->type = ARPHRD_AX25;
@@ -935,9 +936,7 @@
}
mkiss_put(ax);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
/*
@@ -962,7 +961,7 @@
goto out;
}
- actual = tty->driver->write(tty, ax->xhead, ax->xleft);
+ actual = tty->ops->write(tty, ax->xhead, ax->xleft);
ax->xleft -= actual;
ax->xhead += actual;
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index ce4fc2e..0052780 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -1302,13 +1302,10 @@
if (ibmveth_proc_dir) {
char u_addr[10];
sprintf(u_addr, "%x", adapter->vdev->unit_address);
- entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir);
- if (!entry) {
+ entry = proc_create_data(u_addr, S_IFREG, ibmveth_proc_dir,
+ &ibmveth_proc_fops, adapter);
+ if (!entry)
ibmveth_error_printk("Cannot create adapter proc entry");
- } else {
- entry->data = (void *) adapter;
- entry->proc_fops = &ibmveth_proc_fops;
- }
}
return;
}
diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
index fc753d7..e6f40b7 100644
--- a/drivers/net/irda/irtty-sir.c
+++ b/drivers/net/irda/irtty-sir.c
@@ -64,7 +64,7 @@
IRDA_ASSERT(priv != NULL, return -1;);
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
- return priv->tty->driver->chars_in_buffer(priv->tty);
+ return tty_chars_in_buffer(priv->tty);
}
/* Wait (sleep) until underlaying hardware finished transmission
@@ -93,10 +93,8 @@
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
tty = priv->tty;
- if (tty->driver->wait_until_sent) {
- lock_kernel();
- tty->driver->wait_until_sent(tty, msecs_to_jiffies(100));
- unlock_kernel();
+ if (tty->ops->wait_until_sent) {
+ tty->ops->wait_until_sent(tty, msecs_to_jiffies(100));
}
else {
msleep(USBSERIAL_TX_DONE_DELAY);
@@ -125,48 +123,14 @@
tty = priv->tty;
- lock_kernel();
+ mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios);
cflag = tty->termios->c_cflag;
-
- cflag &= ~CBAUD;
-
- IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed);
-
- switch (speed) {
- case 1200:
- cflag |= B1200;
- break;
- case 2400:
- cflag |= B2400;
- break;
- case 4800:
- cflag |= B4800;
- break;
- case 19200:
- cflag |= B19200;
- break;
- case 38400:
- cflag |= B38400;
- break;
- case 57600:
- cflag |= B57600;
- break;
- case 115200:
- cflag |= B115200;
- break;
- case 9600:
- default:
- cflag |= B9600;
- break;
- }
-
- tty->termios->c_cflag = cflag;
- if (tty->driver->set_termios)
- tty->driver->set_termios(tty, &old_termios);
- unlock_kernel();
-
+ tty_encode_baud_rate(tty, speed, speed);
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, &old_termios);
priv->io.speed = speed;
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
@@ -202,8 +166,8 @@
* This function is not yet defined for all tty driver, so
* let's be careful... Jean II
*/
- IRDA_ASSERT(priv->tty->driver->tiocmset != NULL, return -1;);
- priv->tty->driver->tiocmset(priv->tty, NULL, set, clear);
+ IRDA_ASSERT(priv->tty->ops->tiocmset != NULL, return -1;);
+ priv->tty->ops->tiocmset(priv->tty, NULL, set, clear);
return 0;
}
@@ -225,17 +189,13 @@
IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
tty = priv->tty;
- if (!tty->driver->write)
+ if (!tty->ops->write)
return 0;
tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- if (tty->driver->write_room) {
- writelen = tty->driver->write_room(tty);
- if (writelen > len)
- writelen = len;
- }
- else
+ writelen = tty_write_room(tty);
+ if (writelen > len)
writelen = len;
- return tty->driver->write(tty, ptr, writelen);
+ return tty->ops->write(tty, ptr, writelen);
}
/* ------------------------------------------------------- */
@@ -321,7 +281,7 @@
struct ktermios old_termios;
int cflag;
- lock_kernel();
+ mutex_lock(&tty->termios_mutex);
old_termios = *(tty->termios);
cflag = tty->termios->c_cflag;
@@ -331,9 +291,9 @@
cflag |= CREAD;
tty->termios->c_cflag = cflag;
- if (tty->driver->set_termios)
- tty->driver->set_termios(tty, &old_termios);
- unlock_kernel();
+ if (tty->ops->set_termios)
+ tty->ops->set_termios(tty, &old_termios);
+ mutex_unlock(&tty->termios_mutex);
}
/*****************************************************************/
@@ -359,8 +319,8 @@
tty = priv->tty;
- if (tty->driver->start)
- tty->driver->start(tty);
+ if (tty->ops->start)
+ tty->ops->start(tty);
/* Make sure we can receive more data */
irtty_stop_receiver(tty, FALSE);
@@ -388,8 +348,8 @@
/* Make sure we don't receive more data */
irtty_stop_receiver(tty, TRUE);
- if (tty->driver->stop)
- tty->driver->stop(tty);
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
mutex_unlock(&irtty_mutex);
@@ -483,11 +443,10 @@
/* stop the underlying driver */
irtty_stop_receiver(tty, TRUE);
- if (tty->driver->stop)
- tty->driver->stop(tty);
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
/* apply mtt override */
sir_tty_drv.qos_mtt_bits = qos_mtt_bits;
@@ -564,8 +523,8 @@
/* Stop tty */
irtty_stop_receiver(tty, TRUE);
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
- if (tty->driver->stop)
- tty->driver->stop(tty);
+ if (tty->ops->stop)
+ tty->ops->stop(tty);
kfree(priv);
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 93916cf..ad92d3f 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -464,7 +464,7 @@
}
fcs = ~(crc32_le(~0, buf, new_len));
- if(fcs != le32_to_cpu(get_unaligned((__le32 *)(buf+new_len)))) {
+ if(fcs != get_unaligned_le32(buf + new_len)) {
IRDA_ERROR("crc error calc 0x%x len %d\n", fcs, new_len);
mcs->stats.rx_errors++;
mcs->stats.rx_crc_errors++;
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index e59c485..0519637 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -329,7 +329,7 @@
}
fcs = ~(crc32_le(~0, rx_buff->data, len));
- if (fcs != le32_to_cpu(get_unaligned((__le32 *)(rx_buff->data+len)))) {
+ if (fcs != get_unaligned_le32(rx_buff->data + len)) {
pr_debug("crc error calc 0x%x len %d\n", fcs, len);
stir->stats.rx_errors++;
stir->stats.rx_crc_errors++;
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index acd082a..d15e00b 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -1674,13 +1674,12 @@
if (vlsi_proc_root != NULL) {
struct proc_dir_entry *ent;
- ent = create_proc_entry(ndev->name, S_IFREG|S_IRUGO, vlsi_proc_root);
+ ent = proc_create_data(ndev->name, S_IFREG|S_IRUGO,
+ vlsi_proc_root, VLSI_PROC_FOPS, ndev);
if (!ent) {
IRDA_WARNING("%s: failed to create proc entry\n",
__FUNCTION__);
} else {
- ent->data = ndev;
- ent->proc_fops = VLSI_PROC_FOPS;
ent->size = 0;
}
idev->proc_entry = ent;
diff --git a/drivers/net/mlx4/cq.c b/drivers/net/mlx4/cq.c
index 6fda0af..95e87a2 100644
--- a/drivers/net/mlx4/cq.c
+++ b/drivers/net/mlx4/cq.c
@@ -188,7 +188,8 @@
EXPORT_SYMBOL_GPL(mlx4_cq_resize);
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
- struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq)
+ struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
+ int collapsed)
{
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_cq_table *cq_table = &priv->cq_table;
@@ -224,6 +225,7 @@
cq_context = mailbox->buf;
memset(cq_context, 0, sizeof *cq_context);
+ cq_context->flags = cpu_to_be32(!!collapsed << 18);
cq_context->logsize_usrpage = cpu_to_be32((ilog2(nent) << 24) | uar->index);
cq_context->comp_eqn = priv->eq_table.eq[MLX4_EQ_COMP].eqn;
cq_context->log_page_size = mtt->page_shift - MLX4_ICM_PAGE_SHIFT;
diff --git a/drivers/net/mlx4/mr.c b/drivers/net/mlx4/mr.c
index 79b317b..cb46446 100644
--- a/drivers/net/mlx4/mr.c
+++ b/drivers/net/mlx4/mr.c
@@ -607,15 +607,9 @@
void mlx4_fmr_unmap(struct mlx4_dev *dev, struct mlx4_fmr *fmr,
u32 *lkey, u32 *rkey)
{
- u32 key;
-
if (!fmr->maps)
return;
- key = key_to_hw_index(fmr->mr.key);
- key &= dev->caps.num_mpts - 1;
- *lkey = *rkey = fmr->mr.key = hw_index_to_key(key);
-
fmr->maps = 0;
*(u8 *) fmr->mpt = MLX4_MPT_STATUS_SW;
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index cead81e..ef63c8d 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -2437,7 +2437,7 @@
int status;
segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6);
- if (unlikely(IS_ERR(segs)))
+ if (IS_ERR(segs))
goto drop;
while (segs) {
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3ac8529..6bf9e76 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -48,7 +48,7 @@
config SMSC_PHY
tristate "Drivers for SMSC PHYs"
---help---
- Currently supports the LAN83C185 PHY
+ Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs
config BROADCOM_PHY
tristate "Drivers for Broadcom PHYs"
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index ddf8d51..ac3c01d 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -256,7 +256,7 @@
/**
* phy_connect - connect an ethernet device to a PHY device
* @dev: the network device to connect
- * @phy_id: the PHY device to connect
+ * @bus_id: the id string of the PHY device to connect
* @handler: callback function for state change notifications
* @flags: PHY device's dev_flags
* @interface: PHY device's interface
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index b1d8ed4..73baa7a 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -12,6 +12,8 @@
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
+ * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@smsc.com
+ *
*/
#include <linux/kernel.h>
@@ -38,7 +40,7 @@
(MII_LAN83C185_ISF_INT6 | MII_LAN83C185_ISF_INT4)
-static int lan83c185_config_intr(struct phy_device *phydev)
+static int smsc_phy_config_intr(struct phy_device *phydev)
{
int rc = phy_write (phydev, MII_LAN83C185_IM,
((PHY_INTERRUPT_ENABLED == phydev->interrupts)
@@ -48,16 +50,16 @@
return rc < 0 ? rc : 0;
}
-static int lan83c185_ack_interrupt(struct phy_device *phydev)
+static int smsc_phy_ack_interrupt(struct phy_device *phydev)
{
int rc = phy_read (phydev, MII_LAN83C185_ISF);
return rc < 0 ? rc : 0;
}
-static int lan83c185_config_init(struct phy_device *phydev)
+static int smsc_phy_config_init(struct phy_device *phydev)
{
- return lan83c185_ack_interrupt (phydev);
+ return smsc_phy_ack_interrupt (phydev);
}
@@ -73,22 +75,87 @@
/* basic functions */
.config_aneg = genphy_config_aneg,
.read_status = genphy_read_status,
- .config_init = lan83c185_config_init,
+ .config_init = smsc_phy_config_init,
/* IRQ related */
- .ack_interrupt = lan83c185_ack_interrupt,
- .config_intr = lan83c185_config_intr,
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
+
+ .driver = { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan8187_driver = {
+ .phy_id = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */
+ .phy_id_mask = 0xfffffff0,
+ .name = "SMSC LAN8187",
+
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+ /* basic functions */
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .config_init = smsc_phy_config_init,
+
+ /* IRQ related */
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
+
+ .driver = { .owner = THIS_MODULE, }
+};
+
+static struct phy_driver lan8700_driver = {
+ .phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */
+ .phy_id_mask = 0xfffffff0,
+ .name = "SMSC LAN8700",
+
+ .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
+ | SUPPORTED_Asym_Pause),
+ .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
+
+ /* basic functions */
+ .config_aneg = genphy_config_aneg,
+ .read_status = genphy_read_status,
+ .config_init = smsc_phy_config_init,
+
+ /* IRQ related */
+ .ack_interrupt = smsc_phy_ack_interrupt,
+ .config_intr = smsc_phy_config_intr,
.driver = { .owner = THIS_MODULE, }
};
static int __init smsc_init(void)
{
- return phy_driver_register (&lan83c185_driver);
+ int ret;
+
+ ret = phy_driver_register (&lan83c185_driver);
+ if (ret)
+ goto err1;
+
+ ret = phy_driver_register (&lan8187_driver);
+ if (ret)
+ goto err2;
+
+ ret = phy_driver_register (&lan8700_driver);
+ if (ret)
+ goto err3;
+
+ return 0;
+
+err3:
+ phy_driver_unregister (&lan8187_driver);
+err2:
+ phy_driver_unregister (&lan83c185_driver);
+err1:
+ return ret;
}
static void __exit smsc_exit(void)
{
+ phy_driver_unregister (&lan8700_driver);
+ phy_driver_unregister (&lan8187_driver);
phy_driver_unregister (&lan83c185_driver);
}
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index f023d5b..f1a52de 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -158,6 +158,9 @@
struct asyncppp *ap;
int err;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
err = -ENOMEM;
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
if (!ap)
@@ -358,9 +361,7 @@
if (!skb_queue_empty(&ap->rqueue))
tasklet_schedule(&ap->tsk);
ap_put(ap);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
static void
@@ -676,7 +677,7 @@
if (!tty_stuffed && ap->optr < ap->olim) {
avail = ap->olim - ap->optr;
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, ap->optr, avail);
+ sent = tty->ops->write(tty, ap->optr, avail);
if (sent < 0)
goto flush; /* error, e.g. loss of CD */
ap->optr += sent;
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index 0d80fa5..b8f0369 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -207,6 +207,9 @@
struct syncppp *ap;
int err;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
ap = kzalloc(sizeof(*ap), GFP_KERNEL);
err = -ENOMEM;
if (!ap)
@@ -398,9 +401,7 @@
if (!skb_queue_empty(&ap->rqueue))
tasklet_schedule(&ap->tsk);
sp_put(ap);
- if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
- && tty->driver->unthrottle)
- tty->driver->unthrottle(tty);
+ tty_unthrottle(tty);
}
static void
@@ -653,7 +654,7 @@
tty_stuffed = 0;
if (!tty_stuffed && ap->tpkt) {
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
- sent = tty->driver->write(tty, ap->tpkt->data, ap->tpkt->len);
+ sent = tty->ops->write(tty, ap->tpkt->data, ap->tpkt->len);
if (sent < 0)
goto flush; /* error, e.g. loss of CD */
if (sent < ap->tpkt->len) {
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 4fad4dd..58a26a4 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -1052,11 +1052,9 @@
{
struct proc_dir_entry *p;
- p = create_proc_entry("pppoe", S_IRUGO, init_net.proc_net);
+ p = proc_net_fops_create(&init_net, "pppoe", S_IRUGO, &pppoe_seq_fops);
if (!p)
return -ENOMEM;
-
- p->proc_fops = &pppoe_seq_fops;
return 0;
}
#else /* CONFIG_PROC_FS */
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 3d10ca0..244d783 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -2469,12 +2469,12 @@
goto out_unregister_pppol2tp_proto;
#ifdef CONFIG_PROC_FS
- pppol2tp_proc = create_proc_entry("pppol2tp", 0, init_net.proc_net);
+ pppol2tp_proc = proc_net_fops_create(&init_net, "pppol2tp", 0,
+ &pppol2tp_proc_fops);
if (!pppol2tp_proc) {
err = -ENOMEM;
goto out_unregister_pppox_proto;
}
- pppol2tp_proc->proc_fops = &pppol2tp_proc_fops;
#endif /* CONFIG_PROC_FS */
printk(KERN_INFO "PPPoL2TP kernel driver, %s\n",
PPPOL2TP_DRV_VERSION);
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 3acfeea..6572425 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1617,6 +1617,7 @@
SET_NETDEV_DEV(dev, &pdev->dev);
tp = netdev_priv(dev);
tp->dev = dev;
+ tp->pci_dev = pdev;
tp->msg_enable = netif_msg_init(debug.msg_enable, R8169_MSG_DEFAULT);
/* enable device (incl. PCI PM wakeup and hotplug setup) */
@@ -1705,18 +1706,18 @@
rtl8169_print_mac_version(tp);
- for (i = ARRAY_SIZE(rtl_chip_info) - 1; i >= 0; i--) {
+ for (i = 0; i < ARRAY_SIZE(rtl_chip_info); i++) {
if (tp->mac_version == rtl_chip_info[i].mac_version)
break;
}
- if (i < 0) {
+ if (i == ARRAY_SIZE(rtl_chip_info)) {
/* Unknown chip: assume array element #0, original RTL-8169 */
if (netif_msg_probe(tp)) {
dev_printk(KERN_DEBUG, &pdev->dev,
"unknown chip version, assuming %s\n",
rtl_chip_info[0].name);
}
- i++;
+ i = 0;
}
tp->chipset = i;
@@ -1777,7 +1778,6 @@
#endif
tp->intr_mask = 0xffff;
- tp->pci_dev = pdev;
tp->mmio_addr = ioaddr;
tp->align = cfg->align;
tp->hw_start = cfg->hw_start;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 157fd93..523478e 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -86,7 +86,7 @@
#include "s2io.h"
#include "s2io-regs.h"
-#define DRV_VERSION "2.0.26.22"
+#define DRV_VERSION "2.0.26.23"
/* S2io Driver name & version. */
static char s2io_driver_name[] = "Neterion";
@@ -809,6 +809,7 @@
config->rx_cfg[i].num_rxd - 1;
mac_control->rings[i].nic = nic;
mac_control->rings[i].ring_no = i;
+ mac_control->rings[i].lro = lro_enable;
blk_cnt = config->rx_cfg[i].num_rxd /
(rxd_count[nic->rxd_mode] + 1);
@@ -1560,113 +1561,112 @@
writeq(val64, &bar0->tx_fifo_partition_0);
/* Filling the Rx round robin registers as per the
- * number of Rings and steering based on QoS.
- */
+ * number of Rings and steering based on QoS with
+ * equal priority.
+ */
switch (config->rx_ring_num) {
case 1:
+ val64 = 0x0;
+ writeq(val64, &bar0->rx_w_round_robin_0);
+ writeq(val64, &bar0->rx_w_round_robin_1);
+ writeq(val64, &bar0->rx_w_round_robin_2);
+ writeq(val64, &bar0->rx_w_round_robin_3);
+ writeq(val64, &bar0->rx_w_round_robin_4);
+
val64 = 0x8080808080808080ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 2:
- val64 = 0x0000010000010000ULL;
+ val64 = 0x0001000100010001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0100000100000100ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0001000001000001ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0000010000010000ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0100000000000000ULL;
+ val64 = 0x0001000100000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080808040404040ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 3:
- val64 = 0x0001000102000001ULL;
+ val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0001020000010001ULL;
+ val64 = 0x0200010200010200ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0200000100010200ULL;
+ val64 = 0x0102000102000102ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001000102000001ULL;
+ val64 = 0x0001020001020001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0001020000000000ULL;
+ val64 = 0x0200010200000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080804040402020ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 4:
- val64 = 0x0001020300010200ULL;
+ val64 = 0x0001020300010203ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0100000102030001ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0200010000010203ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001020001000001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0203000100000000ULL;
+ val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020201010ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 5:
- val64 = 0x0001000203000102ULL;
+ val64 = 0x0001020304000102ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0001020001030004ULL;
+ val64 = 0x0304000102030400ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0001000203000102ULL;
+ val64 = 0x0102030400010203ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0001020001030004ULL;
+ val64 = 0x0400010203040001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0001000000000000ULL;
+ val64 = 0x0203040000000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020201008ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 6:
- val64 = 0x0001020304000102ULL;
+ val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0304050001020001ULL;
+ val64 = 0x0203040500010203ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0203000100000102ULL;
+ val64 = 0x0405000102030405ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0304000102030405ULL;
+ val64 = 0x0001020304050001ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0001000200000000ULL;
+ val64 = 0x0203040500000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080404020100804ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 7:
- val64 = 0x0001020001020300ULL;
+ val64 = 0x0001020304050600ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0102030400010203ULL;
+ val64 = 0x0102030405060001ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0405060001020001ULL;
+ val64 = 0x0203040506000102ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0304050000010200ULL;
+ val64 = 0x0304050600010203ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0102030000000000ULL;
+ val64 = 0x0405060000000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8080402010080402ULL;
writeq(val64, &bar0->rts_qos_steering);
break;
case 8:
- val64 = 0x0001020300040105ULL;
+ val64 = 0x0001020304050607ULL;
writeq(val64, &bar0->rx_w_round_robin_0);
- val64 = 0x0200030106000204ULL;
writeq(val64, &bar0->rx_w_round_robin_1);
- val64 = 0x0103000502010007ULL;
writeq(val64, &bar0->rx_w_round_robin_2);
- val64 = 0x0304010002060500ULL;
writeq(val64, &bar0->rx_w_round_robin_3);
- val64 = 0x0103020400000000ULL;
+ val64 = 0x0001020300000000ULL;
writeq(val64, &bar0->rx_w_round_robin_4);
val64 = 0x8040201008040201ULL;
@@ -2499,8 +2499,7 @@
/**
* fill_rx_buffers - Allocates the Rx side skbs
- * @nic: device private variable
- * @ring_no: ring number
+ * @ring_info: per ring structure
* Description:
* The function allocates Rx side skbs and puts the physical
* address of these buffers into the RxD buffer pointers, so that the NIC
@@ -2518,103 +2517,94 @@
* SUCCESS on success or an appropriate -ve value on failure.
*/
-static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
+static int fill_rx_buffers(struct ring_info *ring)
{
- struct net_device *dev = nic->dev;
struct sk_buff *skb;
struct RxD_t *rxdp;
- int off, off1, size, block_no, block_no1;
+ int off, size, block_no, block_no1;
u32 alloc_tab = 0;
u32 alloc_cnt;
- struct mac_info *mac_control;
- struct config_param *config;
u64 tmp;
struct buffAdd *ba;
struct RxD_t *first_rxdp = NULL;
u64 Buffer0_ptr = 0, Buffer1_ptr = 0;
+ int rxd_index = 0;
struct RxD1 *rxdp1;
struct RxD3 *rxdp3;
- struct swStat *stats = &nic->mac_control.stats_info->sw_stat;
+ struct swStat *stats = &ring->nic->mac_control.stats_info->sw_stat;
- mac_control = &nic->mac_control;
- config = &nic->config;
- alloc_cnt = mac_control->rings[ring_no].pkt_cnt -
- atomic_read(&nic->rx_bufs_left[ring_no]);
+ alloc_cnt = ring->pkt_cnt - ring->rx_bufs_left;
- block_no1 = mac_control->rings[ring_no].rx_curr_get_info.block_index;
- off1 = mac_control->rings[ring_no].rx_curr_get_info.offset;
+ block_no1 = ring->rx_curr_get_info.block_index;
while (alloc_tab < alloc_cnt) {
- block_no = mac_control->rings[ring_no].rx_curr_put_info.
- block_index;
- off = mac_control->rings[ring_no].rx_curr_put_info.offset;
+ block_no = ring->rx_curr_put_info.block_index;
- rxdp = mac_control->rings[ring_no].
- rx_blocks[block_no].rxds[off].virt_addr;
+ off = ring->rx_curr_put_info.offset;
- if ((block_no == block_no1) && (off == off1) &&
- (rxdp->Host_Control)) {
+ rxdp = ring->rx_blocks[block_no].rxds[off].virt_addr;
+
+ rxd_index = off + 1;
+ if (block_no)
+ rxd_index += (block_no * ring->rxd_count);
+
+ if ((block_no == block_no1) &&
+ (off == ring->rx_curr_get_info.offset) &&
+ (rxdp->Host_Control)) {
DBG_PRINT(INTR_DBG, "%s: Get and Put",
- dev->name);
+ ring->dev->name);
DBG_PRINT(INTR_DBG, " info equated\n");
goto end;
}
- if (off && (off == rxd_count[nic->rxd_mode])) {
- mac_control->rings[ring_no].rx_curr_put_info.
- block_index++;
- if (mac_control->rings[ring_no].rx_curr_put_info.
- block_index == mac_control->rings[ring_no].
- block_count)
- mac_control->rings[ring_no].rx_curr_put_info.
- block_index = 0;
- block_no = mac_control->rings[ring_no].
- rx_curr_put_info.block_index;
- if (off == rxd_count[nic->rxd_mode])
- off = 0;
- mac_control->rings[ring_no].rx_curr_put_info.
- offset = off;
- rxdp = mac_control->rings[ring_no].
- rx_blocks[block_no].block_virt_addr;
+ if (off && (off == ring->rxd_count)) {
+ ring->rx_curr_put_info.block_index++;
+ if (ring->rx_curr_put_info.block_index ==
+ ring->block_count)
+ ring->rx_curr_put_info.block_index = 0;
+ block_no = ring->rx_curr_put_info.block_index;
+ off = 0;
+ ring->rx_curr_put_info.offset = off;
+ rxdp = ring->rx_blocks[block_no].block_virt_addr;
DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
- dev->name, rxdp);
+ ring->dev->name, rxdp);
+
}
if ((rxdp->Control_1 & RXD_OWN_XENA) &&
- ((nic->rxd_mode == RXD_MODE_3B) &&
+ ((ring->rxd_mode == RXD_MODE_3B) &&
(rxdp->Control_2 & s2BIT(0)))) {
- mac_control->rings[ring_no].rx_curr_put_info.
- offset = off;
+ ring->rx_curr_put_info.offset = off;
goto end;
}
/* calculate size of skb based on ring mode */
- size = dev->mtu + HEADER_ETHERNET_II_802_3_SIZE +
+ size = ring->mtu + HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE + HEADER_SNAP_SIZE;
- if (nic->rxd_mode == RXD_MODE_1)
+ if (ring->rxd_mode == RXD_MODE_1)
size += NET_IP_ALIGN;
else
- size = dev->mtu + ALIGN_SIZE + BUF0_LEN + 4;
+ size = ring->mtu + ALIGN_SIZE + BUF0_LEN + 4;
/* allocate skb */
skb = dev_alloc_skb(size);
if(!skb) {
- DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name);
+ DBG_PRINT(INFO_DBG, "%s: Out of ", ring->dev->name);
DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n");
if (first_rxdp) {
wmb();
first_rxdp->Control_1 |= RXD_OWN_XENA;
}
- nic->mac_control.stats_info->sw_stat. \
- mem_alloc_fail_cnt++;
+ stats->mem_alloc_fail_cnt++;
+
return -ENOMEM ;
}
- nic->mac_control.stats_info->sw_stat.mem_allocated
- += skb->truesize;
- if (nic->rxd_mode == RXD_MODE_1) {
+ stats->mem_allocated += skb->truesize;
+
+ if (ring->rxd_mode == RXD_MODE_1) {
/* 1 buffer mode - normal operation mode */
rxdp1 = (struct RxD1*)rxdp;
memset(rxdp, 0, sizeof(struct RxD1));
skb_reserve(skb, NET_IP_ALIGN);
rxdp1->Buffer0_ptr = pci_map_single
- (nic->pdev, skb->data, size - NET_IP_ALIGN,
+ (ring->pdev, skb->data, size - NET_IP_ALIGN,
PCI_DMA_FROMDEVICE);
if( (rxdp1->Buffer0_ptr == 0) ||
(rxdp1->Buffer0_ptr ==
@@ -2623,8 +2613,8 @@
rxdp->Control_2 =
SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
-
- } else if (nic->rxd_mode == RXD_MODE_3B) {
+ rxdp->Host_Control = (unsigned long) (skb);
+ } else if (ring->rxd_mode == RXD_MODE_3B) {
/*
* 2 buffer mode -
* 2 buffer mode provides 128
@@ -2640,7 +2630,7 @@
rxdp3->Buffer0_ptr = Buffer0_ptr;
rxdp3->Buffer1_ptr = Buffer1_ptr;
- ba = &mac_control->rings[ring_no].ba[block_no][off];
+ ba = &ring->ba[block_no][off];
skb_reserve(skb, BUF0_LEN);
tmp = (u64)(unsigned long) skb->data;
tmp += ALIGN_SIZE;
@@ -2650,10 +2640,10 @@
if (!(rxdp3->Buffer0_ptr))
rxdp3->Buffer0_ptr =
- pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
- PCI_DMA_FROMDEVICE);
+ pci_map_single(ring->pdev, ba->ba_0,
+ BUF0_LEN, PCI_DMA_FROMDEVICE);
else
- pci_dma_sync_single_for_device(nic->pdev,
+ pci_dma_sync_single_for_device(ring->pdev,
(dma_addr_t) rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
if( (rxdp3->Buffer0_ptr == 0) ||
@@ -2661,7 +2651,7 @@
goto pci_map_failed;
rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
- if (nic->rxd_mode == RXD_MODE_3B) {
+ if (ring->rxd_mode == RXD_MODE_3B) {
/* Two buffer mode */
/*
@@ -2669,39 +2659,42 @@
* L4 payload
*/
rxdp3->Buffer2_ptr = pci_map_single
- (nic->pdev, skb->data, dev->mtu + 4,
+ (ring->pdev, skb->data, ring->mtu + 4,
PCI_DMA_FROMDEVICE);
if( (rxdp3->Buffer2_ptr == 0) ||
(rxdp3->Buffer2_ptr == DMA_ERROR_CODE))
goto pci_map_failed;
- rxdp3->Buffer1_ptr =
- pci_map_single(nic->pdev,
+ if (!rxdp3->Buffer1_ptr)
+ rxdp3->Buffer1_ptr =
+ pci_map_single(ring->pdev,
ba->ba_1, BUF1_LEN,
PCI_DMA_FROMDEVICE);
+
if( (rxdp3->Buffer1_ptr == 0) ||
(rxdp3->Buffer1_ptr == DMA_ERROR_CODE)) {
pci_unmap_single
- (nic->pdev,
- (dma_addr_t)rxdp3->Buffer2_ptr,
- dev->mtu + 4,
+ (ring->pdev,
+ (dma_addr_t)(unsigned long)
+ skb->data,
+ ring->mtu + 4,
PCI_DMA_FROMDEVICE);
goto pci_map_failed;
}
rxdp->Control_2 |= SET_BUFFER1_SIZE_3(1);
rxdp->Control_2 |= SET_BUFFER2_SIZE_3
- (dev->mtu + 4);
+ (ring->mtu + 4);
}
rxdp->Control_2 |= s2BIT(0);
+ rxdp->Host_Control = (unsigned long) (skb);
}
- rxdp->Host_Control = (unsigned long) (skb);
if (alloc_tab & ((1 << rxsync_frequency) - 1))
rxdp->Control_1 |= RXD_OWN_XENA;
off++;
- if (off == (rxd_count[nic->rxd_mode] + 1))
+ if (off == (ring->rxd_count + 1))
off = 0;
- mac_control->rings[ring_no].rx_curr_put_info.offset = off;
+ ring->rx_curr_put_info.offset = off;
rxdp->Control_2 |= SET_RXD_MARKER;
if (!(alloc_tab & ((1 << rxsync_frequency) - 1))) {
@@ -2711,7 +2704,7 @@
}
first_rxdp = rxdp;
}
- atomic_inc(&nic->rx_bufs_left[ring_no]);
+ ring->rx_bufs_left += 1;
alloc_tab++;
}
@@ -2783,7 +2776,7 @@
}
sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize;
dev_kfree_skb(skb);
- atomic_dec(&sp->rx_bufs_left[ring_no]);
+ mac_control->rings[ring_no].rx_bufs_left -= 1;
}
}
@@ -2814,7 +2807,7 @@
mac_control->rings[i].rx_curr_get_info.block_index = 0;
mac_control->rings[i].rx_curr_put_info.offset = 0;
mac_control->rings[i].rx_curr_get_info.offset = 0;
- atomic_set(&sp->rx_bufs_left[i], 0);
+ mac_control->rings[i].rx_bufs_left = 0;
DBG_PRINT(INIT_DBG, "%s:Freed 0x%x Rx Buffers on ring%d\n",
dev->name, buf_cnt, i);
}
@@ -2864,7 +2857,7 @@
netif_rx_complete(dev, napi);
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
@@ -2877,7 +2870,7 @@
no_rx:
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Poll!!\n");
break;
@@ -2928,7 +2921,7 @@
rx_intr_handler(&mac_control->rings[i]);
for (i = 0; i < config->rx_ring_num; i++) {
- if (fill_rx_buffers(nic, i) == -ENOMEM) {
+ if (fill_rx_buffers(&mac_control->rings[i]) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name);
DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n");
break;
@@ -2953,8 +2946,6 @@
*/
static void rx_intr_handler(struct ring_info *ring_data)
{
- struct s2io_nic *nic = ring_data->nic;
- struct net_device *dev = (struct net_device *) nic->dev;
int get_block, put_block;
struct rx_curr_get_info get_info, put_info;
struct RxD_t *rxdp;
@@ -2977,33 +2968,34 @@
*/
if ((get_block == put_block) &&
(get_info.offset + 1) == put_info.offset) {
- DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
+ DBG_PRINT(INTR_DBG, "%s: Ring Full\n",
+ ring_data->dev->name);
break;
}
skb = (struct sk_buff *) ((unsigned long)rxdp->Host_Control);
if (skb == NULL) {
DBG_PRINT(ERR_DBG, "%s: The skb is ",
- dev->name);
+ ring_data->dev->name);
DBG_PRINT(ERR_DBG, "Null in Rx Intr\n");
return;
}
- if (nic->rxd_mode == RXD_MODE_1) {
+ if (ring_data->rxd_mode == RXD_MODE_1) {
rxdp1 = (struct RxD1*)rxdp;
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_unmap_single(ring_data->pdev, (dma_addr_t)
rxdp1->Buffer0_ptr,
- dev->mtu +
+ ring_data->mtu +
HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE +
HEADER_SNAP_SIZE,
PCI_DMA_FROMDEVICE);
- } else if (nic->rxd_mode == RXD_MODE_3B) {
+ } else if (ring_data->rxd_mode == RXD_MODE_3B) {
rxdp3 = (struct RxD3*)rxdp;
- pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
+ pci_dma_sync_single_for_cpu(ring_data->pdev, (dma_addr_t)
rxdp3->Buffer0_ptr,
BUF0_LEN, PCI_DMA_FROMDEVICE);
- pci_unmap_single(nic->pdev, (dma_addr_t)
+ pci_unmap_single(ring_data->pdev, (dma_addr_t)
rxdp3->Buffer2_ptr,
- dev->mtu + 4,
+ ring_data->mtu + 4,
PCI_DMA_FROMDEVICE);
}
prefetch(skb->data);
@@ -3012,7 +3004,7 @@
ring_data->rx_curr_get_info.offset = get_info.offset;
rxdp = ring_data->rx_blocks[get_block].
rxds[get_info.offset].virt_addr;
- if (get_info.offset == rxd_count[nic->rxd_mode]) {
+ if (get_info.offset == rxd_count[ring_data->rxd_mode]) {
get_info.offset = 0;
ring_data->rx_curr_get_info.offset = get_info.offset;
get_block++;
@@ -3022,19 +3014,21 @@
rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
}
- nic->pkts_to_process -= 1;
- if ((napi) && (!nic->pkts_to_process))
- break;
+ if(ring_data->nic->config.napi){
+ ring_data->nic->pkts_to_process -= 1;
+ if (!ring_data->nic->pkts_to_process)
+ break;
+ }
pkt_cnt++;
if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
break;
}
- if (nic->lro) {
+ if (ring_data->lro) {
/* Clear all LRO sessions before exiting */
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- struct lro *lro = &nic->lro0_n[i];
+ struct lro *lro = &ring_data->lro0_n[i];
if (lro->in_use) {
- update_L3L4_header(nic, lro);
+ update_L3L4_header(ring_data->nic, lro);
queue_rx_frame(lro->parent, lro->vlan_tag);
clear_lro_session(lro);
}
@@ -4333,10 +4327,10 @@
mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
}
-static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
+static int s2io_chk_rx_buffers(struct ring_info *ring)
{
- if (fill_rx_buffers(sp, rng_n) == -ENOMEM) {
- DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name);
+ if (fill_rx_buffers(ring) == -ENOMEM) {
+ DBG_PRINT(INFO_DBG, "%s:Out of memory", ring->dev->name);
DBG_PRINT(INFO_DBG, " in Rx Intr!!\n");
}
return 0;
@@ -4351,7 +4345,7 @@
return IRQ_HANDLED;
rx_intr_handler(ring);
- s2io_chk_rx_buffers(sp, ring->ring_no);
+ s2io_chk_rx_buffers(ring);
return IRQ_HANDLED;
}
@@ -4809,7 +4803,7 @@
*/
if (!config->napi) {
for (i = 0; i < config->rx_ring_num; i++)
- s2io_chk_rx_buffers(sp, i);
+ s2io_chk_rx_buffers(&mac_control->rings[i]);
}
writeq(sp->general_int_mask, &bar0->general_int_mask);
readl(&bar0->general_int_status);
@@ -4866,6 +4860,7 @@
struct s2io_nic *sp = dev->priv;
struct mac_info *mac_control;
struct config_param *config;
+ int i;
mac_control = &sp->mac_control;
@@ -4885,6 +4880,13 @@
sp->stats.rx_length_errors =
le64_to_cpu(mac_control->stats_info->rmac_long_frms);
+ /* collect per-ring rx_packets and rx_bytes */
+ sp->stats.rx_packets = sp->stats.rx_bytes = 0;
+ for (i = 0; i < config->rx_ring_num; i++) {
+ sp->stats.rx_packets += mac_control->rings[i].rx_packets;
+ sp->stats.rx_bytes += mac_control->rings[i].rx_bytes;
+ }
+
return (&sp->stats);
}
@@ -7157,7 +7159,9 @@
config = &sp->config;
for (i = 0; i < config->rx_ring_num; i++) {
- if ((ret = fill_rx_buffers(sp, i))) {
+ mac_control->rings[i].mtu = dev->mtu;
+ ret = fill_rx_buffers(&mac_control->rings[i]);
+ if (ret) {
DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
dev->name);
s2io_reset(sp);
@@ -7165,7 +7169,7 @@
return -ENOMEM;
}
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
- atomic_read(&sp->rx_bufs_left[i]));
+ mac_control->rings[i].rx_bufs_left);
}
/* Initialise napi */
@@ -7300,7 +7304,7 @@
static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
{
struct s2io_nic *sp = ring_data->nic;
- struct net_device *dev = (struct net_device *) sp->dev;
+ struct net_device *dev = (struct net_device *) ring_data->dev;
struct sk_buff *skb = (struct sk_buff *)
((unsigned long) rxdp->Host_Control);
int ring_no = ring_data->ring_no;
@@ -7377,19 +7381,19 @@
sp->mac_control.stats_info->sw_stat.mem_freed
+= skb->truesize;
dev_kfree_skb(skb);
- atomic_dec(&sp->rx_bufs_left[ring_no]);
+ ring_data->rx_bufs_left -= 1;
rxdp->Host_Control = 0;
return 0;
}
}
/* Updating statistics */
- sp->stats.rx_packets++;
+ ring_data->rx_packets++;
rxdp->Host_Control = 0;
if (sp->rxd_mode == RXD_MODE_1) {
int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
- sp->stats.rx_bytes += len;
+ ring_data->rx_bytes += len;
skb_put(skb, len);
} else if (sp->rxd_mode == RXD_MODE_3B) {
@@ -7400,13 +7404,13 @@
unsigned char *buff = skb_push(skb, buf0_len);
struct buffAdd *ba = &ring_data->ba[get_block][get_off];
- sp->stats.rx_bytes += buf0_len + buf2_len;
+ ring_data->rx_bytes += buf0_len + buf2_len;
memcpy(buff, ba->ba_0, buf0_len);
skb_put(skb, buf2_len);
}
- if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!sp->lro) ||
- (sp->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
+ if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) && ((!ring_data->lro) ||
+ (ring_data->lro && (!(rxdp->Control_1 & RXD_FRAME_IP_FRAG)))) &&
(sp->rx_csum)) {
l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1);
@@ -7417,14 +7421,14 @@
* a flag in the RxD.
*/
skb->ip_summed = CHECKSUM_UNNECESSARY;
- if (sp->lro) {
+ if (ring_data->lro) {
u32 tcp_len;
u8 *tcp;
int ret = 0;
- ret = s2io_club_tcp_session(skb->data, &tcp,
- &tcp_len, &lro,
- rxdp, sp);
+ ret = s2io_club_tcp_session(ring_data,
+ skb->data, &tcp, &tcp_len, &lro,
+ rxdp, sp);
switch (ret) {
case 3: /* Begin anew */
lro->parent = skb;
@@ -7486,7 +7490,7 @@
queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2));
dev->last_rx = jiffies;
aggregate:
- atomic_dec(&sp->rx_bufs_left[ring_no]);
+ sp->mac_control.rings[ring_no].rx_bufs_left -= 1;
return SUCCESS;
}
@@ -7603,12 +7607,14 @@
tx_steering_type = NO_STEERING;
}
- if ( rx_ring_num > 8) {
- DBG_PRINT(ERR_DBG, "s2io: Requested number of Rx rings not "
+ if (rx_ring_num > MAX_RX_RINGS) {
+ DBG_PRINT(ERR_DBG, "s2io: Requested number of rx rings not "
"supported\n");
- DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
- rx_ring_num = 8;
+ DBG_PRINT(ERR_DBG, "s2io: Default to %d rx rings\n",
+ MAX_RX_RINGS);
+ rx_ring_num = MAX_RX_RINGS;
}
+
if (*dev_intr_type != INTA)
napi = 0;
@@ -7836,10 +7842,15 @@
/* Rx side parameters. */
config->rx_ring_num = rx_ring_num;
- for (i = 0; i < MAX_RX_RINGS; i++) {
+ for (i = 0; i < config->rx_ring_num; i++) {
config->rx_cfg[i].num_rxd = rx_ring_sz[i] *
(rxd_count[sp->rxd_mode] + 1);
config->rx_cfg[i].ring_priority = i;
+ mac_control->rings[i].rx_bufs_left = 0;
+ mac_control->rings[i].rxd_mode = sp->rxd_mode;
+ mac_control->rings[i].rxd_count = rxd_count[sp->rxd_mode];
+ mac_control->rings[i].pdev = sp->pdev;
+ mac_control->rings[i].dev = sp->dev;
}
for (i = 0; i < rx_ring_num; i++) {
@@ -7854,10 +7865,6 @@
mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
- /* Initialize Ring buffer parameters. */
- for (i = 0; i < config->rx_ring_num; i++)
- atomic_set(&sp->rx_bufs_left[i], 0);
-
/* initialize the shared memory used by the NIC and the host */
if (init_shared_mem(sp)) {
DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n",
@@ -8077,6 +8084,9 @@
DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name,
sp->config.tx_fifo_num);
+ DBG_PRINT(ERR_DBG, "%s: Using %d Rx ring(s)\n", dev->name,
+ sp->config.rx_ring_num);
+
switch(sp->config.intr_type) {
case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
@@ -8391,8 +8401,9 @@
}
static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
- struct RxD_t *rxdp, struct s2io_nic *sp)
+s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer, u8 **tcp,
+ u32 *tcp_len, struct lro **lro, struct RxD_t *rxdp,
+ struct s2io_nic *sp)
{
struct iphdr *ip;
struct tcphdr *tcph;
@@ -8410,7 +8421,7 @@
tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph);
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- struct lro *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &ring_data->lro0_n[i];
if (l_lro->in_use) {
if (check_for_socket_match(l_lro, ip, tcph))
continue;
@@ -8448,7 +8459,7 @@
}
for (i=0; i<MAX_LRO_SESSIONS; i++) {
- struct lro *l_lro = &sp->lro0_n[i];
+ struct lro *l_lro = &ring_data->lro0_n[i];
if (!(l_lro->in_use)) {
*lro = l_lro;
ret = 3; /* Begin anew */
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index ce53a02..0709ebae 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -678,11 +678,53 @@
struct rxd_info *rxds;
};
+/* Data structure to represent a LRO session */
+struct lro {
+ struct sk_buff *parent;
+ struct sk_buff *last_frag;
+ u8 *l2h;
+ struct iphdr *iph;
+ struct tcphdr *tcph;
+ u32 tcp_next_seq;
+ __be32 tcp_ack;
+ int total_len;
+ int frags_len;
+ int sg_num;
+ int in_use;
+ __be16 window;
+ u16 vlan_tag;
+ u32 cur_tsval;
+ __be32 cur_tsecr;
+ u8 saw_ts;
+} ____cacheline_aligned;
+
/* Ring specific structure */
struct ring_info {
/* The ring number */
int ring_no;
+ /* per-ring buffer counter */
+ u32 rx_bufs_left;
+
+ #define MAX_LRO_SESSIONS 32
+ struct lro lro0_n[MAX_LRO_SESSIONS];
+ u8 lro;
+
+ /* copy of sp->rxd_mode flag */
+ int rxd_mode;
+
+ /* Number of rxds per block for the rxd_mode */
+ int rxd_count;
+
+ /* copy of sp pointer */
+ struct s2io_nic *nic;
+
+ /* copy of sp->dev pointer */
+ struct net_device *dev;
+
+ /* copy of sp->pdev pointer */
+ struct pci_dev *pdev;
+
/*
* Place holders for the virtual and physical addresses of
* all the Rx Blocks
@@ -703,10 +745,16 @@
*/
struct rx_curr_get_info rx_curr_get_info;
+ /* interface MTU value */
+ unsigned mtu;
+
/* Buffer Address store. */
struct buffAdd **ba;
- struct s2io_nic *nic;
-};
+
+ /* per-Ring statistics */
+ unsigned long rx_packets;
+ unsigned long rx_bytes;
+} ____cacheline_aligned;
/* Fifo specific structure */
struct fifo_info {
@@ -813,26 +861,6 @@
u64 data;
};
-/* Data structure to represent a LRO session */
-struct lro {
- struct sk_buff *parent;
- struct sk_buff *last_frag;
- u8 *l2h;
- struct iphdr *iph;
- struct tcphdr *tcph;
- u32 tcp_next_seq;
- __be32 tcp_ack;
- int total_len;
- int frags_len;
- int sg_num;
- int in_use;
- __be16 window;
- u16 vlan_tag;
- u32 cur_tsval;
- __be32 cur_tsecr;
- u8 saw_ts;
-} ____cacheline_aligned;
-
/* These flags represent the devices temporary state */
enum s2io_device_state_t
{
@@ -872,8 +900,6 @@
/* Space to back up the PCI config space */
u32 config_space[256 / sizeof(u32)];
- atomic_t rx_bufs_left[MAX_RX_RINGS];
-
#define PROMISC 1
#define ALL_MULTI 2
@@ -950,8 +976,6 @@
#define XFRAME_II_DEVICE 2
u8 device_type;
-#define MAX_LRO_SESSIONS 32
- struct lro lro0_n[MAX_LRO_SESSIONS];
unsigned long clubbed_frms_cnt;
unsigned long sending_both;
u8 lro;
@@ -1118,9 +1142,9 @@
static int do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int offset);
static int do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr);
-static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
- struct RxD_t *rxdp, struct s2io_nic *sp);
+static int s2io_club_tcp_session(struct ring_info *ring_data, u8 *buffer,
+ u8 **tcp, u32 *tcp_len, struct lro **lro, struct RxD_t *rxdp,
+ struct s2io_nic *sp);
static void clear_lro_session(struct lro *lro);
static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag);
static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig
new file mode 100644
index 0000000..dbad95c
--- /dev/null
+++ b/drivers/net/sfc/Kconfig
@@ -0,0 +1,12 @@
+config SFC
+ tristate "Solarflare Solarstorm SFC4000 support"
+ depends on PCI && INET
+ select MII
+ select INET_LRO
+ select CRC32
+ help
+ This driver supports 10-gigabit Ethernet cards based on
+ the Solarflare Communications Solarstorm SFC4000 controller.
+
+ To compile this driver as a module, choose M here. The module
+ will be called sfc.
diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile
new file mode 100644
index 0000000..0f02344
--- /dev/null
+++ b/drivers/net/sfc/Makefile
@@ -0,0 +1,5 @@
+sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \
+ i2c-direct.o ethtool.o xfp_phy.o mdio_10g.o \
+ tenxpress.o boards.o sfe4001.o
+
+obj-$(CONFIG_SFC) += sfc.o
diff --git a/drivers/net/sfc/bitfield.h b/drivers/net/sfc/bitfield.h
new file mode 100644
index 0000000..2806201
--- /dev/null
+++ b/drivers/net/sfc/bitfield.h
@@ -0,0 +1,508 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_BITFIELD_H
+#define EFX_BITFIELD_H
+
+/*
+ * Efx bitfield access
+ *
+ * Efx NICs make extensive use of bitfields up to 128 bits
+ * wide. Since there is no native 128-bit datatype on most systems,
+ * and since 64-bit datatypes are inefficient on 32-bit systems and
+ * vice versa, we wrap accesses in a way that uses the most efficient
+ * datatype.
+ *
+ * The NICs are PCI devices and therefore little-endian. Since most
+ * of the quantities that we deal with are DMAed to/from host memory,
+ * we define our datatypes (efx_oword_t, efx_qword_t and
+ * efx_dword_t) to be little-endian.
+ */
+
+/* Lowest bit numbers and widths */
+#define EFX_DUMMY_FIELD_LBN 0
+#define EFX_DUMMY_FIELD_WIDTH 0
+#define EFX_DWORD_0_LBN 0
+#define EFX_DWORD_0_WIDTH 32
+#define EFX_DWORD_1_LBN 32
+#define EFX_DWORD_1_WIDTH 32
+#define EFX_DWORD_2_LBN 64
+#define EFX_DWORD_2_WIDTH 32
+#define EFX_DWORD_3_LBN 96
+#define EFX_DWORD_3_WIDTH 32
+
+/* Specified attribute (e.g. LBN) of the specified field */
+#define EFX_VAL(field, attribute) field ## _ ## attribute
+/* Low bit number of the specified field */
+#define EFX_LOW_BIT(field) EFX_VAL(field, LBN)
+/* Bit width of the specified field */
+#define EFX_WIDTH(field) EFX_VAL(field, WIDTH)
+/* High bit number of the specified field */
+#define EFX_HIGH_BIT(field) (EFX_LOW_BIT(field) + EFX_WIDTH(field) - 1)
+/* Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 64 bits.
+ */
+#define EFX_MASK64(field) \
+ (EFX_WIDTH(field) == 64 ? ~((u64) 0) : \
+ (((((u64) 1) << EFX_WIDTH(field))) - 1))
+
+/* Mask equal in width to the specified field.
+ *
+ * For example, a field with width 5 would have a mask of 0x1f.
+ *
+ * The maximum width mask that can be generated is 32 bits. Use
+ * EFX_MASK64 for higher width fields.
+ */
+#define EFX_MASK32(field) \
+ (EFX_WIDTH(field) == 32 ? ~((u32) 0) : \
+ (((((u32) 1) << EFX_WIDTH(field))) - 1))
+
+/* A doubleword (i.e. 4 byte) datatype - little-endian in HW */
+typedef union efx_dword {
+ __le32 u32[1];
+} efx_dword_t;
+
+/* A quadword (i.e. 8 byte) datatype - little-endian in HW */
+typedef union efx_qword {
+ __le64 u64[1];
+ __le32 u32[2];
+ efx_dword_t dword[2];
+} efx_qword_t;
+
+/* An octword (eight-word, i.e. 16 byte) datatype - little-endian in HW */
+typedef union efx_oword {
+ __le64 u64[2];
+ efx_qword_t qword[2];
+ __le32 u32[4];
+ efx_dword_t dword[4];
+} efx_oword_t;
+
+/* Format string and value expanders for printk */
+#define EFX_DWORD_FMT "%08x"
+#define EFX_QWORD_FMT "%08x:%08x"
+#define EFX_OWORD_FMT "%08x:%08x:%08x:%08x"
+#define EFX_DWORD_VAL(dword) \
+ ((unsigned int) le32_to_cpu((dword).u32[0]))
+#define EFX_QWORD_VAL(qword) \
+ ((unsigned int) le32_to_cpu((qword).u32[1])), \
+ ((unsigned int) le32_to_cpu((qword).u32[0]))
+#define EFX_OWORD_VAL(oword) \
+ ((unsigned int) le32_to_cpu((oword).u32[3])), \
+ ((unsigned int) le32_to_cpu((oword).u32[2])), \
+ ((unsigned int) le32_to_cpu((oword).u32[1])), \
+ ((unsigned int) le32_to_cpu((oword).u32[0]))
+
+/*
+ * Extract bit field portion [low,high) from the native-endian element
+ * which contains bits [min,max).
+ *
+ * For example, suppose "element" represents the high 32 bits of a
+ * 64-bit value, and we wish to extract the bits belonging to the bit
+ * field occupying bits 28-45 of this 64-bit value.
+ *
+ * Then EFX_EXTRACT ( element, 32, 63, 28, 45 ) would give
+ *
+ * ( element ) << 4
+ *
+ * The result will contain the relevant bits filled in in the range
+ * [0,high-low), with garbage in bits [high-low+1,...).
+ */
+#define EFX_EXTRACT_NATIVE(native_element, min, max, low, high) \
+ (((low > max) || (high < min)) ? 0 : \
+ ((low > min) ? \
+ ((native_element) >> (low - min)) : \
+ ((native_element) << (min - low))))
+
+/*
+ * Extract bit field portion [low,high) from the 64-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFX_EXTRACT64(element, min, max, low, high) \
+ EFX_EXTRACT_NATIVE(le64_to_cpu(element), min, max, low, high)
+
+/*
+ * Extract bit field portion [low,high) from the 32-bit little-endian
+ * element which contains bits [min,max)
+ */
+#define EFX_EXTRACT32(element, min, max, low, high) \
+ EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high)
+
+#define EFX_EXTRACT_OWORD64(oword, low, high) \
+ (EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) | \
+ EFX_EXTRACT64((oword).u64[1], 64, 127, low, high))
+
+#define EFX_EXTRACT_QWORD64(qword, low, high) \
+ EFX_EXTRACT64((qword).u64[0], 0, 63, low, high)
+
+#define EFX_EXTRACT_OWORD32(oword, low, high) \
+ (EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) | \
+ EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) | \
+ EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) | \
+ EFX_EXTRACT32((oword).u32[3], 96, 127, low, high))
+
+#define EFX_EXTRACT_QWORD32(qword, low, high) \
+ (EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) | \
+ EFX_EXTRACT32((qword).u32[1], 32, 63, low, high))
+
+#define EFX_EXTRACT_DWORD(dword, low, high) \
+ EFX_EXTRACT32((dword).u32[0], 0, 31, low, high)
+
+#define EFX_OWORD_FIELD64(oword, field) \
+ (EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK64(field))
+
+#define EFX_QWORD_FIELD64(qword, field) \
+ (EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK64(field))
+
+#define EFX_OWORD_FIELD32(oword, field) \
+ (EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK32(field))
+
+#define EFX_QWORD_FIELD32(qword, field) \
+ (EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK32(field))
+
+#define EFX_DWORD_FIELD(dword, field) \
+ (EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
+ & EFX_MASK32(field))
+
+#define EFX_OWORD_IS_ZERO64(oword) \
+ (((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0)
+
+#define EFX_QWORD_IS_ZERO64(qword) \
+ (((qword).u64[0]) == (__force __le64) 0)
+
+#define EFX_OWORD_IS_ZERO32(oword) \
+ (((oword).u32[0] | (oword).u32[1] | (oword).u32[2] | (oword).u32[3]) \
+ == (__force __le32) 0)
+
+#define EFX_QWORD_IS_ZERO32(qword) \
+ (((qword).u32[0] | (qword).u32[1]) == (__force __le32) 0)
+
+#define EFX_DWORD_IS_ZERO(dword) \
+ (((dword).u32[0]) == (__force __le32) 0)
+
+#define EFX_OWORD_IS_ALL_ONES64(oword) \
+ (((oword).u64[0] & (oword).u64[1]) == ~((__force __le64) 0))
+
+#define EFX_QWORD_IS_ALL_ONES64(qword) \
+ ((qword).u64[0] == ~((__force __le64) 0))
+
+#define EFX_OWORD_IS_ALL_ONES32(oword) \
+ (((oword).u32[0] & (oword).u32[1] & (oword).u32[2] & (oword).u32[3]) \
+ == ~((__force __le32) 0))
+
+#define EFX_QWORD_IS_ALL_ONES32(qword) \
+ (((qword).u32[0] & (qword).u32[1]) == ~((__force __le32) 0))
+
+#define EFX_DWORD_IS_ALL_ONES(dword) \
+ ((dword).u32[0] == ~((__force __le32) 0))
+
+#if BITS_PER_LONG == 64
+#define EFX_OWORD_FIELD EFX_OWORD_FIELD64
+#define EFX_QWORD_FIELD EFX_QWORD_FIELD64
+#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO64
+#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO64
+#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES64
+#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES64
+#else
+#define EFX_OWORD_FIELD EFX_OWORD_FIELD32
+#define EFX_QWORD_FIELD EFX_QWORD_FIELD32
+#define EFX_OWORD_IS_ZERO EFX_OWORD_IS_ZERO32
+#define EFX_QWORD_IS_ZERO EFX_QWORD_IS_ZERO32
+#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES32
+#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES32
+#endif
+
+/*
+ * Construct bit field portion
+ *
+ * Creates the portion of the bit field [low,high) that lies within
+ * the range [min,max).
+ */
+#define EFX_INSERT_NATIVE64(min, max, low, high, value) \
+ (((low > max) || (high < min)) ? 0 : \
+ ((low > min) ? \
+ (((u64) (value)) << (low - min)) : \
+ (((u64) (value)) >> (min - low))))
+
+#define EFX_INSERT_NATIVE32(min, max, low, high, value) \
+ (((low > max) || (high < min)) ? 0 : \
+ ((low > min) ? \
+ (((u32) (value)) << (low - min)) : \
+ (((u32) (value)) >> (min - low))))
+
+#define EFX_INSERT_NATIVE(min, max, low, high, value) \
+ ((((max - min) >= 32) || ((high - low) >= 32)) ? \
+ EFX_INSERT_NATIVE64(min, max, low, high, value) : \
+ EFX_INSERT_NATIVE32(min, max, low, high, value))
+
+/*
+ * Construct bit field portion
+ *
+ * Creates the portion of the named bit field that lies within the
+ * range [min,max).
+ */
+#define EFX_INSERT_FIELD_NATIVE(min, max, field, value) \
+ EFX_INSERT_NATIVE(min, max, EFX_LOW_BIT(field), \
+ EFX_HIGH_BIT(field), value)
+
+/*
+ * Construct bit field
+ *
+ * Creates the portion of the named bit fields that lie within the
+ * range [min,max).
+ */
+#define EFX_INSERT_FIELDS_NATIVE(min, max, \
+ field1, value1, \
+ field2, value2, \
+ field3, value3, \
+ field4, value4, \
+ field5, value5, \
+ field6, value6, \
+ field7, value7, \
+ field8, value8, \
+ field9, value9, \
+ field10, value10) \
+ (EFX_INSERT_FIELD_NATIVE((min), (max), field1, (value1)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field2, (value2)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field3, (value3)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field4, (value4)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field5, (value5)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field6, (value6)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field7, (value7)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field8, (value8)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field9, (value9)) | \
+ EFX_INSERT_FIELD_NATIVE((min), (max), field10, (value10)))
+
+#define EFX_INSERT_FIELDS64(...) \
+ cpu_to_le64(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
+
+#define EFX_INSERT_FIELDS32(...) \
+ cpu_to_le32(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
+
+#define EFX_POPULATE_OWORD64(oword, ...) do { \
+ (oword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
+ (oword).u64[1] = EFX_INSERT_FIELDS64(64, 127, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_QWORD64(qword, ...) do { \
+ (qword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_OWORD32(oword, ...) do { \
+ (oword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
+ (oword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
+ (oword).u32[2] = EFX_INSERT_FIELDS32(64, 95, __VA_ARGS__); \
+ (oword).u32[3] = EFX_INSERT_FIELDS32(96, 127, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_QWORD32(qword, ...) do { \
+ (qword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
+ (qword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__); \
+ } while (0)
+
+#define EFX_POPULATE_DWORD(dword, ...) do { \
+ (dword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__); \
+ } while (0)
+
+#if BITS_PER_LONG == 64
+#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD64
+#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD64
+#else
+#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD32
+#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD32
+#endif
+
+/* Populate an octword field with various numbers of arguments */
+#define EFX_POPULATE_OWORD_10 EFX_POPULATE_OWORD
+#define EFX_POPULATE_OWORD_9(oword, ...) \
+ EFX_POPULATE_OWORD_10(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_8(oword, ...) \
+ EFX_POPULATE_OWORD_9(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_7(oword, ...) \
+ EFX_POPULATE_OWORD_8(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_6(oword, ...) \
+ EFX_POPULATE_OWORD_7(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_5(oword, ...) \
+ EFX_POPULATE_OWORD_6(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_4(oword, ...) \
+ EFX_POPULATE_OWORD_5(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_3(oword, ...) \
+ EFX_POPULATE_OWORD_4(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_2(oword, ...) \
+ EFX_POPULATE_OWORD_3(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_OWORD_1(oword, ...) \
+ EFX_POPULATE_OWORD_2(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_ZERO_OWORD(oword) \
+ EFX_POPULATE_OWORD_1(oword, EFX_DUMMY_FIELD, 0)
+#define EFX_SET_OWORD(oword) \
+ EFX_POPULATE_OWORD_4(oword, \
+ EFX_DWORD_0, 0xffffffff, \
+ EFX_DWORD_1, 0xffffffff, \
+ EFX_DWORD_2, 0xffffffff, \
+ EFX_DWORD_3, 0xffffffff)
+
+/* Populate a quadword field with various numbers of arguments */
+#define EFX_POPULATE_QWORD_10 EFX_POPULATE_QWORD
+#define EFX_POPULATE_QWORD_9(qword, ...) \
+ EFX_POPULATE_QWORD_10(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_8(qword, ...) \
+ EFX_POPULATE_QWORD_9(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_7(qword, ...) \
+ EFX_POPULATE_QWORD_8(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_6(qword, ...) \
+ EFX_POPULATE_QWORD_7(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_5(qword, ...) \
+ EFX_POPULATE_QWORD_6(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_4(qword, ...) \
+ EFX_POPULATE_QWORD_5(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_3(qword, ...) \
+ EFX_POPULATE_QWORD_4(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_2(qword, ...) \
+ EFX_POPULATE_QWORD_3(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_QWORD_1(qword, ...) \
+ EFX_POPULATE_QWORD_2(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_ZERO_QWORD(qword) \
+ EFX_POPULATE_QWORD_1(qword, EFX_DUMMY_FIELD, 0)
+#define EFX_SET_QWORD(qword) \
+ EFX_POPULATE_QWORD_2(qword, \
+ EFX_DWORD_0, 0xffffffff, \
+ EFX_DWORD_1, 0xffffffff)
+
+/* Populate a dword field with various numbers of arguments */
+#define EFX_POPULATE_DWORD_10 EFX_POPULATE_DWORD
+#define EFX_POPULATE_DWORD_9(dword, ...) \
+ EFX_POPULATE_DWORD_10(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_8(dword, ...) \
+ EFX_POPULATE_DWORD_9(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_7(dword, ...) \
+ EFX_POPULATE_DWORD_8(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_6(dword, ...) \
+ EFX_POPULATE_DWORD_7(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_5(dword, ...) \
+ EFX_POPULATE_DWORD_6(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_4(dword, ...) \
+ EFX_POPULATE_DWORD_5(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_3(dword, ...) \
+ EFX_POPULATE_DWORD_4(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_2(dword, ...) \
+ EFX_POPULATE_DWORD_3(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_POPULATE_DWORD_1(dword, ...) \
+ EFX_POPULATE_DWORD_2(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
+#define EFX_ZERO_DWORD(dword) \
+ EFX_POPULATE_DWORD_1(dword, EFX_DUMMY_FIELD, 0)
+#define EFX_SET_DWORD(dword) \
+ EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xffffffff)
+
+/*
+ * Modify a named field within an already-populated structure. Used
+ * for read-modify-write operations.
+ *
+ */
+
+#define EFX_INVERT_OWORD(oword) do { \
+ (oword).u64[0] = ~((oword).u64[0]); \
+ (oword).u64[1] = ~((oword).u64[1]); \
+ } while (0)
+
+#define EFX_INSERT_FIELD64(...) \
+ cpu_to_le64(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
+
+#define EFX_INSERT_FIELD32(...) \
+ cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
+
+#define EFX_INPLACE_MASK64(min, max, field) \
+ EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field))
+
+#define EFX_INPLACE_MASK32(min, max, field) \
+ EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field))
+
+#define EFX_SET_OWORD_FIELD64(oword, field, value) do { \
+ (oword).u64[0] = (((oword).u64[0] \
+ & ~EFX_INPLACE_MASK64(0, 63, field)) \
+ | EFX_INSERT_FIELD64(0, 63, field, value)); \
+ (oword).u64[1] = (((oword).u64[1] \
+ & ~EFX_INPLACE_MASK64(64, 127, field)) \
+ | EFX_INSERT_FIELD64(64, 127, field, value)); \
+ } while (0)
+
+#define EFX_SET_QWORD_FIELD64(qword, field, value) do { \
+ (qword).u64[0] = (((qword).u64[0] \
+ & ~EFX_INPLACE_MASK64(0, 63, field)) \
+ | EFX_INSERT_FIELD64(0, 63, field, value)); \
+ } while (0)
+
+#define EFX_SET_OWORD_FIELD32(oword, field, value) do { \
+ (oword).u32[0] = (((oword).u32[0] \
+ & ~EFX_INPLACE_MASK32(0, 31, field)) \
+ | EFX_INSERT_FIELD32(0, 31, field, value)); \
+ (oword).u32[1] = (((oword).u32[1] \
+ & ~EFX_INPLACE_MASK32(32, 63, field)) \
+ | EFX_INSERT_FIELD32(32, 63, field, value)); \
+ (oword).u32[2] = (((oword).u32[2] \
+ & ~EFX_INPLACE_MASK32(64, 95, field)) \
+ | EFX_INSERT_FIELD32(64, 95, field, value)); \
+ (oword).u32[3] = (((oword).u32[3] \
+ & ~EFX_INPLACE_MASK32(96, 127, field)) \
+ | EFX_INSERT_FIELD32(96, 127, field, value)); \
+ } while (0)
+
+#define EFX_SET_QWORD_FIELD32(qword, field, value) do { \
+ (qword).u32[0] = (((qword).u32[0] \
+ & ~EFX_INPLACE_MASK32(0, 31, field)) \
+ | EFX_INSERT_FIELD32(0, 31, field, value)); \
+ (qword).u32[1] = (((qword).u32[1] \
+ & ~EFX_INPLACE_MASK32(32, 63, field)) \
+ | EFX_INSERT_FIELD32(32, 63, field, value)); \
+ } while (0)
+
+#define EFX_SET_DWORD_FIELD(dword, field, value) do { \
+ (dword).u32[0] = (((dword).u32[0] \
+ & ~EFX_INPLACE_MASK32(0, 31, field)) \
+ | EFX_INSERT_FIELD32(0, 31, field, value)); \
+ } while (0)
+
+#if BITS_PER_LONG == 64
+#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64
+#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64
+#else
+#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD32
+#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32
+#endif
+
+#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \
+ if (FALCON_REV(efx) >= FALCON_REV_B0) { \
+ EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \
+ } else { \
+ EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \
+ } \
+} while (0)
+
+#define EFX_QWORD_FIELD_VER(efx, qword, field) \
+ (FALCON_REV(efx) >= FALCON_REV_B0 ? \
+ EFX_QWORD_FIELD((qword), field##_B0) : \
+ EFX_QWORD_FIELD((qword), field##_A1))
+
+/* Used to avoid compiler warnings about shift range exceeding width
+ * of the data types when dma_addr_t is only 32 bits wide.
+ */
+#define DMA_ADDR_T_WIDTH (8 * sizeof(dma_addr_t))
+#define EFX_DMA_TYPE_WIDTH(width) \
+ (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH)
+#define EFX_DMA_MAX_MASK ((DMA_ADDR_T_WIDTH == 64) ? \
+ ~((u64) 0) : ~((u32) 0))
+#define EFX_DMA_MASK(mask) ((mask) & EFX_DMA_MAX_MASK)
+
+#endif /* EFX_BITFIELD_H */
diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c
new file mode 100644
index 0000000..eecaa6d
--- /dev/null
+++ b/drivers/net/sfc/boards.c
@@ -0,0 +1,167 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include "net_driver.h"
+#include "phy.h"
+#include "boards.h"
+#include "efx.h"
+
+/* Macros for unpacking the board revision */
+/* The revision info is in host byte order. */
+#define BOARD_TYPE(_rev) (_rev >> 8)
+#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
+#define BOARD_MINOR(_rev) (_rev & 0xf)
+
+/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */
+#define BLINK_INTERVAL (HZ/2)
+
+static void blink_led_timer(unsigned long context)
+{
+ struct efx_nic *efx = (struct efx_nic *)context;
+ struct efx_blinker *bl = &efx->board_info.blinker;
+ efx->board_info.set_fault_led(efx, bl->state);
+ bl->state = !bl->state;
+ if (bl->resubmit) {
+ bl->timer.expires = jiffies + BLINK_INTERVAL;
+ add_timer(&bl->timer);
+ }
+}
+
+static void board_blink(struct efx_nic *efx, int blink)
+{
+ struct efx_blinker *blinker = &efx->board_info.blinker;
+
+ /* The rtnl mutex serialises all ethtool ioctls, so
+ * nothing special needs doing here. */
+ if (blink) {
+ blinker->resubmit = 1;
+ blinker->state = 0;
+ setup_timer(&blinker->timer, blink_led_timer,
+ (unsigned long)efx);
+ blinker->timer.expires = jiffies + BLINK_INTERVAL;
+ add_timer(&blinker->timer);
+ } else {
+ blinker->resubmit = 0;
+ if (blinker->timer.function)
+ del_timer_sync(&blinker->timer);
+ efx->board_info.set_fault_led(efx, 0);
+ }
+}
+
+/*****************************************************************************
+ * Support for the SFE4002
+ *
+ */
+/****************************************************************************/
+/* LED allocations. Note that on rev A0 boards the schematic and the reality
+ * differ: red and green are swapped. Below is the fixed (A1) layout (there
+ * are only 3 A0 boards in existence, so no real reason to make this
+ * conditional).
+ */
+#define SFE4002_FAULT_LED (2) /* Red */
+#define SFE4002_RX_LED (0) /* Green */
+#define SFE4002_TX_LED (1) /* Amber */
+
+static int sfe4002_init_leds(struct efx_nic *efx)
+{
+ /* Set the TX and RX LEDs to reflect status and activity, and the
+ * fault LED off */
+ xfp_set_led(efx, SFE4002_TX_LED,
+ QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
+ xfp_set_led(efx, SFE4002_RX_LED,
+ QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
+ xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
+ efx->board_info.blinker.led_num = SFE4002_FAULT_LED;
+ return 0;
+}
+
+static void sfe4002_fault_led(struct efx_nic *efx, int state)
+{
+ xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
+ QUAKE_LED_OFF);
+}
+
+static int sfe4002_init(struct efx_nic *efx)
+{
+ efx->board_info.init_leds = sfe4002_init_leds;
+ efx->board_info.set_fault_led = sfe4002_fault_led;
+ efx->board_info.blink = board_blink;
+ return 0;
+}
+
+/* This will get expanded as board-specific details get moved out of the
+ * PHY drivers. */
+struct efx_board_data {
+ const char *ref_model;
+ const char *gen_type;
+ int (*init) (struct efx_nic *nic);
+};
+
+static int dummy_init(struct efx_nic *nic)
+{
+ return 0;
+}
+
+static struct efx_board_data board_data[] = {
+ [EFX_BOARD_INVALID] =
+ {NULL, NULL, dummy_init},
+ [EFX_BOARD_SFE4001] =
+ {"SFE4001", "10GBASE-T adapter", sfe4001_poweron},
+ [EFX_BOARD_SFE4002] =
+ {"SFE4002", "XFP adapter", sfe4002_init},
+};
+
+int efx_set_board_info(struct efx_nic *efx, u16 revision_info)
+{
+ int rc = 0;
+ struct efx_board_data *data;
+
+ if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) {
+ EFX_ERR(efx, "squashing unknown board type %d\n",
+ BOARD_TYPE(revision_info));
+ revision_info = 0;
+ }
+
+ if (BOARD_TYPE(revision_info) == 0) {
+ efx->board_info.major = 0;
+ efx->board_info.minor = 0;
+ /* For early boards that don't have revision info. there is
+ * only 1 board for each PHY type, so we can work it out, with
+ * the exception of the PHY-less boards. */
+ switch (efx->phy_type) {
+ case PHY_TYPE_10XPRESS:
+ efx->board_info.type = EFX_BOARD_SFE4001;
+ break;
+ case PHY_TYPE_XFP:
+ efx->board_info.type = EFX_BOARD_SFE4002;
+ break;
+ default:
+ efx->board_info.type = 0;
+ break;
+ }
+ } else {
+ efx->board_info.type = BOARD_TYPE(revision_info);
+ efx->board_info.major = BOARD_MAJOR(revision_info);
+ efx->board_info.minor = BOARD_MINOR(revision_info);
+ }
+
+ data = &board_data[efx->board_info.type];
+
+ /* Report the board model number or generic type for recognisable
+ * boards. */
+ if (efx->board_info.type != 0)
+ EFX_INFO(efx, "board is %s rev %c%d\n",
+ (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
+ ? data->ref_model : data->gen_type,
+ 'A' + efx->board_info.major, efx->board_info.minor);
+
+ efx->board_info.init = data->init;
+
+ return rc;
+}
diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h
new file mode 100644
index 0000000..f56341d
--- /dev/null
+++ b/drivers/net/sfc/boards.h
@@ -0,0 +1,26 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_BOARDS_H
+#define EFX_BOARDS_H
+
+/* Board IDs (must fit in 8 bits) */
+enum efx_board_type {
+ EFX_BOARD_INVALID = 0,
+ EFX_BOARD_SFE4001 = 1, /* SFE4001 (10GBASE-T) */
+ EFX_BOARD_SFE4002 = 2,
+ /* Insert new types before here */
+ EFX_BOARD_MAX
+};
+
+extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
+extern int sfe4001_poweron(struct efx_nic *efx);
+extern void sfe4001_poweroff(struct efx_nic *efx);
+
+#endif
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
new file mode 100644
index 0000000..59edcf7
--- /dev/null
+++ b/drivers/net/sfc/efx.c
@@ -0,0 +1,2208 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/delay.h>
+#include <linux/notifier.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/in.h>
+#include <linux/crc32.h>
+#include <linux/ethtool.h>
+#include "net_driver.h"
+#include "gmii.h"
+#include "ethtool.h"
+#include "tx.h"
+#include "rx.h"
+#include "efx.h"
+#include "mdio_10g.h"
+#include "falcon.h"
+#include "workarounds.h"
+#include "mac.h"
+
+#define EFX_MAX_MTU (9 * 1024)
+
+/* RX slow fill workqueue. If memory allocation fails in the fast path,
+ * a work item is pushed onto this work queue to retry the allocation later,
+ * to avoid the NIC being starved of RX buffers. Since this is a per cpu
+ * workqueue, there is nothing to be gained in making it per NIC
+ */
+static struct workqueue_struct *refill_workqueue;
+
+/**************************************************************************
+ *
+ * Configurable values
+ *
+ *************************************************************************/
+
+/*
+ * Enable large receive offload (LRO) aka soft segment reassembly (SSR)
+ *
+ * This sets the default for new devices. It can be controlled later
+ * using ethtool.
+ */
+static int lro = 1;
+module_param(lro, int, 0644);
+MODULE_PARM_DESC(lro, "Large receive offload acceleration");
+
+/*
+ * Use separate channels for TX and RX events
+ *
+ * Set this to 1 to use separate channels for TX and RX. It allows us to
+ * apply a higher level of interrupt moderation to TX events.
+ *
+ * This is forced to 0 for MSI interrupt mode as the interrupt vector
+ * is not written
+ */
+static unsigned int separate_tx_and_rx_channels = 1;
+
+/* This is the weight assigned to each of the (per-channel) virtual
+ * NAPI devices.
+ */
+static int napi_weight = 64;
+
+/* This is the time (in jiffies) between invocations of the hardware
+ * monitor, which checks for known hardware bugs and resets the
+ * hardware and driver as necessary.
+ */
+unsigned int efx_monitor_interval = 1 * HZ;
+
+/* This controls whether or not the hardware monitor will trigger a
+ * reset when it detects an error condition.
+ */
+static unsigned int monitor_reset = 1;
+
+/* This controls whether or not the driver will initialise devices
+ * with invalid MAC addresses stored in the EEPROM or flash. If true,
+ * such devices will be initialised with a random locally-generated
+ * MAC address. This allows for loading the sfc_mtd driver to
+ * reprogram the flash, even if the flash contents (including the MAC
+ * address) have previously been erased.
+ */
+static unsigned int allow_bad_hwaddr;
+
+/* Initial interrupt moderation settings. They can be modified after
+ * module load with ethtool.
+ *
+ * The default for RX should strike a balance between increasing the
+ * round-trip latency and reducing overhead.
+ */
+static unsigned int rx_irq_mod_usec = 60;
+
+/* Initial interrupt moderation settings. They can be modified after
+ * module load with ethtool.
+ *
+ * This default is chosen to ensure that a 10G link does not go idle
+ * while a TX queue is stopped after it has become full. A queue is
+ * restarted when it drops below half full. The time this takes (assuming
+ * worst case 3 descriptors per packet and 1024 descriptors) is
+ * 512 / 3 * 1.2 = 205 usec.
+ */
+static unsigned int tx_irq_mod_usec = 150;
+
+/* This is the first interrupt mode to try out of:
+ * 0 => MSI-X
+ * 1 => MSI
+ * 2 => legacy
+ */
+static unsigned int interrupt_mode;
+
+/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS),
+ * i.e. the number of CPUs among which we may distribute simultaneous
+ * interrupt handling.
+ *
+ * Cards without MSI-X will only target one CPU via legacy or MSI interrupt.
+ * The default (0) means to assign an interrupt to each package (level II cache)
+ */
+static unsigned int rss_cpus;
+module_param(rss_cpus, uint, 0444);
+MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
+
+/**************************************************************************
+ *
+ * Utility functions and prototypes
+ *
+ *************************************************************************/
+static void efx_remove_channel(struct efx_channel *channel);
+static void efx_remove_port(struct efx_nic *efx);
+static void efx_fini_napi(struct efx_nic *efx);
+static void efx_fini_channels(struct efx_nic *efx);
+
+#define EFX_ASSERT_RESET_SERIALISED(efx) \
+ do { \
+ if ((efx->state == STATE_RUNNING) || \
+ (efx->state == STATE_RESETTING)) \
+ ASSERT_RTNL(); \
+ } while (0)
+
+/**************************************************************************
+ *
+ * Event queue processing
+ *
+ *************************************************************************/
+
+/* Process channel's event queue
+ *
+ * This function is responsible for processing the event queue of a
+ * single channel. The caller must guarantee that this function will
+ * never be concurrently called more than once on the same channel,
+ * though different channels may be being processed concurrently.
+ */
+static inline int efx_process_channel(struct efx_channel *channel, int rx_quota)
+{
+ int rxdmaqs;
+ struct efx_rx_queue *rx_queue;
+
+ if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE ||
+ !channel->enabled))
+ return rx_quota;
+
+ rxdmaqs = falcon_process_eventq(channel, &rx_quota);
+
+ /* Deliver last RX packet. */
+ if (channel->rx_pkt) {
+ __efx_rx_packet(channel, channel->rx_pkt,
+ channel->rx_pkt_csummed);
+ channel->rx_pkt = NULL;
+ }
+
+ efx_flush_lro(channel);
+ efx_rx_strategy(channel);
+
+ /* Refill descriptor rings as necessary */
+ rx_queue = &channel->efx->rx_queue[0];
+ while (rxdmaqs) {
+ if (rxdmaqs & 0x01)
+ efx_fast_push_rx_descriptors(rx_queue);
+ rx_queue++;
+ rxdmaqs >>= 1;
+ }
+
+ return rx_quota;
+}
+
+/* Mark channel as finished processing
+ *
+ * Note that since we will not receive further interrupts for this
+ * channel before we finish processing and call the eventq_read_ack()
+ * method, there is no need to use the interrupt hold-off timers.
+ */
+static inline void efx_channel_processed(struct efx_channel *channel)
+{
+ /* Write to EVQ_RPTR_REG. If a new event arrived in a race
+ * with finishing processing, a new interrupt will be raised.
+ */
+ channel->work_pending = 0;
+ smp_wmb(); /* Ensure channel updated before any new interrupt. */
+ falcon_eventq_read_ack(channel);
+}
+
+/* NAPI poll handler
+ *
+ * NAPI guarantees serialisation of polls of the same device, which
+ * provides the guarantee required by efx_process_channel().
+ */
+static int efx_poll(struct napi_struct *napi, int budget)
+{
+ struct efx_channel *channel =
+ container_of(napi, struct efx_channel, napi_str);
+ struct net_device *napi_dev = channel->napi_dev;
+ int unused;
+ int rx_packets;
+
+ EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
+ channel->channel, raw_smp_processor_id());
+
+ unused = efx_process_channel(channel, budget);
+ rx_packets = (budget - unused);
+
+ if (rx_packets < budget) {
+ /* There is no race here; although napi_disable() will
+ * only wait for netif_rx_complete(), this isn't a problem
+ * since efx_channel_processed() will have no effect if
+ * interrupts have already been disabled.
+ */
+ netif_rx_complete(napi_dev, napi);
+ efx_channel_processed(channel);
+ }
+
+ return rx_packets;
+}
+
+/* Process the eventq of the specified channel immediately on this CPU
+ *
+ * Disable hardware generated interrupts, wait for any existing
+ * processing to finish, then directly poll (and ack ) the eventq.
+ * Finally reenable NAPI and interrupts.
+ *
+ * Since we are touching interrupts the caller should hold the suspend lock
+ */
+void efx_process_channel_now(struct efx_channel *channel)
+{
+ struct efx_nic *efx = channel->efx;
+
+ BUG_ON(!channel->used_flags);
+ BUG_ON(!channel->enabled);
+
+ /* Disable interrupts and wait for ISRs to complete */
+ falcon_disable_interrupts(efx);
+ if (efx->legacy_irq)
+ synchronize_irq(efx->legacy_irq);
+ if (channel->has_interrupt && channel->irq)
+ synchronize_irq(channel->irq);
+
+ /* Wait for any NAPI processing to complete */
+ napi_disable(&channel->napi_str);
+
+ /* Poll the channel */
+ (void) efx_process_channel(channel, efx->type->evq_size);
+
+ /* Ack the eventq. This may cause an interrupt to be generated
+ * when they are reenabled */
+ efx_channel_processed(channel);
+
+ napi_enable(&channel->napi_str);
+ falcon_enable_interrupts(efx);
+}
+
+/* Create event queue
+ * Event queue memory allocations are done only once. If the channel
+ * is reset, the memory buffer will be reused; this guards against
+ * errors during channel reset and also simplifies interrupt handling.
+ */
+static int efx_probe_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel);
+
+ return falcon_probe_eventq(channel);
+}
+
+/* Prepare channel's event queue */
+static int efx_init_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel);
+
+ channel->eventq_read_ptr = 0;
+
+ return falcon_init_eventq(channel);
+}
+
+static void efx_fini_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel);
+
+ falcon_fini_eventq(channel);
+}
+
+static void efx_remove_eventq(struct efx_channel *channel)
+{
+ EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel);
+
+ falcon_remove_eventq(channel);
+}
+
+/**************************************************************************
+ *
+ * Channel handling
+ *
+ *************************************************************************/
+
+/* Setup per-NIC RX buffer parameters.
+ * Calculate the rx buffer allocation parameters required to support
+ * the current MTU, including padding for header alignment and overruns.
+ */
+static void efx_calc_rx_buffer_params(struct efx_nic *efx)
+{
+ unsigned int order, len;
+
+ len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
+ EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
+ efx->type->rx_buffer_padding);
+
+ /* Calculate page-order */
+ for (order = 0; ((1u << order) * PAGE_SIZE) < len; ++order)
+ ;
+
+ efx->rx_buffer_len = len;
+ efx->rx_buffer_order = order;
+}
+
+static int efx_probe_channel(struct efx_channel *channel)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ int rc;
+
+ EFX_LOG(channel->efx, "creating channel %d\n", channel->channel);
+
+ rc = efx_probe_eventq(channel);
+ if (rc)
+ goto fail1;
+
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ rc = efx_probe_tx_queue(tx_queue);
+ if (rc)
+ goto fail2;
+ }
+
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ rc = efx_probe_rx_queue(rx_queue);
+ if (rc)
+ goto fail3;
+ }
+
+ channel->n_rx_frm_trunc = 0;
+
+ return 0;
+
+ fail3:
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_remove_rx_queue(rx_queue);
+ fail2:
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_remove_tx_queue(tx_queue);
+ fail1:
+ return rc;
+}
+
+
+/* Channels are shutdown and reinitialised whilst the NIC is running
+ * to propagate configuration changes (mtu, checksum offload), or
+ * to clear hardware error conditions
+ */
+static int efx_init_channels(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ struct efx_channel *channel;
+ int rc = 0;
+
+ efx_calc_rx_buffer_params(efx);
+
+ /* Initialise the channels */
+ efx_for_each_channel(channel, efx) {
+ EFX_LOG(channel->efx, "init chan %d\n", channel->channel);
+
+ rc = efx_init_eventq(channel);
+ if (rc)
+ goto err;
+
+ efx_for_each_channel_tx_queue(tx_queue, channel) {
+ rc = efx_init_tx_queue(tx_queue);
+ if (rc)
+ goto err;
+ }
+
+ /* The rx buffer allocation strategy is MTU dependent */
+ efx_rx_strategy(channel);
+
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ rc = efx_init_rx_queue(rx_queue);
+ if (rc)
+ goto err;
+ }
+
+ WARN_ON(channel->rx_pkt != NULL);
+ efx_rx_strategy(channel);
+ }
+
+ return 0;
+
+ err:
+ EFX_ERR(efx, "failed to initialise channel %d\n",
+ channel ? channel->channel : -1);
+ efx_fini_channels(efx);
+ return rc;
+}
+
+/* This enables event queue processing and packet transmission.
+ *
+ * Note that this function is not allowed to fail, since that would
+ * introduce too much complexity into the suspend/resume path.
+ */
+static void efx_start_channel(struct efx_channel *channel)
+{
+ struct efx_rx_queue *rx_queue;
+
+ EFX_LOG(channel->efx, "starting chan %d\n", channel->channel);
+
+ if (!(channel->efx->net_dev->flags & IFF_UP))
+ netif_napi_add(channel->napi_dev, &channel->napi_str,
+ efx_poll, napi_weight);
+
+ channel->work_pending = 0;
+ channel->enabled = 1;
+ smp_wmb(); /* ensure channel updated before first interrupt */
+
+ napi_enable(&channel->napi_str);
+
+ /* Load up RX descriptors */
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_fast_push_rx_descriptors(rx_queue);
+}
+
+/* This disables event queue processing and packet transmission.
+ * This function does not guarantee that all queue processing
+ * (e.g. RX refill) is complete.
+ */
+static void efx_stop_channel(struct efx_channel *channel)
+{
+ struct efx_rx_queue *rx_queue;
+
+ if (!channel->enabled)
+ return;
+
+ EFX_LOG(channel->efx, "stop chan %d\n", channel->channel);
+
+ channel->enabled = 0;
+ napi_disable(&channel->napi_str);
+
+ /* Ensure that any worker threads have exited or will be no-ops */
+ efx_for_each_channel_rx_queue(rx_queue, channel) {
+ spin_lock_bh(&rx_queue->add_lock);
+ spin_unlock_bh(&rx_queue->add_lock);
+ }
+}
+
+static void efx_fini_channels(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+ BUG_ON(efx->port_enabled);
+
+ efx_for_each_channel(channel, efx) {
+ EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
+
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_fini_rx_queue(rx_queue);
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_fini_tx_queue(tx_queue);
+ }
+
+ /* Do the event queues last so that we can handle flush events
+ * for all DMA queues. */
+ efx_for_each_channel(channel, efx) {
+ EFX_LOG(channel->efx, "shut down evq %d\n", channel->channel);
+
+ efx_fini_eventq(channel);
+ }
+}
+
+static void efx_remove_channel(struct efx_channel *channel)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+
+ EFX_LOG(channel->efx, "destroy chan %d\n", channel->channel);
+
+ efx_for_each_channel_rx_queue(rx_queue, channel)
+ efx_remove_rx_queue(rx_queue);
+ efx_for_each_channel_tx_queue(tx_queue, channel)
+ efx_remove_tx_queue(tx_queue);
+ efx_remove_eventq(channel);
+
+ channel->used_flags = 0;
+}
+
+void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay)
+{
+ queue_delayed_work(refill_workqueue, &rx_queue->work, delay);
+}
+
+/**************************************************************************
+ *
+ * Port handling
+ *
+ **************************************************************************/
+
+/* This ensures that the kernel is kept informed (via
+ * netif_carrier_on/off) of the link status, and also maintains the
+ * link status's stop on the port's TX queue.
+ */
+static void efx_link_status_changed(struct efx_nic *efx)
+{
+ int carrier_ok;
+
+ /* SFC Bug 5356: A net_dev notifier is registered, so we must ensure
+ * that no events are triggered between unregister_netdev() and the
+ * driver unloading. A more general condition is that NETDEV_CHANGE
+ * can only be generated between NETDEV_UP and NETDEV_DOWN */
+ if (!netif_running(efx->net_dev))
+ return;
+
+ carrier_ok = netif_carrier_ok(efx->net_dev) ? 1 : 0;
+ if (efx->link_up != carrier_ok) {
+ efx->n_link_state_changes++;
+
+ if (efx->link_up)
+ netif_carrier_on(efx->net_dev);
+ else
+ netif_carrier_off(efx->net_dev);
+ }
+
+ /* Status message for kernel log */
+ if (efx->link_up) {
+ struct mii_if_info *gmii = &efx->mii;
+ unsigned adv, lpa;
+ /* NONE here means direct XAUI from the controller, with no
+ * MDIO-attached device we can query. */
+ if (efx->phy_type != PHY_TYPE_NONE) {
+ adv = gmii_advertised(gmii);
+ lpa = gmii_lpa(gmii);
+ } else {
+ lpa = GM_LPA_10000 | LPA_DUPLEX;
+ adv = lpa;
+ }
+ EFX_INFO(efx, "link up at %dMbps %s-duplex "
+ "(adv %04x lpa %04x) (MTU %d)%s\n",
+ (efx->link_options & GM_LPA_10000 ? 10000 :
+ (efx->link_options & GM_LPA_1000 ? 1000 :
+ (efx->link_options & GM_LPA_100 ? 100 :
+ 10))),
+ (efx->link_options & GM_LPA_DUPLEX ?
+ "full" : "half"),
+ adv, lpa,
+ efx->net_dev->mtu,
+ (efx->promiscuous ? " [PROMISC]" : ""));
+ } else {
+ EFX_INFO(efx, "link down\n");
+ }
+
+}
+
+/* This call reinitialises the MAC to pick up new PHY settings. The
+ * caller must hold the mac_lock */
+static void __efx_reconfigure_port(struct efx_nic *efx)
+{
+ WARN_ON(!mutex_is_locked(&efx->mac_lock));
+
+ EFX_LOG(efx, "reconfiguring MAC from PHY settings on CPU %d\n",
+ raw_smp_processor_id());
+
+ falcon_reconfigure_xmac(efx);
+
+ /* Inform kernel of loss/gain of carrier */
+ efx_link_status_changed(efx);
+}
+
+/* Reinitialise the MAC to pick up new PHY settings, even if the port is
+ * disabled. */
+void efx_reconfigure_port(struct efx_nic *efx)
+{
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ mutex_lock(&efx->mac_lock);
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+}
+
+/* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all()
+ * we don't efx_reconfigure_port() if the port is disabled. Care is taken
+ * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */
+static void efx_reconfigure_work(struct work_struct *data)
+{
+ struct efx_nic *efx = container_of(data, struct efx_nic,
+ reconfigure_work);
+
+ mutex_lock(&efx->mac_lock);
+ if (efx->port_enabled)
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+}
+
+static int efx_probe_port(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_LOG(efx, "create port\n");
+
+ /* Connect up MAC/PHY operations table and read MAC address */
+ rc = falcon_probe_port(efx);
+ if (rc)
+ goto err;
+
+ /* Sanity check MAC address */
+ if (is_valid_ether_addr(efx->mac_address)) {
+ memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
+ } else {
+ DECLARE_MAC_BUF(mac);
+
+ EFX_ERR(efx, "invalid MAC address %s\n",
+ print_mac(mac, efx->mac_address));
+ if (!allow_bad_hwaddr) {
+ rc = -EINVAL;
+ goto err;
+ }
+ random_ether_addr(efx->net_dev->dev_addr);
+ EFX_INFO(efx, "using locally-generated MAC %s\n",
+ print_mac(mac, efx->net_dev->dev_addr));
+ }
+
+ return 0;
+
+ err:
+ efx_remove_port(efx);
+ return rc;
+}
+
+static int efx_init_port(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_LOG(efx, "init port\n");
+
+ /* Initialise the MAC and PHY */
+ rc = falcon_init_xmac(efx);
+ if (rc)
+ return rc;
+
+ efx->port_initialized = 1;
+
+ /* Reconfigure port to program MAC registers */
+ falcon_reconfigure_xmac(efx);
+
+ return 0;
+}
+
+/* Allow efx_reconfigure_port() to be scheduled, and close the window
+ * between efx_stop_port and efx_flush_all whereby a previously scheduled
+ * efx_reconfigure_port() may have been cancelled */
+static void efx_start_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "start port\n");
+ BUG_ON(efx->port_enabled);
+
+ mutex_lock(&efx->mac_lock);
+ efx->port_enabled = 1;
+ __efx_reconfigure_port(efx);
+ mutex_unlock(&efx->mac_lock);
+}
+
+/* Prevent efx_reconfigure_work and efx_monitor() from executing, and
+ * efx_set_multicast_list() from scheduling efx_reconfigure_work.
+ * efx_reconfigure_work can still be scheduled via NAPI processing
+ * until efx_flush_all() is called */
+static void efx_stop_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "stop port\n");
+
+ mutex_lock(&efx->mac_lock);
+ efx->port_enabled = 0;
+ mutex_unlock(&efx->mac_lock);
+
+ /* Serialise against efx_set_multicast_list() */
+ if (NET_DEV_REGISTERED(efx)) {
+ netif_tx_lock_bh(efx->net_dev);
+ netif_tx_unlock_bh(efx->net_dev);
+ }
+}
+
+static void efx_fini_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "shut down port\n");
+
+ if (!efx->port_initialized)
+ return;
+
+ falcon_fini_xmac(efx);
+ efx->port_initialized = 0;
+
+ efx->link_up = 0;
+ efx_link_status_changed(efx);
+}
+
+static void efx_remove_port(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "destroying port\n");
+
+ falcon_remove_port(efx);
+}
+
+/**************************************************************************
+ *
+ * NIC handling
+ *
+ **************************************************************************/
+
+/* This configures the PCI device to enable I/O and DMA. */
+static int efx_init_io(struct efx_nic *efx)
+{
+ struct pci_dev *pci_dev = efx->pci_dev;
+ dma_addr_t dma_mask = efx->type->max_dma_mask;
+ int rc;
+
+ EFX_LOG(efx, "initialising I/O\n");
+
+ rc = pci_enable_device(pci_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed to enable PCI device\n");
+ goto fail1;
+ }
+
+ pci_set_master(pci_dev);
+
+ /* Set the PCI DMA mask. Try all possibilities from our
+ * genuine mask down to 32 bits, because some architectures
+ * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit
+ * masks event though they reject 46 bit masks.
+ */
+ while (dma_mask > 0x7fffffffUL) {
+ if (pci_dma_supported(pci_dev, dma_mask) &&
+ ((rc = pci_set_dma_mask(pci_dev, dma_mask)) == 0))
+ break;
+ dma_mask >>= 1;
+ }
+ if (rc) {
+ EFX_ERR(efx, "could not find a suitable DMA mask\n");
+ goto fail2;
+ }
+ EFX_LOG(efx, "using DMA mask %llx\n", (unsigned long long) dma_mask);
+ rc = pci_set_consistent_dma_mask(pci_dev, dma_mask);
+ if (rc) {
+ /* pci_set_consistent_dma_mask() is not *allowed* to
+ * fail with a mask that pci_set_dma_mask() accepted,
+ * but just in case...
+ */
+ EFX_ERR(efx, "failed to set consistent DMA mask\n");
+ goto fail2;
+ }
+
+ efx->membase_phys = pci_resource_start(efx->pci_dev,
+ efx->type->mem_bar);
+ rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc");
+ if (rc) {
+ EFX_ERR(efx, "request for memory BAR failed\n");
+ rc = -EIO;
+ goto fail3;
+ }
+ efx->membase = ioremap_nocache(efx->membase_phys,
+ efx->type->mem_map_size);
+ if (!efx->membase) {
+ EFX_ERR(efx, "could not map memory BAR %d at %lx+%x\n",
+ efx->type->mem_bar, efx->membase_phys,
+ efx->type->mem_map_size);
+ rc = -ENOMEM;
+ goto fail4;
+ }
+ EFX_LOG(efx, "memory BAR %u at %lx+%x (virtual %p)\n",
+ efx->type->mem_bar, efx->membase_phys, efx->type->mem_map_size,
+ efx->membase);
+
+ return 0;
+
+ fail4:
+ release_mem_region(efx->membase_phys, efx->type->mem_map_size);
+ fail3:
+ efx->membase_phys = 0UL;
+ fail2:
+ pci_disable_device(efx->pci_dev);
+ fail1:
+ return rc;
+}
+
+static void efx_fini_io(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "shutting down I/O\n");
+
+ if (efx->membase) {
+ iounmap(efx->membase);
+ efx->membase = NULL;
+ }
+
+ if (efx->membase_phys) {
+ pci_release_region(efx->pci_dev, efx->type->mem_bar);
+ efx->membase_phys = 0UL;
+ }
+
+ pci_disable_device(efx->pci_dev);
+}
+
+/* Probe the number and type of interrupts we are able to obtain. */
+static void efx_probe_interrupts(struct efx_nic *efx)
+{
+ int max_channel = efx->type->phys_addr_channels - 1;
+ struct msix_entry xentries[EFX_MAX_CHANNELS];
+ int rc, i;
+
+ if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
+ BUG_ON(!pci_find_capability(efx->pci_dev, PCI_CAP_ID_MSIX));
+
+ efx->rss_queues = rss_cpus ? rss_cpus : num_online_cpus();
+ efx->rss_queues = min(efx->rss_queues, max_channel + 1);
+ efx->rss_queues = min(efx->rss_queues, EFX_MAX_CHANNELS);
+
+ /* Request maximum number of MSI interrupts, and fill out
+ * the channel interrupt information the allowed allocation */
+ for (i = 0; i < efx->rss_queues; i++)
+ xentries[i].entry = i;
+ rc = pci_enable_msix(efx->pci_dev, xentries, efx->rss_queues);
+ if (rc > 0) {
+ EFX_BUG_ON_PARANOID(rc >= efx->rss_queues);
+ efx->rss_queues = rc;
+ rc = pci_enable_msix(efx->pci_dev, xentries,
+ efx->rss_queues);
+ }
+
+ if (rc == 0) {
+ for (i = 0; i < efx->rss_queues; i++) {
+ efx->channel[i].has_interrupt = 1;
+ efx->channel[i].irq = xentries[i].vector;
+ }
+ } else {
+ /* Fall back to single channel MSI */
+ efx->interrupt_mode = EFX_INT_MODE_MSI;
+ EFX_ERR(efx, "could not enable MSI-X\n");
+ }
+ }
+
+ /* Try single interrupt MSI */
+ if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
+ efx->rss_queues = 1;
+ rc = pci_enable_msi(efx->pci_dev);
+ if (rc == 0) {
+ efx->channel[0].irq = efx->pci_dev->irq;
+ efx->channel[0].has_interrupt = 1;
+ } else {
+ EFX_ERR(efx, "could not enable MSI\n");
+ efx->interrupt_mode = EFX_INT_MODE_LEGACY;
+ }
+ }
+
+ /* Assume legacy interrupts */
+ if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
+ efx->rss_queues = 1;
+ /* Every channel is interruptible */
+ for (i = 0; i < EFX_MAX_CHANNELS; i++)
+ efx->channel[i].has_interrupt = 1;
+ efx->legacy_irq = efx->pci_dev->irq;
+ }
+}
+
+static void efx_remove_interrupts(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ /* Remove MSI/MSI-X interrupts */
+ efx_for_each_channel_with_interrupt(channel, efx)
+ channel->irq = 0;
+ pci_disable_msi(efx->pci_dev);
+ pci_disable_msix(efx->pci_dev);
+
+ /* Remove legacy interrupt */
+ efx->legacy_irq = 0;
+}
+
+/* Select number of used resources
+ * Should be called after probe_interrupts()
+ */
+static void efx_select_used(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ int i;
+
+ /* TX queues. One per port per channel with TX capability
+ * (more than one per port won't work on Linux, due to out
+ * of order issues... but will be fine on Solaris)
+ */
+ tx_queue = &efx->tx_queue[0];
+
+ /* Perform this for each channel with TX capabilities.
+ * At the moment, we only support a single TX queue
+ */
+ tx_queue->used = 1;
+ if ((!EFX_INT_MODE_USE_MSI(efx)) && separate_tx_and_rx_channels)
+ tx_queue->channel = &efx->channel[1];
+ else
+ tx_queue->channel = &efx->channel[0];
+ tx_queue->channel->used_flags |= EFX_USED_BY_TX;
+ tx_queue++;
+
+ /* RX queues. Each has a dedicated channel. */
+ for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
+ rx_queue = &efx->rx_queue[i];
+
+ if (i < efx->rss_queues) {
+ rx_queue->used = 1;
+ /* If we allow multiple RX queues per channel
+ * we need to decide that here
+ */
+ rx_queue->channel = &efx->channel[rx_queue->queue];
+ rx_queue->channel->used_flags |= EFX_USED_BY_RX;
+ rx_queue++;
+ }
+ }
+}
+
+static int efx_probe_nic(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_LOG(efx, "creating NIC\n");
+
+ /* Carry out hardware-type specific initialisation */
+ rc = falcon_probe_nic(efx);
+ if (rc)
+ return rc;
+
+ /* Determine the number of channels and RX queues by trying to hook
+ * in MSI-X interrupts. */
+ efx_probe_interrupts(efx);
+
+ /* Determine number of RX queues and TX queues */
+ efx_select_used(efx);
+
+ /* Initialise the interrupt moderation settings */
+ efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec);
+
+ return 0;
+}
+
+static void efx_remove_nic(struct efx_nic *efx)
+{
+ EFX_LOG(efx, "destroying NIC\n");
+
+ efx_remove_interrupts(efx);
+ falcon_remove_nic(efx);
+}
+
+/**************************************************************************
+ *
+ * NIC startup/shutdown
+ *
+ *************************************************************************/
+
+static int efx_probe_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ /* Create NIC */
+ rc = efx_probe_nic(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to create NIC\n");
+ goto fail1;
+ }
+
+ /* Create port */
+ rc = efx_probe_port(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to create port\n");
+ goto fail2;
+ }
+
+ /* Create channels */
+ efx_for_each_channel(channel, efx) {
+ rc = efx_probe_channel(channel);
+ if (rc) {
+ EFX_ERR(efx, "failed to create channel %d\n",
+ channel->channel);
+ goto fail3;
+ }
+ }
+
+ return 0;
+
+ fail3:
+ efx_for_each_channel(channel, efx)
+ efx_remove_channel(channel);
+ efx_remove_port(efx);
+ fail2:
+ efx_remove_nic(efx);
+ fail1:
+ return rc;
+}
+
+/* Called after previous invocation(s) of efx_stop_all, restarts the
+ * port, kernel transmit queue, NAPI processing and hardware interrupts,
+ * and ensures that the port is scheduled to be reconfigured.
+ * This function is safe to call multiple times when the NIC is in any
+ * state. */
+static void efx_start_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ /* Check that it is appropriate to restart the interface. All
+ * of these flags are safe to read under just the rtnl lock */
+ if (efx->port_enabled)
+ return;
+ if ((efx->state != STATE_RUNNING) && (efx->state != STATE_INIT))
+ return;
+ if (NET_DEV_REGISTERED(efx) && !netif_running(efx->net_dev))
+ return;
+
+ /* Mark the port as enabled so port reconfigurations can start, then
+ * restart the transmit interface early so the watchdog timer stops */
+ efx_start_port(efx);
+ efx_wake_queue(efx);
+
+ efx_for_each_channel(channel, efx)
+ efx_start_channel(channel);
+
+ falcon_enable_interrupts(efx);
+
+ /* Start hardware monitor if we're in RUNNING */
+ if (efx->state == STATE_RUNNING)
+ queue_delayed_work(efx->workqueue, &efx->monitor_work,
+ efx_monitor_interval);
+}
+
+/* Flush all delayed work. Should only be called when no more delayed work
+ * will be scheduled. This doesn't flush pending online resets (efx_reset),
+ * since we're holding the rtnl_lock at this point. */
+static void efx_flush_all(struct efx_nic *efx)
+{
+ struct efx_rx_queue *rx_queue;
+
+ /* Make sure the hardware monitor is stopped */
+ cancel_delayed_work_sync(&efx->monitor_work);
+
+ /* Ensure that all RX slow refills are complete. */
+ efx_for_each_rx_queue(rx_queue, efx) {
+ cancel_delayed_work_sync(&rx_queue->work);
+ }
+
+ /* Stop scheduled port reconfigurations */
+ cancel_work_sync(&efx->reconfigure_work);
+
+}
+
+/* Quiesce hardware and software without bringing the link down.
+ * Safe to call multiple times, when the nic and interface is in any
+ * state. The caller is guaranteed to subsequently be in a position
+ * to modify any hardware and software state they see fit without
+ * taking locks. */
+static void efx_stop_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ /* port_enabled can be read safely under the rtnl lock */
+ if (!efx->port_enabled)
+ return;
+
+ /* Disable interrupts and wait for ISR to complete */
+ falcon_disable_interrupts(efx);
+ if (efx->legacy_irq)
+ synchronize_irq(efx->legacy_irq);
+ efx_for_each_channel_with_interrupt(channel, efx)
+ if (channel->irq)
+ synchronize_irq(channel->irq);
+
+ /* Stop all NAPI processing and synchronous rx refills */
+ efx_for_each_channel(channel, efx)
+ efx_stop_channel(channel);
+
+ /* Stop all asynchronous port reconfigurations. Since all
+ * event processing has already been stopped, there is no
+ * window to loose phy events */
+ efx_stop_port(efx);
+
+ /* Flush reconfigure_work, refill_workqueue, monitor_work */
+ efx_flush_all(efx);
+
+ /* Isolate the MAC from the TX and RX engines, so that queue
+ * flushes will complete in a timely fashion. */
+ falcon_deconfigure_mac_wrapper(efx);
+ falcon_drain_tx_fifo(efx);
+
+ /* Stop the kernel transmit interface late, so the watchdog
+ * timer isn't ticking over the flush */
+ efx_stop_queue(efx);
+ if (NET_DEV_REGISTERED(efx)) {
+ netif_tx_lock_bh(efx->net_dev);
+ netif_tx_unlock_bh(efx->net_dev);
+ }
+}
+
+static void efx_remove_all(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ efx_for_each_channel(channel, efx)
+ efx_remove_channel(channel);
+ efx_remove_port(efx);
+ efx_remove_nic(efx);
+}
+
+/* A convinience function to safely flush all the queues */
+int efx_flush_queues(struct efx_nic *efx)
+{
+ int rc;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ efx_stop_all(efx);
+
+ efx_fini_channels(efx);
+ rc = efx_init_channels(efx);
+ if (rc) {
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+ return rc;
+ }
+
+ efx_start_all(efx);
+
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * Interrupt moderation
+ *
+ **************************************************************************/
+
+/* Set interrupt moderation parameters */
+void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
+{
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ efx_for_each_tx_queue(tx_queue, efx)
+ tx_queue->channel->irq_moderation = tx_usecs;
+
+ efx_for_each_rx_queue(rx_queue, efx)
+ rx_queue->channel->irq_moderation = rx_usecs;
+}
+
+/**************************************************************************
+ *
+ * Hardware monitor
+ *
+ **************************************************************************/
+
+/* Run periodically off the general workqueue. Serialised against
+ * efx_reconfigure_port via the mac_lock */
+static void efx_monitor(struct work_struct *data)
+{
+ struct efx_nic *efx = container_of(data, struct efx_nic,
+ monitor_work.work);
+ int rc = 0;
+
+ EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
+ raw_smp_processor_id());
+
+
+ /* If the mac_lock is already held then it is likely a port
+ * reconfiguration is already in place, which will likely do
+ * most of the work of check_hw() anyway. */
+ if (!mutex_trylock(&efx->mac_lock)) {
+ queue_delayed_work(efx->workqueue, &efx->monitor_work,
+ efx_monitor_interval);
+ return;
+ }
+
+ if (efx->port_enabled)
+ rc = falcon_check_xmac(efx);
+ mutex_unlock(&efx->mac_lock);
+
+ if (rc) {
+ if (monitor_reset) {
+ EFX_ERR(efx, "hardware monitor detected a fault: "
+ "triggering reset\n");
+ efx_schedule_reset(efx, RESET_TYPE_MONITOR);
+ } else {
+ EFX_ERR(efx, "hardware monitor detected a fault, "
+ "skipping reset\n");
+ }
+ }
+
+ queue_delayed_work(efx->workqueue, &efx->monitor_work,
+ efx_monitor_interval);
+}
+
+/**************************************************************************
+ *
+ * ioctls
+ *
+ *************************************************************************/
+
+/* Net device ioctl
+ * Context: process, rtnl_lock() held.
+ */
+static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ return generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL);
+}
+
+/**************************************************************************
+ *
+ * NAPI interface
+ *
+ **************************************************************************/
+
+static int efx_init_napi(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ efx_for_each_channel(channel, efx) {
+ channel->napi_dev = efx->net_dev;
+ rc = efx_lro_init(&channel->lro_mgr, efx);
+ if (rc)
+ goto err;
+ }
+ return 0;
+ err:
+ efx_fini_napi(efx);
+ return rc;
+}
+
+static void efx_fini_napi(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+
+ efx_for_each_channel(channel, efx) {
+ efx_lro_fini(&channel->lro_mgr);
+ channel->napi_dev = NULL;
+ }
+}
+
+/**************************************************************************
+ *
+ * Kernel netpoll interface
+ *
+ *************************************************************************/
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+
+/* Although in the common case interrupts will be disabled, this is not
+ * guaranteed. However, all our work happens inside the NAPI callback,
+ * so no locking is required.
+ */
+static void efx_netpoll(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_channel *channel;
+
+ efx_for_each_channel_with_interrupt(channel, efx)
+ efx_schedule_channel(channel);
+}
+
+#endif
+
+/**************************************************************************
+ *
+ * Kernel net device interface
+ *
+ *************************************************************************/
+
+/* Context: process, rtnl_lock() held. */
+static int efx_net_open(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name,
+ raw_smp_processor_id());
+
+ efx_start_all(efx);
+ return 0;
+}
+
+/* Context: process, rtnl_lock() held.
+ * Note that the kernel will ignore our return code; this method
+ * should really be a void.
+ */
+static int efx_net_stop(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name,
+ raw_smp_processor_id());
+
+ /* Stop the device and flush all the channels */
+ efx_stop_all(efx);
+ efx_fini_channels(efx);
+ rc = efx_init_channels(efx);
+ if (rc)
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+
+ return 0;
+}
+
+/* Context: process, dev_base_lock held, non-blocking. */
+static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_mac_stats *mac_stats = &efx->mac_stats;
+ struct net_device_stats *stats = &net_dev->stats;
+
+ if (!spin_trylock(&efx->stats_lock))
+ return stats;
+ if (efx->state == STATE_RUNNING) {
+ falcon_update_stats_xmac(efx);
+ falcon_update_nic_stats(efx);
+ }
+ spin_unlock(&efx->stats_lock);
+
+ stats->rx_packets = mac_stats->rx_packets;
+ stats->tx_packets = mac_stats->tx_packets;
+ stats->rx_bytes = mac_stats->rx_bytes;
+ stats->tx_bytes = mac_stats->tx_bytes;
+ stats->multicast = mac_stats->rx_multicast;
+ stats->collisions = mac_stats->tx_collision;
+ stats->rx_length_errors = (mac_stats->rx_gtjumbo +
+ mac_stats->rx_length_error);
+ stats->rx_over_errors = efx->n_rx_nodesc_drop_cnt;
+ stats->rx_crc_errors = mac_stats->rx_bad;
+ stats->rx_frame_errors = mac_stats->rx_align_error;
+ stats->rx_fifo_errors = mac_stats->rx_overflow;
+ stats->rx_missed_errors = mac_stats->rx_missed;
+ stats->tx_window_errors = mac_stats->tx_late_collision;
+
+ stats->rx_errors = (stats->rx_length_errors +
+ stats->rx_over_errors +
+ stats->rx_crc_errors +
+ stats->rx_frame_errors +
+ stats->rx_fifo_errors +
+ stats->rx_missed_errors +
+ mac_stats->rx_symbol_error);
+ stats->tx_errors = (stats->tx_window_errors +
+ mac_stats->tx_bad);
+
+ return stats;
+}
+
+/* Context: netif_tx_lock held, BHs disabled. */
+static void efx_watchdog(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n",
+ atomic_read(&efx->netif_stop_count), efx->port_enabled,
+ monitor_reset ? "resetting channels" : "skipping reset");
+
+ if (monitor_reset)
+ efx_schedule_reset(efx, RESET_TYPE_MONITOR);
+}
+
+
+/* Context: process, rtnl_lock() held. */
+static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc = 0;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ if (new_mtu > EFX_MAX_MTU)
+ return -EINVAL;
+
+ efx_stop_all(efx);
+
+ EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
+
+ efx_fini_channels(efx);
+ net_dev->mtu = new_mtu;
+ rc = efx_init_channels(efx);
+ if (rc)
+ goto fail;
+
+ efx_start_all(efx);
+ return rc;
+
+ fail:
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+ return rc;
+}
+
+static int efx_set_mac_address(struct net_device *net_dev, void *data)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct sockaddr *addr = data;
+ char *new_addr = addr->sa_data;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ if (!is_valid_ether_addr(new_addr)) {
+ DECLARE_MAC_BUF(mac);
+ EFX_ERR(efx, "invalid ethernet MAC address requested: %s\n",
+ print_mac(mac, new_addr));
+ return -EINVAL;
+ }
+
+ memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
+
+ /* Reconfigure the MAC */
+ efx_reconfigure_port(efx);
+
+ return 0;
+}
+
+/* Context: netif_tx_lock held, BHs disabled. */
+static void efx_set_multicast_list(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct dev_mc_list *mc_list = net_dev->mc_list;
+ union efx_multicast_hash *mc_hash = &efx->multicast_hash;
+ int promiscuous;
+ u32 crc;
+ int bit;
+ int i;
+
+ /* Set per-MAC promiscuity flag and reconfigure MAC if necessary */
+ promiscuous = (net_dev->flags & IFF_PROMISC) ? 1 : 0;
+ if (efx->promiscuous != promiscuous) {
+ efx->promiscuous = promiscuous;
+ /* Close the window between efx_stop_port() and efx_flush_all()
+ * by only queuing work when the port is enabled. */
+ if (efx->port_enabled)
+ queue_work(efx->workqueue, &efx->reconfigure_work);
+ }
+
+ /* Build multicast hash table */
+ if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
+ memset(mc_hash, 0xff, sizeof(*mc_hash));
+ } else {
+ memset(mc_hash, 0x00, sizeof(*mc_hash));
+ for (i = 0; i < net_dev->mc_count; i++) {
+ crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr);
+ bit = crc & (EFX_MCAST_HASH_ENTRIES - 1);
+ set_bit_le(bit, mc_hash->byte);
+ mc_list = mc_list->next;
+ }
+ }
+
+ /* Create and activate new global multicast hash table */
+ falcon_set_multicast_hash(efx);
+}
+
+static int efx_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *net_dev = (struct net_device *)ptr;
+
+ if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) {
+ struct efx_nic *efx = net_dev->priv;
+
+ strcpy(efx->name, net_dev->name);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block efx_netdev_notifier = {
+ .notifier_call = efx_netdev_event,
+};
+
+static int efx_register_netdev(struct efx_nic *efx)
+{
+ struct net_device *net_dev = efx->net_dev;
+ int rc;
+
+ net_dev->watchdog_timeo = 5 * HZ;
+ net_dev->irq = efx->pci_dev->irq;
+ net_dev->open = efx_net_open;
+ net_dev->stop = efx_net_stop;
+ net_dev->get_stats = efx_net_stats;
+ net_dev->tx_timeout = &efx_watchdog;
+ net_dev->hard_start_xmit = efx_hard_start_xmit;
+ net_dev->do_ioctl = efx_ioctl;
+ net_dev->change_mtu = efx_change_mtu;
+ net_dev->set_mac_address = efx_set_mac_address;
+ net_dev->set_multicast_list = efx_set_multicast_list;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ net_dev->poll_controller = efx_netpoll;
+#endif
+ SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev);
+ SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
+
+ /* Always start with carrier off; PHY events will detect the link */
+ netif_carrier_off(efx->net_dev);
+
+ /* Clear MAC statistics */
+ falcon_update_stats_xmac(efx);
+ memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
+
+ rc = register_netdev(net_dev);
+ if (rc) {
+ EFX_ERR(efx, "could not register net dev\n");
+ return rc;
+ }
+ strcpy(efx->name, net_dev->name);
+
+ return 0;
+}
+
+static void efx_unregister_netdev(struct efx_nic *efx)
+{
+ struct efx_tx_queue *tx_queue;
+
+ if (!efx->net_dev)
+ return;
+
+ BUG_ON(efx->net_dev->priv != efx);
+
+ /* Free up any skbs still remaining. This has to happen before
+ * we try to unregister the netdev as running their destructors
+ * may be needed to get the device ref. count to 0. */
+ efx_for_each_tx_queue(tx_queue, efx)
+ efx_release_tx_buffers(tx_queue);
+
+ if (NET_DEV_REGISTERED(efx)) {
+ strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
+ unregister_netdev(efx->net_dev);
+ }
+}
+
+/**************************************************************************
+ *
+ * Device reset and suspend
+ *
+ **************************************************************************/
+
+/* The final hardware and software finalisation before reset. */
+static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ int rc;
+
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ rc = falcon_xmac_get_settings(efx, ecmd);
+ if (rc) {
+ EFX_ERR(efx, "could not back up PHY settings\n");
+ goto fail;
+ }
+
+ efx_fini_channels(efx);
+ return 0;
+
+ fail:
+ return rc;
+}
+
+/* The first part of software initialisation after a hardware reset
+ * This function does not handle serialisation with the kernel, it
+ * assumes the caller has done this */
+static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ int rc;
+
+ rc = efx_init_channels(efx);
+ if (rc)
+ goto fail1;
+
+ /* Restore MAC and PHY settings. */
+ rc = falcon_xmac_set_settings(efx, ecmd);
+ if (rc) {
+ EFX_ERR(efx, "could not restore PHY settings\n");
+ goto fail2;
+ }
+
+ return 0;
+
+ fail2:
+ efx_fini_channels(efx);
+ fail1:
+ return rc;
+}
+
+/* Reset the NIC as transparently as possible. Do not reset the PHY
+ * Note that the reset may fail, in which case the card will be left
+ * in a most-probably-unusable state.
+ *
+ * This function will sleep. You cannot reset from within an atomic
+ * state; use efx_schedule_reset() instead.
+ *
+ * Grabs the rtnl_lock.
+ */
+static int efx_reset(struct efx_nic *efx)
+{
+ struct ethtool_cmd ecmd;
+ enum reset_type method = efx->reset_pending;
+ int rc;
+
+ /* Serialise with kernel interfaces */
+ rtnl_lock();
+
+ /* If we're not RUNNING then don't reset. Leave the reset_pending
+ * flag set so that efx_pci_probe_main will be retried */
+ if (efx->state != STATE_RUNNING) {
+ EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
+ goto unlock_rtnl;
+ }
+
+ efx->state = STATE_RESETTING;
+ EFX_INFO(efx, "resetting (%d)\n", method);
+
+ /* The net_dev->get_stats handler is quite slow, and will fail
+ * if a fetch is pending over reset. Serialise against it. */
+ spin_lock(&efx->stats_lock);
+ spin_unlock(&efx->stats_lock);
+
+ efx_stop_all(efx);
+ mutex_lock(&efx->mac_lock);
+
+ rc = efx_reset_down(efx, &ecmd);
+ if (rc)
+ goto fail1;
+
+ rc = falcon_reset_hw(efx, method);
+ if (rc) {
+ EFX_ERR(efx, "failed to reset hardware\n");
+ goto fail2;
+ }
+
+ /* Allow resets to be rescheduled. */
+ efx->reset_pending = RESET_TYPE_NONE;
+
+ /* Reinitialise bus-mastering, which may have been turned off before
+ * the reset was scheduled. This is still appropriate, even in the
+ * RESET_TYPE_DISABLE since this driver generally assumes the hardware
+ * can respond to requests. */
+ pci_set_master(efx->pci_dev);
+
+ /* Reinitialise device. This is appropriate in the RESET_TYPE_DISABLE
+ * case so the driver can talk to external SRAM */
+ rc = falcon_init_nic(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise NIC\n");
+ goto fail3;
+ }
+
+ /* Leave device stopped if necessary */
+ if (method == RESET_TYPE_DISABLE) {
+ /* Reinitialise the device anyway so the driver unload sequence
+ * can talk to the external SRAM */
+ (void) falcon_init_nic(efx);
+ rc = -EIO;
+ goto fail4;
+ }
+
+ rc = efx_reset_up(efx, &ecmd);
+ if (rc)
+ goto fail5;
+
+ mutex_unlock(&efx->mac_lock);
+ EFX_LOG(efx, "reset complete\n");
+
+ efx->state = STATE_RUNNING;
+ efx_start_all(efx);
+
+ unlock_rtnl:
+ rtnl_unlock();
+ return 0;
+
+ fail5:
+ fail4:
+ fail3:
+ fail2:
+ fail1:
+ EFX_ERR(efx, "has been disabled\n");
+ efx->state = STATE_DISABLED;
+
+ mutex_unlock(&efx->mac_lock);
+ rtnl_unlock();
+ efx_unregister_netdev(efx);
+ efx_fini_port(efx);
+ return rc;
+}
+
+/* The worker thread exists so that code that cannot sleep can
+ * schedule a reset for later.
+ */
+static void efx_reset_work(struct work_struct *data)
+{
+ struct efx_nic *nic = container_of(data, struct efx_nic, reset_work);
+
+ efx_reset(nic);
+}
+
+void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
+{
+ enum reset_type method;
+
+ if (efx->reset_pending != RESET_TYPE_NONE) {
+ EFX_INFO(efx, "quenching already scheduled reset\n");
+ return;
+ }
+
+ switch (type) {
+ case RESET_TYPE_INVISIBLE:
+ case RESET_TYPE_ALL:
+ case RESET_TYPE_WORLD:
+ case RESET_TYPE_DISABLE:
+ method = type;
+ break;
+ case RESET_TYPE_RX_RECOVERY:
+ case RESET_TYPE_RX_DESC_FETCH:
+ case RESET_TYPE_TX_DESC_FETCH:
+ case RESET_TYPE_TX_SKIP:
+ method = RESET_TYPE_INVISIBLE;
+ break;
+ default:
+ method = RESET_TYPE_ALL;
+ break;
+ }
+
+ if (method != type)
+ EFX_LOG(efx, "scheduling reset (%d:%d)\n", type, method);
+ else
+ EFX_LOG(efx, "scheduling reset (%d)\n", method);
+
+ efx->reset_pending = method;
+
+ queue_work(efx->workqueue, &efx->reset_work);
+}
+
+/**************************************************************************
+ *
+ * List of NICs we support
+ *
+ **************************************************************************/
+
+/* PCI device ID table */
+static struct pci_device_id efx_pci_table[] __devinitdata = {
+ {PCI_DEVICE(EFX_VENDID_SFC, FALCON_A_P_DEVID),
+ .driver_data = (unsigned long) &falcon_a_nic_type},
+ {PCI_DEVICE(EFX_VENDID_SFC, FALCON_B_P_DEVID),
+ .driver_data = (unsigned long) &falcon_b_nic_type},
+ {0} /* end of list */
+};
+
+/**************************************************************************
+ *
+ * Dummy PHY/MAC/Board operations
+ *
+ * Can be used where the MAC does not implement this operation
+ * Needed so all function pointers are valid and do not have to be tested
+ * before use
+ *
+ **************************************************************************/
+int efx_port_dummy_op_int(struct efx_nic *efx)
+{
+ return 0;
+}
+void efx_port_dummy_op_void(struct efx_nic *efx) {}
+void efx_port_dummy_op_blink(struct efx_nic *efx, int blink) {}
+
+static struct efx_phy_operations efx_dummy_phy_operations = {
+ .init = efx_port_dummy_op_int,
+ .reconfigure = efx_port_dummy_op_void,
+ .check_hw = efx_port_dummy_op_int,
+ .fini = efx_port_dummy_op_void,
+ .clear_interrupt = efx_port_dummy_op_void,
+ .reset_xaui = efx_port_dummy_op_void,
+};
+
+/* Dummy board operations */
+static int efx_nic_dummy_op_int(struct efx_nic *nic)
+{
+ return 0;
+}
+
+static struct efx_board efx_dummy_board_info = {
+ .init = efx_nic_dummy_op_int,
+ .init_leds = efx_port_dummy_op_int,
+ .set_fault_led = efx_port_dummy_op_blink,
+};
+
+/**************************************************************************
+ *
+ * Data housekeeping
+ *
+ **************************************************************************/
+
+/* This zeroes out and then fills in the invariants in a struct
+ * efx_nic (including all sub-structures).
+ */
+static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
+ struct pci_dev *pci_dev, struct net_device *net_dev)
+{
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ int i, rc;
+
+ /* Initialise common structures */
+ memset(efx, 0, sizeof(*efx));
+ spin_lock_init(&efx->biu_lock);
+ spin_lock_init(&efx->phy_lock);
+ INIT_WORK(&efx->reset_work, efx_reset_work);
+ INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
+ efx->pci_dev = pci_dev;
+ efx->state = STATE_INIT;
+ efx->reset_pending = RESET_TYPE_NONE;
+ strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
+ efx->board_info = efx_dummy_board_info;
+
+ efx->net_dev = net_dev;
+ efx->rx_checksum_enabled = 1;
+ spin_lock_init(&efx->netif_stop_lock);
+ spin_lock_init(&efx->stats_lock);
+ mutex_init(&efx->mac_lock);
+ efx->phy_op = &efx_dummy_phy_operations;
+ efx->mii.dev = net_dev;
+ INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work);
+ atomic_set(&efx->netif_stop_count, 1);
+
+ for (i = 0; i < EFX_MAX_CHANNELS; i++) {
+ channel = &efx->channel[i];
+ channel->efx = efx;
+ channel->channel = i;
+ channel->evqnum = i;
+ channel->work_pending = 0;
+ }
+ for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
+ tx_queue = &efx->tx_queue[i];
+ tx_queue->efx = efx;
+ tx_queue->queue = i;
+ tx_queue->buffer = NULL;
+ tx_queue->channel = &efx->channel[0]; /* for safety */
+ }
+ for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
+ rx_queue = &efx->rx_queue[i];
+ rx_queue->efx = efx;
+ rx_queue->queue = i;
+ rx_queue->channel = &efx->channel[0]; /* for safety */
+ rx_queue->buffer = NULL;
+ spin_lock_init(&rx_queue->add_lock);
+ INIT_DELAYED_WORK(&rx_queue->work, efx_rx_work);
+ }
+
+ efx->type = type;
+
+ /* Sanity-check NIC type */
+ EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask &
+ (efx->type->txd_ring_mask + 1));
+ EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask &
+ (efx->type->rxd_ring_mask + 1));
+ EFX_BUG_ON_PARANOID(efx->type->evq_size &
+ (efx->type->evq_size - 1));
+ /* As close as we can get to guaranteeing that we don't overflow */
+ EFX_BUG_ON_PARANOID(efx->type->evq_size <
+ (efx->type->txd_ring_mask + 1 +
+ efx->type->rxd_ring_mask + 1));
+ EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS);
+
+ /* Higher numbered interrupt modes are less capable! */
+ efx->interrupt_mode = max(efx->type->max_interrupt_mode,
+ interrupt_mode);
+
+ efx->workqueue = create_singlethread_workqueue("sfc_work");
+ if (!efx->workqueue) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ return 0;
+
+ fail1:
+ return rc;
+}
+
+static void efx_fini_struct(struct efx_nic *efx)
+{
+ if (efx->workqueue) {
+ destroy_workqueue(efx->workqueue);
+ efx->workqueue = NULL;
+ }
+}
+
+/**************************************************************************
+ *
+ * PCI interface
+ *
+ **************************************************************************/
+
+/* Main body of final NIC shutdown code
+ * This is called only at module unload (or hotplug removal).
+ */
+static void efx_pci_remove_main(struct efx_nic *efx)
+{
+ EFX_ASSERT_RESET_SERIALISED(efx);
+
+ /* Skip everything if we never obtained a valid membase */
+ if (!efx->membase)
+ return;
+
+ efx_fini_channels(efx);
+ efx_fini_port(efx);
+
+ /* Shutdown the board, then the NIC and board state */
+ falcon_fini_interrupt(efx);
+
+ efx_fini_napi(efx);
+ efx_remove_all(efx);
+}
+
+/* Final NIC shutdown
+ * This is called only at module unload (or hotplug removal).
+ */
+static void efx_pci_remove(struct pci_dev *pci_dev)
+{
+ struct efx_nic *efx;
+
+ efx = pci_get_drvdata(pci_dev);
+ if (!efx)
+ return;
+
+ /* Mark the NIC as fini, then stop the interface */
+ rtnl_lock();
+ efx->state = STATE_FINI;
+ dev_close(efx->net_dev);
+
+ /* Allow any queued efx_resets() to complete */
+ rtnl_unlock();
+
+ if (efx->membase == NULL)
+ goto out;
+
+ efx_unregister_netdev(efx);
+
+ /* Wait for any scheduled resets to complete. No more will be
+ * scheduled from this point because efx_stop_all() has been
+ * called, we are no longer registered with driverlink, and
+ * the net_device's have been removed. */
+ flush_workqueue(efx->workqueue);
+
+ efx_pci_remove_main(efx);
+
+out:
+ efx_fini_io(efx);
+ EFX_LOG(efx, "shutdown successful\n");
+
+ pci_set_drvdata(pci_dev, NULL);
+ efx_fini_struct(efx);
+ free_netdev(efx->net_dev);
+};
+
+/* Main body of NIC initialisation
+ * This is called at module load (or hotplug insertion, theoretically).
+ */
+static int efx_pci_probe_main(struct efx_nic *efx)
+{
+ int rc;
+
+ /* Do start-of-day initialisation */
+ rc = efx_probe_all(efx);
+ if (rc)
+ goto fail1;
+
+ rc = efx_init_napi(efx);
+ if (rc)
+ goto fail2;
+
+ /* Initialise the board */
+ rc = efx->board_info.init(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise board\n");
+ goto fail3;
+ }
+
+ rc = falcon_init_nic(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise NIC\n");
+ goto fail4;
+ }
+
+ rc = efx_init_port(efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to initialise port\n");
+ goto fail5;
+ }
+
+ rc = efx_init_channels(efx);
+ if (rc)
+ goto fail6;
+
+ rc = falcon_init_interrupt(efx);
+ if (rc)
+ goto fail7;
+
+ return 0;
+
+ fail7:
+ efx_fini_channels(efx);
+ fail6:
+ efx_fini_port(efx);
+ fail5:
+ fail4:
+ fail3:
+ efx_fini_napi(efx);
+ fail2:
+ efx_remove_all(efx);
+ fail1:
+ return rc;
+}
+
+/* NIC initialisation
+ *
+ * This is called at module load (or hotplug insertion,
+ * theoretically). It sets up PCI mappings, tests and resets the NIC,
+ * sets up and registers the network devices with the kernel and hooks
+ * the interrupt service routine. It does not prepare the device for
+ * transmission; this is left to the first time one of the network
+ * interfaces is brought up (i.e. efx_net_open).
+ */
+static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *entry)
+{
+ struct efx_nic_type *type = (struct efx_nic_type *) entry->driver_data;
+ struct net_device *net_dev;
+ struct efx_nic *efx;
+ int i, rc;
+
+ /* Allocate and initialise a struct net_device and struct efx_nic */
+ net_dev = alloc_etherdev(sizeof(*efx));
+ if (!net_dev)
+ return -ENOMEM;
+ net_dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA;
+ if (lro)
+ net_dev->features |= NETIF_F_LRO;
+ efx = net_dev->priv;
+ pci_set_drvdata(pci_dev, efx);
+ rc = efx_init_struct(efx, type, pci_dev, net_dev);
+ if (rc)
+ goto fail1;
+
+ EFX_INFO(efx, "Solarflare Communications NIC detected\n");
+
+ /* Set up basic I/O (BAR mappings etc) */
+ rc = efx_init_io(efx);
+ if (rc)
+ goto fail2;
+
+ /* No serialisation is required with the reset path because
+ * we're in STATE_INIT. */
+ for (i = 0; i < 5; i++) {
+ rc = efx_pci_probe_main(efx);
+ if (rc == 0)
+ break;
+
+ /* Serialise against efx_reset(). No more resets will be
+ * scheduled since efx_stop_all() has been called, and we
+ * have not and never have been registered with either
+ * the rtnetlink or driverlink layers. */
+ cancel_work_sync(&efx->reset_work);
+
+ /* Retry if a recoverably reset event has been scheduled */
+ if ((efx->reset_pending != RESET_TYPE_INVISIBLE) &&
+ (efx->reset_pending != RESET_TYPE_ALL))
+ goto fail3;
+
+ efx->reset_pending = RESET_TYPE_NONE;
+ }
+
+ if (rc) {
+ EFX_ERR(efx, "Could not reset NIC\n");
+ goto fail4;
+ }
+
+ /* Switch to the running state before we expose the device to
+ * the OS. This is to ensure that the initial gathering of
+ * MAC stats succeeds. */
+ rtnl_lock();
+ efx->state = STATE_RUNNING;
+ rtnl_unlock();
+
+ rc = efx_register_netdev(efx);
+ if (rc)
+ goto fail5;
+
+ EFX_LOG(efx, "initialisation successful\n");
+
+ return 0;
+
+ fail5:
+ efx_pci_remove_main(efx);
+ fail4:
+ fail3:
+ efx_fini_io(efx);
+ fail2:
+ efx_fini_struct(efx);
+ fail1:
+ EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
+ free_netdev(net_dev);
+ return rc;
+}
+
+static struct pci_driver efx_pci_driver = {
+ .name = EFX_DRIVER_NAME,
+ .id_table = efx_pci_table,
+ .probe = efx_pci_probe,
+ .remove = efx_pci_remove,
+};
+
+/**************************************************************************
+ *
+ * Kernel module interface
+ *
+ *************************************************************************/
+
+module_param(interrupt_mode, uint, 0444);
+MODULE_PARM_DESC(interrupt_mode,
+ "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)");
+
+static int __init efx_init_module(void)
+{
+ int rc;
+
+ printk(KERN_INFO "Solarflare NET driver v" EFX_DRIVER_VERSION "\n");
+
+ rc = register_netdevice_notifier(&efx_netdev_notifier);
+ if (rc)
+ goto err_notifier;
+
+ refill_workqueue = create_workqueue("sfc_refill");
+ if (!refill_workqueue) {
+ rc = -ENOMEM;
+ goto err_refill;
+ }
+
+ rc = pci_register_driver(&efx_pci_driver);
+ if (rc < 0)
+ goto err_pci;
+
+ return 0;
+
+ err_pci:
+ destroy_workqueue(refill_workqueue);
+ err_refill:
+ unregister_netdevice_notifier(&efx_netdev_notifier);
+ err_notifier:
+ return rc;
+}
+
+static void __exit efx_exit_module(void)
+{
+ printk(KERN_INFO "Solarflare NET driver unloading\n");
+
+ pci_unregister_driver(&efx_pci_driver);
+ destroy_workqueue(refill_workqueue);
+ unregister_netdevice_notifier(&efx_netdev_notifier);
+
+}
+
+module_init(efx_init_module);
+module_exit(efx_exit_module);
+
+MODULE_AUTHOR("Michael Brown <mbrown@fensystems.co.uk> and "
+ "Solarflare Communications");
+MODULE_DESCRIPTION("Solarflare Communications network driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, efx_pci_table);
diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h
new file mode 100644
index 0000000..3b2f69f
--- /dev/null
+++ b/drivers/net/sfc/efx.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_EFX_H
+#define EFX_EFX_H
+
+#include "net_driver.h"
+
+/* PCI IDs */
+#define EFX_VENDID_SFC 0x1924
+#define FALCON_A_P_DEVID 0x0703
+#define FALCON_A_S_DEVID 0x6703
+#define FALCON_B_P_DEVID 0x0710
+
+/* TX */
+extern int efx_xmit(struct efx_nic *efx,
+ struct efx_tx_queue *tx_queue, struct sk_buff *skb);
+extern void efx_stop_queue(struct efx_nic *efx);
+extern void efx_wake_queue(struct efx_nic *efx);
+
+/* RX */
+extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
+extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
+ unsigned int len, int checksummed, int discard);
+extern void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue, int delay);
+
+/* Channels */
+extern void efx_process_channel_now(struct efx_channel *channel);
+extern int efx_flush_queues(struct efx_nic *efx);
+
+/* Ports */
+extern void efx_reconfigure_port(struct efx_nic *efx);
+
+/* Global */
+extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
+extern void efx_suspend(struct efx_nic *efx);
+extern void efx_resume(struct efx_nic *efx);
+extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
+ int rx_usecs);
+extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
+extern void efx_hex_dump(const u8 *, unsigned int, const char *);
+
+/* Dummy PHY ops for PHY drivers */
+extern int efx_port_dummy_op_int(struct efx_nic *efx);
+extern void efx_port_dummy_op_void(struct efx_nic *efx);
+extern void efx_port_dummy_op_blink(struct efx_nic *efx, int blink);
+
+
+extern unsigned int efx_monitor_interval;
+
+static inline void efx_schedule_channel(struct efx_channel *channel)
+{
+ EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n",
+ channel->channel, raw_smp_processor_id());
+ channel->work_pending = 1;
+
+ netif_rx_schedule(channel->napi_dev, &channel->napi_str);
+}
+
+#endif /* EFX_EFX_H */
diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h
new file mode 100644
index 0000000..43663a4
--- /dev/null
+++ b/drivers/net/sfc/enum.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_ENUM_H
+#define EFX_ENUM_H
+
+/*****************************************************************************/
+
+/**
+ * enum reset_type - reset types
+ *
+ * %RESET_TYPE_INVSIBLE, %RESET_TYPE_ALL, %RESET_TYPE_WORLD and
+ * %RESET_TYPE_DISABLE specify the method/scope of the reset. The
+ * other valuesspecify reasons, which efx_schedule_reset() will choose
+ * a method for.
+ *
+ * @RESET_TYPE_INVISIBLE: don't reset the PHYs or interrupts
+ * @RESET_TYPE_ALL: reset everything but PCI core blocks
+ * @RESET_TYPE_WORLD: reset everything, save & restore PCI config
+ * @RESET_TYPE_DISABLE: disable NIC
+ * @RESET_TYPE_MONITOR: reset due to hardware monitor
+ * @RESET_TYPE_INT_ERROR: reset due to internal error
+ * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors
+ * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch
+ * @RESET_TYPE_TX_DESC_FETCH: pcie error during tx descriptor fetch
+ * @RESET_TYPE_TX_SKIP: hardware completed empty tx descriptors
+ */
+enum reset_type {
+ RESET_TYPE_NONE = -1,
+ RESET_TYPE_INVISIBLE = 0,
+ RESET_TYPE_ALL = 1,
+ RESET_TYPE_WORLD = 2,
+ RESET_TYPE_DISABLE = 3,
+ RESET_TYPE_MAX_METHOD,
+ RESET_TYPE_MONITOR,
+ RESET_TYPE_INT_ERROR,
+ RESET_TYPE_RX_RECOVERY,
+ RESET_TYPE_RX_DESC_FETCH,
+ RESET_TYPE_TX_DESC_FETCH,
+ RESET_TYPE_TX_SKIP,
+ RESET_TYPE_MAX,
+};
+
+#endif /* EFX_ENUM_H */
diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c
new file mode 100644
index 0000000..ad541ba
--- /dev/null
+++ b/drivers/net/sfc/ethtool.c
@@ -0,0 +1,460 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+#include "net_driver.h"
+#include "efx.h"
+#include "ethtool.h"
+#include "falcon.h"
+#include "gmii.h"
+#include "mac.h"
+
+static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
+
+struct ethtool_string {
+ char name[ETH_GSTRING_LEN];
+};
+
+struct efx_ethtool_stat {
+ const char *name;
+ enum {
+ EFX_ETHTOOL_STAT_SOURCE_mac_stats,
+ EFX_ETHTOOL_STAT_SOURCE_nic,
+ EFX_ETHTOOL_STAT_SOURCE_channel
+ } source;
+ unsigned offset;
+ u64(*get_stat) (void *field); /* Reader function */
+};
+
+/* Initialiser for a struct #efx_ethtool_stat with type-checking */
+#define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \
+ get_stat_function) { \
+ .name = #stat_name, \
+ .source = EFX_ETHTOOL_STAT_SOURCE_##source_name, \
+ .offset = ((((field_type *) 0) == \
+ &((struct efx_##source_name *)0)->field) ? \
+ offsetof(struct efx_##source_name, field) : \
+ offsetof(struct efx_##source_name, field)), \
+ .get_stat = get_stat_function, \
+}
+
+static u64 efx_get_uint_stat(void *field)
+{
+ return *(unsigned int *)field;
+}
+
+static u64 efx_get_ulong_stat(void *field)
+{
+ return *(unsigned long *)field;
+}
+
+static u64 efx_get_u64_stat(void *field)
+{
+ return *(u64 *) field;
+}
+
+static u64 efx_get_atomic_stat(void *field)
+{
+ return atomic_read((atomic_t *) field);
+}
+
+#define EFX_ETHTOOL_ULONG_MAC_STAT(field) \
+ EFX_ETHTOOL_STAT(field, mac_stats, field, \
+ unsigned long, efx_get_ulong_stat)
+
+#define EFX_ETHTOOL_U64_MAC_STAT(field) \
+ EFX_ETHTOOL_STAT(field, mac_stats, field, \
+ u64, efx_get_u64_stat)
+
+#define EFX_ETHTOOL_UINT_NIC_STAT(name) \
+ EFX_ETHTOOL_STAT(name, nic, n_##name, \
+ unsigned int, efx_get_uint_stat)
+
+#define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field) \
+ EFX_ETHTOOL_STAT(field, nic, field, \
+ atomic_t, efx_get_atomic_stat)
+
+#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field) \
+ EFX_ETHTOOL_STAT(field, channel, n_##field, \
+ unsigned int, efx_get_uint_stat)
+
+static struct efx_ethtool_stat efx_ethtool_stats[] = {
+ EFX_ETHTOOL_U64_MAC_STAT(tx_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_packets),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_bad),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_pause),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_control),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_unicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_multicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_broadcast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_lt64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_65_to_127),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_128_to_255),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_256_to_511),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_512_to_1023),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_1024_to_15xx),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_15xx_to_jumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_gtjumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_single_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_multiple_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_deferred),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_late_collision),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_deferred),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_non_tcpudp),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_mac_src_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(tx_ip_src_error),
+ EFX_ETHTOOL_U64_MAC_STAT(rx_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes),
+ EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_packets),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_good),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_pause),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_control),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_unicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_multicast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_broadcast),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_lt64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_65_to_127),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_128_to_255),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_256_to_511),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_512_to_1023),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_1024_to_15xx),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_15xx_to_jumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_gtjumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_lt64),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_64_to_15xx),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_15xx_to_jumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_gtjumbo),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_overflow),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_missed),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_false_carrier),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_symbol_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_align_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_length_error),
+ EFX_ETHTOOL_ULONG_MAC_STAT(rx_internal_error),
+ EFX_ETHTOOL_UINT_NIC_STAT(rx_nodesc_drop_cnt),
+ EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
+ EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
+};
+
+/* Number of ethtool statistics */
+#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
+
+/**************************************************************************
+ *
+ * Ethtool operations
+ *
+ **************************************************************************
+ */
+
+/* Identify device by flashing LEDs */
+static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ efx->board_info.blink(efx, 1);
+ schedule_timeout_interruptible(seconds * HZ);
+ efx->board_info.blink(efx, 0);
+ return 0;
+}
+
+/* This must be called with rtnl_lock held. */
+int efx_ethtool_get_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ mutex_lock(&efx->mac_lock);
+ rc = falcon_xmac_get_settings(efx, ecmd);
+ mutex_unlock(&efx->mac_lock);
+
+ return rc;
+}
+
+/* This must be called with rtnl_lock held. */
+int efx_ethtool_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ mutex_lock(&efx->mac_lock);
+ rc = falcon_xmac_set_settings(efx, ecmd);
+ mutex_unlock(&efx->mac_lock);
+ if (!rc)
+ efx_reconfigure_port(efx);
+
+ return rc;
+}
+
+static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
+ struct ethtool_drvinfo *info)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
+ strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
+ strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
+}
+
+static int efx_ethtool_get_stats_count(struct net_device *net_dev)
+{
+ return EFX_ETHTOOL_NUM_STATS;
+}
+
+static void efx_ethtool_get_strings(struct net_device *net_dev,
+ u32 string_set, u8 *strings)
+{
+ struct ethtool_string *ethtool_strings =
+ (struct ethtool_string *)strings;
+ int i;
+
+ if (string_set == ETH_SS_STATS)
+ for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++)
+ strncpy(ethtool_strings[i].name,
+ efx_ethtool_stats[i].name,
+ sizeof(ethtool_strings[i].name));
+}
+
+static void efx_ethtool_get_stats(struct net_device *net_dev,
+ struct ethtool_stats *stats,
+ u64 *data)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_mac_stats *mac_stats = &efx->mac_stats;
+ struct efx_ethtool_stat *stat;
+ struct efx_channel *channel;
+ int i;
+
+ EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
+
+ /* Update MAC and NIC statistics */
+ net_dev->get_stats(net_dev);
+
+ /* Fill detailed statistics buffer */
+ for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
+ stat = &efx_ethtool_stats[i];
+ switch (stat->source) {
+ case EFX_ETHTOOL_STAT_SOURCE_mac_stats:
+ data[i] = stat->get_stat((void *)mac_stats +
+ stat->offset);
+ break;
+ case EFX_ETHTOOL_STAT_SOURCE_nic:
+ data[i] = stat->get_stat((void *)efx + stat->offset);
+ break;
+ case EFX_ETHTOOL_STAT_SOURCE_channel:
+ data[i] = 0;
+ efx_for_each_channel(channel, efx)
+ data[i] += stat->get_stat((void *)channel +
+ stat->offset);
+ break;
+ }
+ }
+}
+
+static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
+{
+ struct efx_nic *efx = net_dev->priv;
+ int rc;
+
+ rc = ethtool_op_set_tx_csum(net_dev, enable);
+ if (rc)
+ return rc;
+
+ efx_flush_queues(efx);
+
+ return 0;
+}
+
+static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ /* No way to stop the hardware doing the checks; we just
+ * ignore the result.
+ */
+ efx->rx_checksum_enabled = (enable ? 1 : 0);
+
+ return 0;
+}
+
+static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return efx->rx_checksum_enabled;
+}
+
+/* Restart autonegotiation */
+static int efx_ethtool_nway_reset(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return mii_nway_restart(&efx->mii);
+}
+
+static u32 efx_ethtool_get_link(struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ return efx->link_up;
+}
+
+static int efx_ethtool_get_coalesce(struct net_device *net_dev,
+ struct ethtool_coalesce *coalesce)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_tx_queue *tx_queue;
+ struct efx_rx_queue *rx_queue;
+ struct efx_channel *channel;
+
+ memset(coalesce, 0, sizeof(*coalesce));
+
+ /* Find lowest IRQ moderation across all used TX queues */
+ coalesce->tx_coalesce_usecs_irq = ~((u32) 0);
+ efx_for_each_tx_queue(tx_queue, efx) {
+ channel = tx_queue->channel;
+ if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
+ if (channel->used_flags != EFX_USED_BY_RX_TX)
+ coalesce->tx_coalesce_usecs_irq =
+ channel->irq_moderation;
+ else
+ coalesce->tx_coalesce_usecs_irq = 0;
+ }
+ }
+
+ /* Find lowest IRQ moderation across all used RX queues */
+ coalesce->rx_coalesce_usecs_irq = ~((u32) 0);
+ efx_for_each_rx_queue(rx_queue, efx) {
+ channel = rx_queue->channel;
+ if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
+ coalesce->rx_coalesce_usecs_irq =
+ channel->irq_moderation;
+ }
+
+ return 0;
+}
+
+/* Set coalescing parameters
+ * The difficulties occur for shared channels
+ */
+static int efx_ethtool_set_coalesce(struct net_device *net_dev,
+ struct ethtool_coalesce *coalesce)
+{
+ struct efx_nic *efx = net_dev->priv;
+ struct efx_channel *channel;
+ struct efx_tx_queue *tx_queue;
+ unsigned tx_usecs, rx_usecs;
+
+ if (coalesce->use_adaptive_rx_coalesce ||
+ coalesce->use_adaptive_tx_coalesce)
+ return -EOPNOTSUPP;
+
+ if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
+ EFX_ERR(efx, "invalid coalescing setting. "
+ "Only rx/tx_coalesce_usecs_irq are supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ rx_usecs = coalesce->rx_coalesce_usecs_irq;
+ tx_usecs = coalesce->tx_coalesce_usecs_irq;
+
+ /* If the channel is shared only allow RX parameters to be set */
+ efx_for_each_tx_queue(tx_queue, efx) {
+ if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) &&
+ tx_usecs) {
+ EFX_ERR(efx, "Channel is shared. "
+ "Only RX coalescing may be set\n");
+ return -EOPNOTSUPP;
+ }
+ }
+
+ efx_init_irq_moderation(efx, tx_usecs, rx_usecs);
+
+ /* Reset channel to pick up new moderation value. Note that
+ * this may change the value of the irq_moderation field
+ * (e.g. to allow for hardware timer granularity).
+ */
+ efx_for_each_channel(channel, efx)
+ falcon_set_int_moderation(channel);
+
+ return 0;
+}
+
+static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct efx_nic *efx = net_dev->priv;
+ enum efx_fc_type flow_control = efx->flow_control;
+ int rc;
+
+ flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
+ flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
+ flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
+ flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
+
+ /* Try to push the pause parameters */
+ mutex_lock(&efx->mac_lock);
+ rc = falcon_xmac_set_pause(efx, flow_control);
+ mutex_unlock(&efx->mac_lock);
+
+ if (!rc)
+ efx_reconfigure_port(efx);
+
+ return rc;
+}
+
+static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
+ struct ethtool_pauseparam *pause)
+{
+ struct efx_nic *efx = net_dev->priv;
+
+ pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
+ pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
+ pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0;
+}
+
+
+struct ethtool_ops efx_ethtool_ops = {
+ .get_settings = efx_ethtool_get_settings,
+ .set_settings = efx_ethtool_set_settings,
+ .get_drvinfo = efx_ethtool_get_drvinfo,
+ .nway_reset = efx_ethtool_nway_reset,
+ .get_link = efx_ethtool_get_link,
+ .get_coalesce = efx_ethtool_get_coalesce,
+ .set_coalesce = efx_ethtool_set_coalesce,
+ .get_pauseparam = efx_ethtool_get_pauseparam,
+ .set_pauseparam = efx_ethtool_set_pauseparam,
+ .get_rx_csum = efx_ethtool_get_rx_csum,
+ .set_rx_csum = efx_ethtool_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = efx_ethtool_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = ethtool_op_set_flags,
+ .get_strings = efx_ethtool_get_strings,
+ .phys_id = efx_ethtool_phys_id,
+ .get_stats_count = efx_ethtool_get_stats_count,
+ .get_ethtool_stats = efx_ethtool_get_stats,
+};
diff --git a/drivers/net/sfc/ethtool.h b/drivers/net/sfc/ethtool.h
new file mode 100644
index 0000000..3628e43
--- /dev/null
+++ b/drivers/net/sfc/ethtool.h
@@ -0,0 +1,27 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_ETHTOOL_H
+#define EFX_ETHTOOL_H
+
+#include "net_driver.h"
+
+/*
+ * Ethtool support
+ */
+
+extern int efx_ethtool_get_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd);
+extern int efx_ethtool_set_settings(struct net_device *net_dev,
+ struct ethtool_cmd *ecmd);
+
+extern struct ethtool_ops efx_ethtool_ops;
+
+#endif /* EFX_ETHTOOL_H */
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c
new file mode 100644
index 0000000..46db549
--- /dev/null
+++ b/drivers/net/sfc/falcon.c
@@ -0,0 +1,2722 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include "net_driver.h"
+#include "bitfield.h"
+#include "efx.h"
+#include "mac.h"
+#include "gmii.h"
+#include "spi.h"
+#include "falcon.h"
+#include "falcon_hwdefs.h"
+#include "falcon_io.h"
+#include "mdio_10g.h"
+#include "phy.h"
+#include "boards.h"
+#include "workarounds.h"
+
+/* Falcon hardware control.
+ * Falcon is the internal codename for the SFC4000 controller that is
+ * present in SFE400X evaluation boards
+ */
+
+/**
+ * struct falcon_nic_data - Falcon NIC state
+ * @next_buffer_table: First available buffer table id
+ * @pci_dev2: The secondary PCI device if present
+ */
+struct falcon_nic_data {
+ unsigned next_buffer_table;
+ struct pci_dev *pci_dev2;
+};
+
+/**************************************************************************
+ *
+ * Configurable values
+ *
+ **************************************************************************
+ */
+
+static int disable_dma_stats;
+
+/* This is set to 16 for a good reason. In summary, if larger than
+ * 16, the descriptor cache holds more than a default socket
+ * buffer's worth of packets (for UDP we can only have at most one
+ * socket buffer's worth outstanding). This combined with the fact
+ * that we only get 1 TX event per descriptor cache means the NIC
+ * goes idle.
+ */
+#define TX_DC_ENTRIES 16
+#define TX_DC_ENTRIES_ORDER 0
+#define TX_DC_BASE 0x130000
+
+#define RX_DC_ENTRIES 64
+#define RX_DC_ENTRIES_ORDER 2
+#define RX_DC_BASE 0x100000
+
+/* RX FIFO XOFF watermark
+ *
+ * When the amount of the RX FIFO increases used increases past this
+ * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A)
+ * This also has an effect on RX/TX arbitration
+ */
+static int rx_xoff_thresh_bytes = -1;
+module_param(rx_xoff_thresh_bytes, int, 0644);
+MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold");
+
+/* RX FIFO XON watermark
+ *
+ * When the amount of the RX FIFO used decreases below this
+ * watermark send XON. Only used if TX flow control is enabled (ethtool -A)
+ * This also has an effect on RX/TX arbitration
+ */
+static int rx_xon_thresh_bytes = -1;
+module_param(rx_xon_thresh_bytes, int, 0644);
+MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
+
+/* TX descriptor ring size - min 512 max 4k */
+#define FALCON_TXD_RING_ORDER TX_DESCQ_SIZE_1K
+#define FALCON_TXD_RING_SIZE 1024
+#define FALCON_TXD_RING_MASK (FALCON_TXD_RING_SIZE - 1)
+
+/* RX descriptor ring size - min 512 max 4k */
+#define FALCON_RXD_RING_ORDER RX_DESCQ_SIZE_1K
+#define FALCON_RXD_RING_SIZE 1024
+#define FALCON_RXD_RING_MASK (FALCON_RXD_RING_SIZE - 1)
+
+/* Event queue size - max 32k */
+#define FALCON_EVQ_ORDER EVQ_SIZE_4K
+#define FALCON_EVQ_SIZE 4096
+#define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1)
+
+/* Max number of internal errors. After this resets will not be performed */
+#define FALCON_MAX_INT_ERRORS 4
+
+/* Maximum period that we wait for flush events. If the flush event
+ * doesn't arrive in this period of time then we check if the queue
+ * was disabled anyway. */
+#define FALCON_FLUSH_TIMEOUT 10 /* 10ms */
+
+/**************************************************************************
+ *
+ * Falcon constants
+ *
+ **************************************************************************
+ */
+
+/* DMA address mask (up to 46-bit, avoiding compiler warnings)
+ *
+ * Note that it is possible to have a platform with 64-bit longs and
+ * 32-bit DMA addresses, or vice versa. EFX_DMA_MASK takes care of the
+ * platform DMA mask.
+ */
+#if BITS_PER_LONG == 64
+#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffUL)
+#else
+#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffULL)
+#endif
+
+/* TX DMA length mask (13-bit) */
+#define FALCON_TX_DMA_MASK (4096 - 1)
+
+/* Size and alignment of special buffers (4KB) */
+#define FALCON_BUF_SIZE 4096
+
+/* Dummy SRAM size code */
+#define SRM_NB_BSZ_ONCHIP_ONLY (-1)
+
+/* Be nice if these (or equiv.) were in linux/pci_regs.h, but they're not. */
+#define PCI_EXP_DEVCAP_PWR_VAL_LBN 18
+#define PCI_EXP_DEVCAP_PWR_SCL_LBN 26
+#define PCI_EXP_DEVCTL_PAYLOAD_LBN 5
+#define PCI_EXP_LNKSTA_LNK_WID 0x3f0
+#define PCI_EXP_LNKSTA_LNK_WID_LBN 4
+
+#define FALCON_IS_DUAL_FUNC(efx) \
+ (FALCON_REV(efx) < FALCON_REV_B0)
+
+/**************************************************************************
+ *
+ * Falcon hardware access
+ *
+ **************************************************************************/
+
+/* Read the current event from the event queue */
+static inline efx_qword_t *falcon_event(struct efx_channel *channel,
+ unsigned int index)
+{
+ return (((efx_qword_t *) (channel->eventq.addr)) + index);
+}
+
+/* See if an event is present
+ *
+ * We check both the high and low dword of the event for all ones. We
+ * wrote all ones when we cleared the event, and no valid event can
+ * have all ones in either its high or low dwords. This approach is
+ * robust against reordering.
+ *
+ * Note that using a single 64-bit comparison is incorrect; even
+ * though the CPU read will be atomic, the DMA write may not be.
+ */
+static inline int falcon_event_present(efx_qword_t *event)
+{
+ return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
+ EFX_DWORD_IS_ALL_ONES(event->dword[1])));
+}
+
+/**************************************************************************
+ *
+ * I2C bus - this is a bit-bashing interface using GPIO pins
+ * Note that it uses the output enables to tristate the outputs
+ * SDA is the data pin and SCL is the clock
+ *
+ **************************************************************************
+ */
+static void falcon_setsdascl(struct efx_i2c_interface *i2c)
+{
+ efx_oword_t reg;
+
+ falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1));
+ EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1));
+ falcon_write(i2c->efx, ®, GPIO_CTL_REG_KER);
+}
+
+static int falcon_getsda(struct efx_i2c_interface *i2c)
+{
+ efx_oword_t reg;
+
+ falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
+ return EFX_OWORD_FIELD(reg, GPIO3_IN);
+}
+
+static int falcon_getscl(struct efx_i2c_interface *i2c)
+{
+ efx_oword_t reg;
+
+ falcon_read(i2c->efx, ®, GPIO_CTL_REG_KER);
+ return EFX_DWORD_FIELD(reg, GPIO0_IN);
+}
+
+static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
+ .setsda = falcon_setsdascl,
+ .setscl = falcon_setsdascl,
+ .getsda = falcon_getsda,
+ .getscl = falcon_getscl,
+ .udelay = 100,
+ .mdelay = 10,
+};
+
+/**************************************************************************
+ *
+ * Falcon special buffer handling
+ * Special buffers are used for event queues and the TX and RX
+ * descriptor rings.
+ *
+ *************************************************************************/
+
+/*
+ * Initialise a Falcon special buffer
+ *
+ * This will define a buffer (previously allocated via
+ * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing
+ * it to be used for event queues, descriptor rings etc.
+ */
+static int
+falcon_init_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer)
+{
+ efx_qword_t buf_desc;
+ int index;
+ dma_addr_t dma_addr;
+ int i;
+
+ EFX_BUG_ON_PARANOID(!buffer->addr);
+
+ /* Write buffer descriptors to NIC */
+ for (i = 0; i < buffer->entries; i++) {
+ index = buffer->index + i;
+ dma_addr = buffer->dma_addr + (i * 4096);
+ EFX_LOG(efx, "mapping special buffer %d at %llx\n",
+ index, (unsigned long long)dma_addr);
+ EFX_POPULATE_QWORD_4(buf_desc,
+ IP_DAT_BUF_SIZE, IP_DAT_BUF_SIZE_4K,
+ BUF_ADR_REGION, 0,
+ BUF_ADR_FBUF, (dma_addr >> 12),
+ BUF_OWNER_ID_FBUF, 0);
+ falcon_write_sram(efx, &buf_desc, index);
+ }
+
+ return 0;
+}
+
+/* Unmaps a buffer from Falcon and clears the buffer table entries */
+static void
+falcon_fini_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer)
+{
+ efx_oword_t buf_tbl_upd;
+ unsigned int start = buffer->index;
+ unsigned int end = (buffer->index + buffer->entries - 1);
+
+ if (!buffer->entries)
+ return;
+
+ EFX_LOG(efx, "unmapping special buffers %d-%d\n",
+ buffer->index, buffer->index + buffer->entries - 1);
+
+ EFX_POPULATE_OWORD_4(buf_tbl_upd,
+ BUF_UPD_CMD, 0,
+ BUF_CLR_CMD, 1,
+ BUF_CLR_END_ID, end,
+ BUF_CLR_START_ID, start);
+ falcon_write(efx, &buf_tbl_upd, BUF_TBL_UPD_REG_KER);
+}
+
+/*
+ * Allocate a new Falcon special buffer
+ *
+ * This allocates memory for a new buffer, clears it and allocates a
+ * new buffer ID range. It does not write into Falcon's buffer table.
+ *
+ * This call will allocate 4KB buffers, since Falcon can't use 8KB
+ * buffers for event queues and descriptor rings.
+ */
+static int falcon_alloc_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer,
+ unsigned int len)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ len = ALIGN(len, FALCON_BUF_SIZE);
+
+ buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
+ &buffer->dma_addr);
+ if (!buffer->addr)
+ return -ENOMEM;
+ buffer->len = len;
+ buffer->entries = len / FALCON_BUF_SIZE;
+ BUG_ON(buffer->dma_addr & (FALCON_BUF_SIZE - 1));
+
+ /* All zeros is a potentially valid event so memset to 0xff */
+ memset(buffer->addr, 0xff, len);
+
+ /* Select new buffer ID */
+ buffer->index = nic_data->next_buffer_table;
+ nic_data->next_buffer_table += buffer->entries;
+
+ EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x "
+ "(virt %p phys %lx)\n", buffer->index,
+ buffer->index + buffer->entries - 1,
+ (unsigned long long)buffer->dma_addr, len,
+ buffer->addr, virt_to_phys(buffer->addr));
+
+ return 0;
+}
+
+static void falcon_free_special_buffer(struct efx_nic *efx,
+ struct efx_special_buffer *buffer)
+{
+ if (!buffer->addr)
+ return;
+
+ EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x "
+ "(virt %p phys %lx)\n", buffer->index,
+ buffer->index + buffer->entries - 1,
+ (unsigned long long)buffer->dma_addr, buffer->len,
+ buffer->addr, virt_to_phys(buffer->addr));
+
+ pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
+ buffer->dma_addr);
+ buffer->addr = NULL;
+ buffer->entries = 0;
+}
+
+/**************************************************************************
+ *
+ * Falcon generic buffer handling
+ * These buffers are used for interrupt status and MAC stats
+ *
+ **************************************************************************/
+
+static int falcon_alloc_buffer(struct efx_nic *efx,
+ struct efx_buffer *buffer, unsigned int len)
+{
+ buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
+ &buffer->dma_addr);
+ if (!buffer->addr)
+ return -ENOMEM;
+ buffer->len = len;
+ memset(buffer->addr, 0, len);
+ return 0;
+}
+
+static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer)
+{
+ if (buffer->addr) {
+ pci_free_consistent(efx->pci_dev, buffer->len,
+ buffer->addr, buffer->dma_addr);
+ buffer->addr = NULL;
+ }
+}
+
+/**************************************************************************
+ *
+ * Falcon TX path
+ *
+ **************************************************************************/
+
+/* Returns a pointer to the specified transmit descriptor in the TX
+ * descriptor queue belonging to the specified channel.
+ */
+static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue,
+ unsigned int index)
+{
+ return (((efx_qword_t *) (tx_queue->txd.addr)) + index);
+}
+
+/* This writes to the TX_DESC_WPTR; write pointer for TX descriptor ring */
+static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue)
+{
+ unsigned write_ptr;
+ efx_dword_t reg;
+
+ write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
+ EFX_POPULATE_DWORD_1(reg, TX_DESC_WPTR_DWORD, write_ptr);
+ falcon_writel_page(tx_queue->efx, ®,
+ TX_DESC_UPD_REG_KER_DWORD, tx_queue->queue);
+}
+
+
+/* For each entry inserted into the software descriptor ring, create a
+ * descriptor in the hardware TX descriptor ring (in host memory), and
+ * write a doorbell.
+ */
+void falcon_push_buffers(struct efx_tx_queue *tx_queue)
+{
+
+ struct efx_tx_buffer *buffer;
+ efx_qword_t *txd;
+ unsigned write_ptr;
+
+ BUG_ON(tx_queue->write_count == tx_queue->insert_count);
+
+ do {
+ write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
+ buffer = &tx_queue->buffer[write_ptr];
+ txd = falcon_tx_desc(tx_queue, write_ptr);
+ ++tx_queue->write_count;
+
+ /* Create TX descriptor ring entry */
+ EFX_POPULATE_QWORD_5(*txd,
+ TX_KER_PORT, 0,
+ TX_KER_CONT, buffer->continuation,
+ TX_KER_BYTE_CNT, buffer->len,
+ TX_KER_BUF_REGION, 0,
+ TX_KER_BUF_ADR, buffer->dma_addr);
+ } while (tx_queue->write_count != tx_queue->insert_count);
+
+ wmb(); /* Ensure descriptors are written before they are fetched */
+ falcon_notify_tx_desc(tx_queue);
+}
+
+/* Allocate hardware resources for a TX queue */
+int falcon_probe_tx(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ return falcon_alloc_special_buffer(efx, &tx_queue->txd,
+ FALCON_TXD_RING_SIZE *
+ sizeof(efx_qword_t));
+}
+
+int falcon_init_tx(struct efx_tx_queue *tx_queue)
+{
+ efx_oword_t tx_desc_ptr;
+ struct efx_nic *efx = tx_queue->efx;
+ int rc;
+
+ /* Pin TX descriptor ring */
+ rc = falcon_init_special_buffer(efx, &tx_queue->txd);
+ if (rc)
+ return rc;
+
+ /* Push TX descriptor ring to card */
+ EFX_POPULATE_OWORD_10(tx_desc_ptr,
+ TX_DESCQ_EN, 1,
+ TX_ISCSI_DDIG_EN, 0,
+ TX_ISCSI_HDIG_EN, 0,
+ TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index,
+ TX_DESCQ_EVQ_ID, tx_queue->channel->evqnum,
+ TX_DESCQ_OWNER_ID, 0,
+ TX_DESCQ_LABEL, tx_queue->queue,
+ TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER,
+ TX_DESCQ_TYPE, 0,
+ TX_NON_IP_DROP_DIS_B0, 1);
+
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM);
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum);
+ EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum);
+ }
+
+ falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
+
+ if (FALCON_REV(efx) < FALCON_REV_B0) {
+ efx_oword_t reg;
+
+ BUG_ON(tx_queue->queue >= 128); /* HW limit */
+
+ falcon_read(efx, ®, TX_CHKSM_CFG_REG_KER_A1);
+ if (efx->net_dev->features & NETIF_F_IP_CSUM)
+ clear_bit_le(tx_queue->queue, (void *)®);
+ else
+ set_bit_le(tx_queue->queue, (void *)®);
+ falcon_write(efx, ®, TX_CHKSM_CFG_REG_KER_A1);
+ }
+
+ return 0;
+}
+
+static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ struct efx_channel *channel = &efx->channel[0];
+ efx_oword_t tx_flush_descq;
+ unsigned int read_ptr, i;
+
+ /* Post a flush command */
+ EFX_POPULATE_OWORD_2(tx_flush_descq,
+ TX_FLUSH_DESCQ_CMD, 1,
+ TX_FLUSH_DESCQ, tx_queue->queue);
+ falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER);
+ msleep(FALCON_FLUSH_TIMEOUT);
+
+ if (EFX_WORKAROUND_7803(efx))
+ return 0;
+
+ /* Look for a flush completed event */
+ read_ptr = channel->eventq_read_ptr;
+ for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
+ efx_qword_t *event = falcon_event(channel, read_ptr);
+ int ev_code, ev_sub_code, ev_queue;
+ if (!falcon_event_present(event))
+ break;
+
+ ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
+ ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+ ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_TX_DESCQ_ID);
+ if ((ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) &&
+ (ev_queue == tx_queue->queue)) {
+ EFX_LOG(efx, "tx queue %d flush command succesful\n",
+ tx_queue->queue);
+ return 0;
+ }
+
+ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+ }
+
+ if (EFX_WORKAROUND_11557(efx)) {
+ efx_oword_t reg;
+ int enabled;
+
+ falcon_read_table(efx, ®, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
+ enabled = EFX_OWORD_FIELD(reg, TX_DESCQ_EN);
+ if (!enabled) {
+ EFX_LOG(efx, "tx queue %d disabled without a "
+ "flush event seen\n", tx_queue->queue);
+ return 0;
+ }
+ }
+
+ EFX_ERR(efx, "tx queue %d flush command timed out\n", tx_queue->queue);
+ return -ETIMEDOUT;
+}
+
+void falcon_fini_tx(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ efx_oword_t tx_desc_ptr;
+
+ /* Stop the hardware using the queue */
+ if (falcon_flush_tx_queue(tx_queue))
+ EFX_ERR(efx, "failed to flush tx queue %d\n", tx_queue->queue);
+
+ /* Remove TX descriptor ring from card */
+ EFX_ZERO_OWORD(tx_desc_ptr);
+ falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
+ tx_queue->queue);
+
+ /* Unpin TX descriptor ring */
+ falcon_fini_special_buffer(efx, &tx_queue->txd);
+}
+
+/* Free buffers backing TX queue */
+void falcon_remove_tx(struct efx_tx_queue *tx_queue)
+{
+ falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd);
+}
+
+/**************************************************************************
+ *
+ * Falcon RX path
+ *
+ **************************************************************************/
+
+/* Returns a pointer to the specified descriptor in the RX descriptor queue */
+static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue,
+ unsigned int index)
+{
+ return (((efx_qword_t *) (rx_queue->rxd.addr)) + index);
+}
+
+/* This creates an entry in the RX descriptor queue */
+static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue,
+ unsigned index)
+{
+ struct efx_rx_buffer *rx_buf;
+ efx_qword_t *rxd;
+
+ rxd = falcon_rx_desc(rx_queue, index);
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ EFX_POPULATE_QWORD_3(*rxd,
+ RX_KER_BUF_SIZE,
+ rx_buf->len -
+ rx_queue->efx->type->rx_buffer_padding,
+ RX_KER_BUF_REGION, 0,
+ RX_KER_BUF_ADR, rx_buf->dma_addr);
+}
+
+/* This writes to the RX_DESC_WPTR register for the specified receive
+ * descriptor ring.
+ */
+void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue)
+{
+ efx_dword_t reg;
+ unsigned write_ptr;
+
+ while (rx_queue->notified_count != rx_queue->added_count) {
+ falcon_build_rx_desc(rx_queue,
+ rx_queue->notified_count &
+ FALCON_RXD_RING_MASK);
+ ++rx_queue->notified_count;
+ }
+
+ wmb();
+ write_ptr = rx_queue->added_count & FALCON_RXD_RING_MASK;
+ EFX_POPULATE_DWORD_1(reg, RX_DESC_WPTR_DWORD, write_ptr);
+ falcon_writel_page(rx_queue->efx, ®,
+ RX_DESC_UPD_REG_KER_DWORD, rx_queue->queue);
+}
+
+int falcon_probe_rx(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ return falcon_alloc_special_buffer(efx, &rx_queue->rxd,
+ FALCON_RXD_RING_SIZE *
+ sizeof(efx_qword_t));
+}
+
+int falcon_init_rx(struct efx_rx_queue *rx_queue)
+{
+ efx_oword_t rx_desc_ptr;
+ struct efx_nic *efx = rx_queue->efx;
+ int rc;
+ int is_b0 = FALCON_REV(efx) >= FALCON_REV_B0;
+ int iscsi_digest_en = is_b0;
+
+ EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
+ rx_queue->queue, rx_queue->rxd.index,
+ rx_queue->rxd.index + rx_queue->rxd.entries - 1);
+
+ /* Pin RX descriptor ring */
+ rc = falcon_init_special_buffer(efx, &rx_queue->rxd);
+ if (rc)
+ return rc;
+
+ /* Push RX descriptor ring to card */
+ EFX_POPULATE_OWORD_10(rx_desc_ptr,
+ RX_ISCSI_DDIG_EN, iscsi_digest_en,
+ RX_ISCSI_HDIG_EN, iscsi_digest_en,
+ RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index,
+ RX_DESCQ_EVQ_ID, rx_queue->channel->evqnum,
+ RX_DESCQ_OWNER_ID, 0,
+ RX_DESCQ_LABEL, rx_queue->queue,
+ RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER,
+ RX_DESCQ_TYPE, 0 /* kernel queue */ ,
+ /* For >=B0 this is scatter so disable */
+ RX_DESCQ_JUMBO, !is_b0,
+ RX_DESCQ_EN, 1);
+ falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
+ return 0;
+}
+
+static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ struct efx_channel *channel = &efx->channel[0];
+ unsigned int read_ptr, i;
+ efx_oword_t rx_flush_descq;
+
+ /* Post a flush command */
+ EFX_POPULATE_OWORD_2(rx_flush_descq,
+ RX_FLUSH_DESCQ_CMD, 1,
+ RX_FLUSH_DESCQ, rx_queue->queue);
+ falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER);
+ msleep(FALCON_FLUSH_TIMEOUT);
+
+ if (EFX_WORKAROUND_7803(efx))
+ return 0;
+
+ /* Look for a flush completed event */
+ read_ptr = channel->eventq_read_ptr;
+ for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
+ efx_qword_t *event = falcon_event(channel, read_ptr);
+ int ev_code, ev_sub_code, ev_queue, ev_failed;
+ if (!falcon_event_present(event))
+ break;
+
+ ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
+ ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+ ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_DESCQ_ID);
+ ev_failed = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_FLUSH_FAIL);
+
+ if ((ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) &&
+ (ev_queue == rx_queue->queue)) {
+ if (ev_failed) {
+ EFX_INFO(efx, "rx queue %d flush command "
+ "failed\n", rx_queue->queue);
+ return -EAGAIN;
+ } else {
+ EFX_LOG(efx, "rx queue %d flush command "
+ "succesful\n", rx_queue->queue);
+ return 0;
+ }
+ }
+
+ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+ }
+
+ if (EFX_WORKAROUND_11557(efx)) {
+ efx_oword_t reg;
+ int enabled;
+
+ falcon_read_table(efx, ®, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
+ enabled = EFX_OWORD_FIELD(reg, RX_DESCQ_EN);
+ if (!enabled) {
+ EFX_LOG(efx, "rx queue %d disabled without a "
+ "flush event seen\n", rx_queue->queue);
+ return 0;
+ }
+ }
+
+ EFX_ERR(efx, "rx queue %d flush command timed out\n", rx_queue->queue);
+ return -ETIMEDOUT;
+}
+
+void falcon_fini_rx(struct efx_rx_queue *rx_queue)
+{
+ efx_oword_t rx_desc_ptr;
+ struct efx_nic *efx = rx_queue->efx;
+ int i, rc;
+
+ /* Try and flush the rx queue. This may need to be repeated */
+ for (i = 0; i < 5; i++) {
+ rc = falcon_flush_rx_queue(rx_queue);
+ if (rc == -EAGAIN)
+ continue;
+ break;
+ }
+ if (rc)
+ EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue);
+
+ /* Remove RX descriptor ring from card */
+ EFX_ZERO_OWORD(rx_desc_ptr);
+ falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
+ rx_queue->queue);
+
+ /* Unpin RX descriptor ring */
+ falcon_fini_special_buffer(efx, &rx_queue->rxd);
+}
+
+/* Free buffers backing RX queue */
+void falcon_remove_rx(struct efx_rx_queue *rx_queue)
+{
+ falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
+}
+
+/**************************************************************************
+ *
+ * Falcon event queue processing
+ * Event queues are processed by per-channel tasklets.
+ *
+ **************************************************************************/
+
+/* Update a channel's event queue's read pointer (RPTR) register
+ *
+ * This writes the EVQ_RPTR_REG register for the specified channel's
+ * event queue.
+ *
+ * Note that EVQ_RPTR_REG contains the index of the "last read" event,
+ * whereas channel->eventq_read_ptr contains the index of the "next to
+ * read" event.
+ */
+void falcon_eventq_read_ack(struct efx_channel *channel)
+{
+ efx_dword_t reg;
+ struct efx_nic *efx = channel->efx;
+
+ EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr);
+ falcon_writel_table(efx, ®, efx->type->evq_rptr_tbl_base,
+ channel->evqnum);
+}
+
+/* Use HW to insert a SW defined event */
+void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event)
+{
+ efx_oword_t drv_ev_reg;
+
+ EFX_POPULATE_OWORD_2(drv_ev_reg,
+ DRV_EV_QID, channel->evqnum,
+ DRV_EV_DATA,
+ EFX_QWORD_FIELD64(*event, WHOLE_EVENT));
+ falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER);
+}
+
+/* Handle a transmit completion event
+ *
+ * Falcon batches TX completion events; the message we receive is of
+ * the form "complete all TX events up to this index".
+ */
+static inline void falcon_handle_tx_event(struct efx_channel *channel,
+ efx_qword_t *event)
+{
+ unsigned int tx_ev_desc_ptr;
+ unsigned int tx_ev_q_label;
+ struct efx_tx_queue *tx_queue;
+ struct efx_nic *efx = channel->efx;
+
+ if (likely(EFX_QWORD_FIELD(*event, TX_EV_COMP))) {
+ /* Transmit completion */
+ tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR);
+ tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
+ tx_queue = &efx->tx_queue[tx_ev_q_label];
+ efx_xmit_done(tx_queue, tx_ev_desc_ptr);
+ } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) {
+ /* Rewrite the FIFO write pointer */
+ tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
+ tx_queue = &efx->tx_queue[tx_ev_q_label];
+
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_lock(efx->net_dev);
+ falcon_notify_tx_desc(tx_queue);
+ if (NET_DEV_REGISTERED(efx))
+ netif_tx_unlock(efx->net_dev);
+ } else if (EFX_QWORD_FIELD(*event, TX_EV_PKT_ERR) &&
+ EFX_WORKAROUND_10727(efx)) {
+ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
+ } else {
+ EFX_ERR(efx, "channel %d unexpected TX event "
+ EFX_QWORD_FMT"\n", channel->channel,
+ EFX_QWORD_VAL(*event));
+ }
+}
+
+/* Check received packet's destination MAC address. */
+static int check_dest_mac(struct efx_rx_queue *rx_queue,
+ const efx_qword_t *event)
+{
+ struct efx_rx_buffer *rx_buf;
+ struct efx_nic *efx = rx_queue->efx;
+ int rx_ev_desc_ptr;
+ struct ethhdr *eh;
+
+ if (efx->promiscuous)
+ return 1;
+
+ rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
+ rx_buf = efx_rx_buffer(rx_queue, rx_ev_desc_ptr);
+ eh = (struct ethhdr *)rx_buf->data;
+ if (memcmp(eh->h_dest, efx->net_dev->dev_addr, ETH_ALEN))
+ return 0;
+ return 1;
+}
+
+/* Detect errors included in the rx_evt_pkt_ok bit. */
+static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
+ const efx_qword_t *event,
+ unsigned *rx_ev_pkt_ok,
+ int *discard, int byte_count)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
+ unsigned rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
+ unsigned rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
+ unsigned rx_ev_pkt_type, rx_ev_other_err, rx_ev_pause_frm;
+ unsigned rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
+ int snap, non_ip;
+
+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
+ rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, RX_EV_TOBE_DISC);
+ rx_ev_pkt_type = EFX_QWORD_FIELD(*event, RX_EV_PKT_TYPE);
+ rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event,
+ RX_EV_BUF_OWNER_ID_ERR);
+ rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, RX_EV_IF_FRAG_ERR);
+ rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event,
+ RX_EV_IP_HDR_CHKSUM_ERR);
+ rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event,
+ RX_EV_TCP_UDP_CHKSUM_ERR);
+ rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, RX_EV_ETH_CRC_ERR);
+ rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, RX_EV_FRM_TRUNC);
+ rx_ev_drib_nib = ((FALCON_REV(efx) >= FALCON_REV_B0) ?
+ 0 : EFX_QWORD_FIELD(*event, RX_EV_DRIB_NIB));
+ rx_ev_pause_frm = EFX_QWORD_FIELD(*event, RX_EV_PAUSE_FRM_ERR);
+
+ /* Every error apart from tobe_disc and pause_frm */
+ rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err |
+ rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
+ rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
+
+ snap = (rx_ev_pkt_type == RX_EV_PKT_TYPE_LLC_DECODE) ||
+ (rx_ev_pkt_type == RX_EV_PKT_TYPE_VLAN_LLC_DECODE);
+ non_ip = (rx_ev_hdr_type == RX_EV_HDR_TYPE_NON_IP_DECODE);
+
+ /* SFC bug 5475/8970: The Falcon XMAC incorrectly calculates the
+ * length field of an LLC frame, which sets TOBE_DISC. We could set
+ * PASS_LEN_ERR, but we want the MAC to filter out short frames (to
+ * protect the RX block).
+ *
+ * bug5475 - LLC/SNAP: Falcon identifies SNAP packets.
+ * bug8970 - LLC/noSNAP: Falcon does not provide an LLC flag.
+ * LLC can't encapsulate IP, so by definition
+ * these packets are NON_IP.
+ *
+ * Unicast mismatch will also cause TOBE_DISC, so the driver needs
+ * to check this.
+ */
+ if (EFX_WORKAROUND_5475(efx) && rx_ev_tobe_disc && (snap || non_ip)) {
+ /* If all the other flags are zero then we can state the
+ * entire packet is ok, which will flag to the kernel not
+ * to recalculate checksums.
+ */
+ if (!(non_ip | rx_ev_other_err | rx_ev_pause_frm))
+ *rx_ev_pkt_ok = 1;
+
+ rx_ev_tobe_disc = 0;
+
+ /* TOBE_DISC is set for unicast mismatch. But given that
+ * we can't trust TOBE_DISC here, we must validate the dest
+ * MAC address ourselves.
+ */
+ if (!rx_ev_mcast_pkt && !check_dest_mac(rx_queue, event))
+ rx_ev_tobe_disc = 1;
+ }
+
+ /* Count errors that are not in MAC stats. */
+ if (rx_ev_frm_trunc)
+ ++rx_queue->channel->n_rx_frm_trunc;
+ else if (rx_ev_tobe_disc)
+ ++rx_queue->channel->n_rx_tobe_disc;
+ else if (rx_ev_ip_hdr_chksum_err)
+ ++rx_queue->channel->n_rx_ip_hdr_chksum_err;
+ else if (rx_ev_tcp_udp_chksum_err)
+ ++rx_queue->channel->n_rx_tcp_udp_chksum_err;
+ if (rx_ev_ip_frag_err)
+ ++rx_queue->channel->n_rx_ip_frag_err;
+
+ /* The frame must be discarded if any of these are true. */
+ *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib |
+ rx_ev_tobe_disc | rx_ev_pause_frm);
+
+ /* TOBE_DISC is expected on unicast mismatches; don't print out an
+ * error message. FRM_TRUNC indicates RXDP dropped the packet due
+ * to a FIFO overflow.
+ */
+#ifdef EFX_ENABLE_DEBUG
+ if (rx_ev_other_err) {
+ EFX_INFO_RL(efx, " RX queue %d unexpected RX event "
+ EFX_QWORD_FMT "%s%s%s%s%s%s%s%s%s\n",
+ rx_queue->queue, EFX_QWORD_VAL(*event),
+ rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
+ rx_ev_ip_hdr_chksum_err ?
+ " [IP_HDR_CHKSUM_ERR]" : "",
+ rx_ev_tcp_udp_chksum_err ?
+ " [TCP_UDP_CHKSUM_ERR]" : "",
+ rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "",
+ rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
+ rx_ev_drib_nib ? " [DRIB_NIB]" : "",
+ rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
+ rx_ev_pause_frm ? " [PAUSE]" : "",
+ snap ? " [SNAP/LLC]" : "");
+ }
+#endif
+
+ if (unlikely(rx_ev_eth_crc_err && EFX_WORKAROUND_10750(efx) &&
+ efx->phy_type == PHY_TYPE_10XPRESS))
+ tenxpress_crc_err(efx);
+}
+
+/* Handle receive events that are not in-order. */
+static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue,
+ unsigned index)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned expected, dropped;
+
+ expected = rx_queue->removed_count & FALCON_RXD_RING_MASK;
+ dropped = ((index + FALCON_RXD_RING_SIZE - expected) &
+ FALCON_RXD_RING_MASK);
+ EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n",
+ dropped, index, expected);
+
+ efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ?
+ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
+}
+
+/* Handle a packet received event
+ *
+ * Falcon silicon gives a "discard" flag if it's a unicast packet with the
+ * wrong destination address
+ * Also "is multicast" and "matches multicast filter" flags can be used to
+ * discard non-matching multicast packets.
+ */
+static inline int falcon_handle_rx_event(struct efx_channel *channel,
+ const efx_qword_t *event)
+{
+ unsigned int rx_ev_q_label, rx_ev_desc_ptr, rx_ev_byte_cnt;
+ unsigned int rx_ev_pkt_ok, rx_ev_hdr_type, rx_ev_mcast_pkt;
+ unsigned expected_ptr;
+ int discard = 0, checksummed;
+ struct efx_rx_queue *rx_queue;
+ struct efx_nic *efx = channel->efx;
+
+ /* Basic packet information */
+ rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, RX_EV_BYTE_CNT);
+ rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, RX_EV_PKT_OK);
+ rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
+ WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT));
+ WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1);
+
+ rx_ev_q_label = EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL);
+ rx_queue = &efx->rx_queue[rx_ev_q_label];
+
+ rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
+ expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK;
+ if (unlikely(rx_ev_desc_ptr != expected_ptr)) {
+ falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
+ return rx_ev_q_label;
+ }
+
+ if (likely(rx_ev_pkt_ok)) {
+ /* If packet is marked as OK and packet type is TCP/IPv4 or
+ * UDP/IPv4, then we can rely on the hardware checksum.
+ */
+ checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type);
+ } else {
+ falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok,
+ &discard, rx_ev_byte_cnt);
+ checksummed = 0;
+ }
+
+ /* Detect multicast packets that didn't match the filter */
+ rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
+ if (rx_ev_mcast_pkt) {
+ unsigned int rx_ev_mcast_hash_match =
+ EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH);
+
+ if (unlikely(!rx_ev_mcast_hash_match))
+ discard = 1;
+ }
+
+ /* Handle received packet */
+ efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
+ checksummed, discard);
+
+ return rx_ev_q_label;
+}
+
+/* Global events are basically PHY events */
+static void falcon_handle_global_event(struct efx_channel *channel,
+ efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ int is_phy_event = 0, handled = 0;
+
+ /* Check for interrupt on either port. Some boards have a
+ * single PHY wired to the interrupt line for port 1. */
+ if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) ||
+ EFX_QWORD_FIELD(*event, G_PHY1_INTR) ||
+ EFX_QWORD_FIELD(*event, XG_PHY_INTR))
+ is_phy_event = 1;
+
+ if ((FALCON_REV(efx) >= FALCON_REV_B0) &&
+ EFX_OWORD_FIELD(*event, XG_MNT_INTR_B0))
+ is_phy_event = 1;
+
+ if (is_phy_event) {
+ efx->phy_op->clear_interrupt(efx);
+ queue_work(efx->workqueue, &efx->reconfigure_work);
+ handled = 1;
+ }
+
+ if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) {
+ EFX_ERR(efx, "channel %d seen global RX_RESET "
+ "event. Resetting.\n", channel->channel);
+
+ atomic_inc(&efx->rx_reset);
+ efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
+ RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
+ handled = 1;
+ }
+
+ if (!handled)
+ EFX_ERR(efx, "channel %d unknown global event "
+ EFX_QWORD_FMT "\n", channel->channel,
+ EFX_QWORD_VAL(*event));
+}
+
+static void falcon_handle_driver_event(struct efx_channel *channel,
+ efx_qword_t *event)
+{
+ struct efx_nic *efx = channel->efx;
+ unsigned int ev_sub_code;
+ unsigned int ev_sub_data;
+
+ ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
+ ev_sub_data = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_DATA);
+
+ switch (ev_sub_code) {
+ case TX_DESCQ_FLS_DONE_EV_DECODE:
+ EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
+ channel->channel, ev_sub_data);
+ break;
+ case RX_DESCQ_FLS_DONE_EV_DECODE:
+ EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
+ channel->channel, ev_sub_data);
+ break;
+ case EVQ_INIT_DONE_EV_DECODE:
+ EFX_LOG(efx, "channel %d EVQ %d initialised\n",
+ channel->channel, ev_sub_data);
+ break;
+ case SRM_UPD_DONE_EV_DECODE:
+ EFX_TRACE(efx, "channel %d SRAM update done\n",
+ channel->channel);
+ break;
+ case WAKE_UP_EV_DECODE:
+ EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
+ channel->channel, ev_sub_data);
+ break;
+ case TIMER_EV_DECODE:
+ EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
+ channel->channel, ev_sub_data);
+ break;
+ case RX_RECOVERY_EV_DECODE:
+ EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
+ "Resetting.\n", channel->channel);
+ efx_schedule_reset(efx,
+ EFX_WORKAROUND_6555(efx) ?
+ RESET_TYPE_RX_RECOVERY :
+ RESET_TYPE_DISABLE);
+ break;
+ case RX_DSC_ERROR_EV_DECODE:
+ EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error."
+ " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+ efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
+ break;
+ case TX_DSC_ERROR_EV_DECODE:
+ EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error."
+ " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
+ efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
+ break;
+ default:
+ EFX_TRACE(efx, "channel %d unknown driver event code %d "
+ "data %04x\n", channel->channel, ev_sub_code,
+ ev_sub_data);
+ break;
+ }
+}
+
+int falcon_process_eventq(struct efx_channel *channel, int *rx_quota)
+{
+ unsigned int read_ptr;
+ efx_qword_t event, *p_event;
+ int ev_code;
+ int rxq;
+ int rxdmaqs = 0;
+
+ read_ptr = channel->eventq_read_ptr;
+
+ do {
+ p_event = falcon_event(channel, read_ptr);
+ event = *p_event;
+
+ if (!falcon_event_present(&event))
+ /* End of events */
+ break;
+
+ EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n",
+ channel->channel, EFX_QWORD_VAL(event));
+
+ /* Clear this event by marking it all ones */
+ EFX_SET_QWORD(*p_event);
+
+ ev_code = EFX_QWORD_FIELD(event, EV_CODE);
+
+ switch (ev_code) {
+ case RX_IP_EV_DECODE:
+ rxq = falcon_handle_rx_event(channel, &event);
+ rxdmaqs |= (1 << rxq);
+ (*rx_quota)--;
+ break;
+ case TX_IP_EV_DECODE:
+ falcon_handle_tx_event(channel, &event);
+ break;
+ case DRV_GEN_EV_DECODE:
+ channel->eventq_magic
+ = EFX_QWORD_FIELD(event, EVQ_MAGIC);
+ EFX_LOG(channel->efx, "channel %d received generated "
+ "event "EFX_QWORD_FMT"\n", channel->channel,
+ EFX_QWORD_VAL(event));
+ break;
+ case GLOBAL_EV_DECODE:
+ falcon_handle_global_event(channel, &event);
+ break;
+ case DRIVER_EV_DECODE:
+ falcon_handle_driver_event(channel, &event);
+ break;
+ default:
+ EFX_ERR(channel->efx, "channel %d unknown event type %d"
+ " (data " EFX_QWORD_FMT ")\n", channel->channel,
+ ev_code, EFX_QWORD_VAL(event));
+ }
+
+ /* Increment read pointer */
+ read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
+
+ } while (*rx_quota);
+
+ channel->eventq_read_ptr = read_ptr;
+ return rxdmaqs;
+}
+
+void falcon_set_int_moderation(struct efx_channel *channel)
+{
+ efx_dword_t timer_cmd;
+ struct efx_nic *efx = channel->efx;
+
+ /* Set timer register */
+ if (channel->irq_moderation) {
+ /* Round to resolution supported by hardware. The value we
+ * program is based at 0. So actual interrupt moderation
+ * achieved is ((x + 1) * res).
+ */
+ unsigned int res = 5;
+ channel->irq_moderation -= (channel->irq_moderation % res);
+ if (channel->irq_moderation < res)
+ channel->irq_moderation = res;
+ EFX_POPULATE_DWORD_2(timer_cmd,
+ TIMER_MODE, TIMER_MODE_INT_HLDOFF,
+ TIMER_VAL,
+ (channel->irq_moderation / res) - 1);
+ } else {
+ EFX_POPULATE_DWORD_2(timer_cmd,
+ TIMER_MODE, TIMER_MODE_DIS,
+ TIMER_VAL, 0);
+ }
+ falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER,
+ channel->evqnum);
+
+}
+
+/* Allocate buffer table entries for event queue */
+int falcon_probe_eventq(struct efx_channel *channel)
+{
+ struct efx_nic *efx = channel->efx;
+ unsigned int evq_size;
+
+ evq_size = FALCON_EVQ_SIZE * sizeof(efx_qword_t);
+ return falcon_alloc_special_buffer(efx, &channel->eventq, evq_size);
+}
+
+int falcon_init_eventq(struct efx_channel *channel)
+{
+ efx_oword_t evq_ptr;
+ struct efx_nic *efx = channel->efx;
+ int rc;
+
+ EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
+ channel->channel, channel->eventq.index,
+ channel->eventq.index + channel->eventq.entries - 1);
+
+ /* Pin event queue buffer */
+ rc = falcon_init_special_buffer(efx, &channel->eventq);
+ if (rc)
+ return rc;
+
+ /* Fill event queue with all ones (i.e. empty events) */
+ memset(channel->eventq.addr, 0xff, channel->eventq.len);
+
+ /* Push event queue to card */
+ EFX_POPULATE_OWORD_3(evq_ptr,
+ EVQ_EN, 1,
+ EVQ_SIZE, FALCON_EVQ_ORDER,
+ EVQ_BUF_BASE_ID, channel->eventq.index);
+ falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
+ channel->evqnum);
+
+ falcon_set_int_moderation(channel);
+
+ return 0;
+}
+
+void falcon_fini_eventq(struct efx_channel *channel)
+{
+ efx_oword_t eventq_ptr;
+ struct efx_nic *efx = channel->efx;
+
+ /* Remove event queue from card */
+ EFX_ZERO_OWORD(eventq_ptr);
+ falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base,
+ channel->evqnum);
+
+ /* Unpin event queue */
+ falcon_fini_special_buffer(efx, &channel->eventq);
+}
+
+/* Free buffers backing event queue */
+void falcon_remove_eventq(struct efx_channel *channel)
+{
+ falcon_free_special_buffer(channel->efx, &channel->eventq);
+}
+
+
+/* Generates a test event on the event queue. A subsequent call to
+ * process_eventq() should pick up the event and place the value of
+ * "magic" into channel->eventq_magic;
+ */
+void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
+{
+ efx_qword_t test_event;
+
+ EFX_POPULATE_QWORD_2(test_event,
+ EV_CODE, DRV_GEN_EV_DECODE,
+ EVQ_MAGIC, magic);
+ falcon_generate_event(channel, &test_event);
+}
+
+
+/**************************************************************************
+ *
+ * Falcon hardware interrupts
+ * The hardware interrupt handler does very little work; all the event
+ * queue processing is carried out by per-channel tasklets.
+ *
+ **************************************************************************/
+
+/* Enable/disable/generate Falcon interrupts */
+static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
+ int force)
+{
+ efx_oword_t int_en_reg_ker;
+
+ EFX_POPULATE_OWORD_2(int_en_reg_ker,
+ KER_INT_KER, force,
+ DRV_INT_EN_KER, enabled);
+ falcon_write(efx, &int_en_reg_ker, INT_EN_REG_KER);
+}
+
+void falcon_enable_interrupts(struct efx_nic *efx)
+{
+ efx_oword_t int_adr_reg_ker;
+ struct efx_channel *channel;
+
+ EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
+ wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
+
+ /* Program address */
+ EFX_POPULATE_OWORD_2(int_adr_reg_ker,
+ NORM_INT_VEC_DIS_KER, EFX_INT_MODE_USE_MSI(efx),
+ INT_ADR_KER, efx->irq_status.dma_addr);
+ falcon_write(efx, &int_adr_reg_ker, INT_ADR_REG_KER);
+
+ /* Enable interrupts */
+ falcon_interrupts(efx, 1, 0);
+
+ /* Force processing of all the channels to get the EVQ RPTRs up to
+ date */
+ efx_for_each_channel_with_interrupt(channel, efx)
+ efx_schedule_channel(channel);
+}
+
+void falcon_disable_interrupts(struct efx_nic *efx)
+{
+ /* Disable interrupts */
+ falcon_interrupts(efx, 0, 0);
+}
+
+/* Generate a Falcon test interrupt
+ * Interrupt must already have been enabled, otherwise nasty things
+ * may happen.
+ */
+void falcon_generate_interrupt(struct efx_nic *efx)
+{
+ falcon_interrupts(efx, 1, 1);
+}
+
+/* Acknowledge a legacy interrupt from Falcon
+ *
+ * This acknowledges a legacy (not MSI) interrupt via INT_ACK_KER_REG.
+ *
+ * Due to SFC bug 3706 (silicon revision <=A1) reads can be duplicated in the
+ * BIU. Interrupt acknowledge is read sensitive so must write instead
+ * (then read to ensure the BIU collector is flushed)
+ *
+ * NB most hardware supports MSI interrupts
+ */
+static inline void falcon_irq_ack_a1(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ EFX_POPULATE_DWORD_1(reg, INT_ACK_DUMMY_DATA, 0xb7eb7e);
+ falcon_writel(efx, ®, INT_ACK_REG_KER_A1);
+ falcon_readl(efx, ®, WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1);
+}
+
+/* Process a fatal interrupt
+ * Disable bus mastering ASAP and schedule a reset
+ */
+static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ efx_oword_t fatal_intr;
+ int error, mem_perr;
+ static int n_int_errors;
+
+ falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER);
+ error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR);
+
+ EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status "
+ EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
+ EFX_OWORD_VAL(fatal_intr),
+ error ? "disabling bus mastering" : "no recognised error");
+ if (error == 0)
+ goto out;
+
+ /* If this is a memory parity error dump which blocks are offending */
+ mem_perr = EFX_OWORD_FIELD(fatal_intr, MEM_PERR_INT_KER);
+ if (mem_perr) {
+ efx_oword_t reg;
+ falcon_read(efx, ®, MEM_STAT_REG_KER);
+ EFX_ERR(efx, "SYSTEM ERROR: memory parity error "
+ EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
+ }
+
+ /* Disable DMA bus mastering on both devices */
+ pci_disable_device(efx->pci_dev);
+ if (FALCON_IS_DUAL_FUNC(efx))
+ pci_disable_device(nic_data->pci_dev2);
+
+ if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
+ EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
+ efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
+ } else {
+ EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen."
+ "NIC will be disabled\n");
+ efx_schedule_reset(efx, RESET_TYPE_DISABLE);
+ }
+out:
+ return IRQ_HANDLED;
+}
+
+/* Handle a legacy interrupt from Falcon
+ * Acknowledges the interrupt and schedule event queue processing.
+ */
+static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
+{
+ struct efx_nic *efx = (struct efx_nic *)dev_id;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ struct efx_channel *channel;
+ efx_dword_t reg;
+ u32 queues;
+ int syserr;
+
+ /* Read the ISR which also ACKs the interrupts */
+ falcon_readl(efx, ®, INT_ISR0_B0);
+ queues = EFX_EXTRACT_DWORD(reg, 0, 31);
+
+ /* Check to see if we have a serious error condition */
+ syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ if (unlikely(syserr))
+ return falcon_fatal_interrupt(efx);
+
+ if (queues == 0)
+ return IRQ_NONE;
+
+ efx->last_irq_cpu = raw_smp_processor_id();
+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+
+ /* Schedule processing of any interrupting queues */
+ channel = &efx->channel[0];
+ while (queues) {
+ if (queues & 0x01)
+ efx_schedule_channel(channel);
+ channel++;
+ queues >>= 1;
+ }
+
+ return IRQ_HANDLED;
+}
+
+
+static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
+{
+ struct efx_nic *efx = (struct efx_nic *)dev_id;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ struct efx_channel *channel;
+ int syserr;
+ int queues;
+
+ /* Check to see if this is our interrupt. If it isn't, we
+ * exit without having touched the hardware.
+ */
+ if (unlikely(EFX_OWORD_IS_ZERO(*int_ker))) {
+ EFX_TRACE(efx, "IRQ %d on CPU %d not for me\n", irq,
+ raw_smp_processor_id());
+ return IRQ_NONE;
+ }
+ efx->last_irq_cpu = raw_smp_processor_id();
+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+
+ /* Check to see if we have a serious error condition */
+ syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ if (unlikely(syserr))
+ return falcon_fatal_interrupt(efx);
+
+ /* Determine interrupting queues, clear interrupt status
+ * register and acknowledge the device interrupt.
+ */
+ BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS);
+ queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS);
+ EFX_ZERO_OWORD(*int_ker);
+ wmb(); /* Ensure the vector is cleared before interrupt ack */
+ falcon_irq_ack_a1(efx);
+
+ /* Schedule processing of any interrupting queues */
+ channel = &efx->channel[0];
+ while (queues) {
+ if (queues & 0x01)
+ efx_schedule_channel(channel);
+ channel++;
+ queues >>= 1;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/* Handle an MSI interrupt from Falcon
+ *
+ * Handle an MSI hardware interrupt. This routine schedules event
+ * queue processing. No interrupt acknowledgement cycle is necessary.
+ * Also, we never need to check that the interrupt is for us, since
+ * MSI interrupts cannot be shared.
+ */
+static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
+{
+ struct efx_channel *channel = (struct efx_channel *)dev_id;
+ struct efx_nic *efx = channel->efx;
+ efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
+ int syserr;
+
+ efx->last_irq_cpu = raw_smp_processor_id();
+ EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
+ irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
+
+ /* Check to see if we have a serious error condition */
+ syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+ if (unlikely(syserr))
+ return falcon_fatal_interrupt(efx);
+
+ /* Schedule processing of the channel */
+ efx_schedule_channel(channel);
+
+ return IRQ_HANDLED;
+}
+
+
+/* Setup RSS indirection table.
+ * This maps from the hash value of the packet to RXQ
+ */
+static void falcon_setup_rss_indir_table(struct efx_nic *efx)
+{
+ int i = 0;
+ unsigned long offset;
+ efx_dword_t dword;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ for (offset = RX_RSS_INDIR_TBL_B0;
+ offset < RX_RSS_INDIR_TBL_B0 + 0x800;
+ offset += 0x10) {
+ EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0,
+ i % efx->rss_queues);
+ falcon_writel(efx, &dword, offset);
+ i++;
+ }
+}
+
+/* Hook interrupt handler(s)
+ * Try MSI and then legacy interrupts.
+ */
+int falcon_init_interrupt(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ int rc;
+
+ if (!EFX_INT_MODE_USE_MSI(efx)) {
+ irq_handler_t handler;
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ handler = falcon_legacy_interrupt_b0;
+ else
+ handler = falcon_legacy_interrupt_a1;
+
+ rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED,
+ efx->name, efx);
+ if (rc) {
+ EFX_ERR(efx, "failed to hook legacy IRQ %d\n",
+ efx->pci_dev->irq);
+ goto fail1;
+ }
+ return 0;
+ }
+
+ /* Hook MSI or MSI-X interrupt */
+ efx_for_each_channel_with_interrupt(channel, efx) {
+ rc = request_irq(channel->irq, falcon_msi_interrupt,
+ IRQF_PROBE_SHARED, /* Not shared */
+ efx->name, channel);
+ if (rc) {
+ EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq);
+ goto fail2;
+ }
+ }
+
+ return 0;
+
+ fail2:
+ efx_for_each_channel_with_interrupt(channel, efx)
+ free_irq(channel->irq, channel);
+ fail1:
+ return rc;
+}
+
+void falcon_fini_interrupt(struct efx_nic *efx)
+{
+ struct efx_channel *channel;
+ efx_oword_t reg;
+
+ /* Disable MSI/MSI-X interrupts */
+ efx_for_each_channel_with_interrupt(channel, efx)
+ if (channel->irq)
+ free_irq(channel->irq, channel);
+
+ /* ACK legacy interrupt */
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ falcon_read(efx, ®, INT_ISR0_B0);
+ else
+ falcon_irq_ack_a1(efx);
+
+ /* Disable legacy interrupt */
+ if (efx->legacy_irq)
+ free_irq(efx->legacy_irq, efx);
+}
+
+/**************************************************************************
+ *
+ * EEPROM/flash
+ *
+ **************************************************************************
+ */
+
+#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t)
+
+/* Wait for SPI command completion */
+static int falcon_spi_wait(struct efx_nic *efx)
+{
+ efx_oword_t reg;
+ int cmd_en, timer_active;
+ int count;
+
+ count = 0;
+ do {
+ falcon_read(efx, ®, EE_SPI_HCMD_REG_KER);
+ cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN);
+ timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE);
+ if (!cmd_en && !timer_active)
+ return 0;
+ udelay(10);
+ } while (++count < 10000); /* wait upto 100msec */
+ EFX_ERR(efx, "timed out waiting for SPI\n");
+ return -ETIMEDOUT;
+}
+
+static int
+falcon_spi_read(struct efx_nic *efx, int device_id, unsigned int command,
+ unsigned int address, unsigned int addr_len,
+ void *data, unsigned int len)
+{
+ efx_oword_t reg;
+ int rc;
+
+ BUG_ON(len > FALCON_SPI_MAX_LEN);
+
+ /* Check SPI not currently being accessed */
+ rc = falcon_spi_wait(efx);
+ if (rc)
+ return rc;
+
+ /* Program address register */
+ EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
+ falcon_write(efx, ®, EE_SPI_HADR_REG_KER);
+
+ /* Issue read command */
+ EFX_POPULATE_OWORD_7(reg,
+ EE_SPI_HCMD_CMD_EN, 1,
+ EE_SPI_HCMD_SF_SEL, device_id,
+ EE_SPI_HCMD_DABCNT, len,
+ EE_SPI_HCMD_READ, EE_SPI_READ,
+ EE_SPI_HCMD_DUBCNT, 0,
+ EE_SPI_HCMD_ADBCNT, addr_len,
+ EE_SPI_HCMD_ENC, command);
+ falcon_write(efx, ®, EE_SPI_HCMD_REG_KER);
+
+ /* Wait for read to complete */
+ rc = falcon_spi_wait(efx);
+ if (rc)
+ return rc;
+
+ /* Read data */
+ falcon_read(efx, ®, EE_SPI_HDATA_REG_KER);
+ memcpy(data, ®, len);
+ return 0;
+}
+
+/**************************************************************************
+ *
+ * MAC wrapper
+ *
+ **************************************************************************
+ */
+void falcon_drain_tx_fifo(struct efx_nic *efx)
+{
+ efx_oword_t temp;
+ int count;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
+ /* There is no point in draining more than once */
+ if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
+ return;
+
+ /* MAC stats will fail whilst the TX fifo is draining. Serialise
+ * the drain sequence with the statistics fetch */
+ spin_lock(&efx->stats_lock);
+
+ EFX_SET_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0, 1);
+ falcon_write(efx, &temp, MAC0_CTRL_REG_KER);
+
+ /* Reset the MAC and EM block. */
+ falcon_read(efx, &temp, GLB_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, RST_XGTX, 1);
+ EFX_SET_OWORD_FIELD(temp, RST_XGRX, 1);
+ EFX_SET_OWORD_FIELD(temp, RST_EM, 1);
+ falcon_write(efx, &temp, GLB_CTL_REG_KER);
+
+ count = 0;
+ while (1) {
+ falcon_read(efx, &temp, GLB_CTL_REG_KER);
+ if (!EFX_OWORD_FIELD(temp, RST_XGTX) &&
+ !EFX_OWORD_FIELD(temp, RST_XGRX) &&
+ !EFX_OWORD_FIELD(temp, RST_EM)) {
+ EFX_LOG(efx, "Completed MAC reset after %d loops\n",
+ count);
+ break;
+ }
+ if (count > 20) {
+ EFX_ERR(efx, "MAC reset failed\n");
+ break;
+ }
+ count++;
+ udelay(10);
+ }
+
+ spin_unlock(&efx->stats_lock);
+
+ /* If we've reset the EM block and the link is up, then
+ * we'll have to kick the XAUI link so the PHY can recover */
+ if (efx->link_up && EFX_WORKAROUND_5147(efx))
+ falcon_reset_xaui(efx);
+}
+
+void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
+{
+ efx_oword_t temp;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ /* Isolate the MAC -> RX */
+ falcon_read(efx, &temp, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 0);
+ falcon_write(efx, &temp, RX_CFG_REG_KER);
+
+ if (!efx->link_up)
+ falcon_drain_tx_fifo(efx);
+}
+
+void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
+{
+ efx_oword_t reg;
+ int link_speed;
+ unsigned int tx_fc;
+
+ if (efx->link_options & GM_LPA_10000)
+ link_speed = 0x3;
+ else if (efx->link_options & GM_LPA_1000)
+ link_speed = 0x2;
+ else if (efx->link_options & GM_LPA_100)
+ link_speed = 0x1;
+ else
+ link_speed = 0x0;
+ /* MAC_LINK_STATUS controls MAC backpressure but doesn't work
+ * as advertised. Disable to ensure packets are not
+ * indefinitely held and TX queue can be flushed at any point
+ * while the link is down. */
+ EFX_POPULATE_OWORD_5(reg,
+ MAC_XOFF_VAL, 0xffff /* max pause time */,
+ MAC_BCAD_ACPT, 1,
+ MAC_UC_PROM, efx->promiscuous,
+ MAC_LINK_STATUS, 1, /* always set */
+ MAC_SPEED, link_speed);
+ /* On B0, MAC backpressure can be disabled and packets get
+ * discarded. */
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0,
+ !efx->link_up);
+ }
+
+ falcon_write(efx, ®, MAC0_CTRL_REG_KER);
+
+ /* Restore the multicast hash registers. */
+ falcon_set_multicast_hash(efx);
+
+ /* Transmission of pause frames when RX crosses the threshold is
+ * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
+ * Action on receipt of pause frames is controller by XM_DIS_FCNTL */
+ tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
+ falcon_read(efx, ®, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
+
+ /* Unisolate the MAC -> RX */
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 1);
+ falcon_write(efx, ®, RX_CFG_REG_KER);
+}
+
+int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
+{
+ efx_oword_t reg;
+ u32 *dma_done;
+ int i;
+
+ if (disable_dma_stats)
+ return 0;
+
+ /* Statistics fetch will fail if the MAC is in TX drain */
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ efx_oword_t temp;
+ falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
+ if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
+ return 0;
+ }
+
+ dma_done = (efx->stats_buffer.addr + done_offset);
+ *dma_done = FALCON_STATS_NOT_DONE;
+ wmb(); /* ensure done flag is clear */
+
+ /* Initiate DMA transfer of stats */
+ EFX_POPULATE_OWORD_2(reg,
+ MAC_STAT_DMA_CMD, 1,
+ MAC_STAT_DMA_ADR,
+ efx->stats_buffer.dma_addr);
+ falcon_write(efx, ®, MAC0_STAT_DMA_REG_KER);
+
+ /* Wait for transfer to complete */
+ for (i = 0; i < 400; i++) {
+ if (*(volatile u32 *)dma_done == FALCON_STATS_DONE)
+ return 0;
+ udelay(10);
+ }
+
+ EFX_ERR(efx, "timed out waiting for statistics\n");
+ return -ETIMEDOUT;
+}
+
+/**************************************************************************
+ *
+ * PHY access via GMII
+ *
+ **************************************************************************
+ */
+
+/* Use the top bit of the MII PHY id to indicate the PHY type
+ * (1G/10G), with the remaining bits as the actual PHY id.
+ *
+ * This allows us to avoid leaking information from the mii_if_info
+ * structure into other data structures.
+ */
+#define FALCON_PHY_ID_ID_WIDTH EFX_WIDTH(MD_PRT_DEV_ADR)
+#define FALCON_PHY_ID_ID_MASK ((1 << FALCON_PHY_ID_ID_WIDTH) - 1)
+#define FALCON_PHY_ID_WIDTH (FALCON_PHY_ID_ID_WIDTH + 1)
+#define FALCON_PHY_ID_MASK ((1 << FALCON_PHY_ID_WIDTH) - 1)
+#define FALCON_PHY_ID_10G (1 << (FALCON_PHY_ID_WIDTH - 1))
+
+
+/* Packing the clause 45 port and device fields into a single value */
+#define MD_PRT_ADR_COMP_LBN (MD_PRT_ADR_LBN - MD_DEV_ADR_LBN)
+#define MD_PRT_ADR_COMP_WIDTH MD_PRT_ADR_WIDTH
+#define MD_DEV_ADR_COMP_LBN 0
+#define MD_DEV_ADR_COMP_WIDTH MD_DEV_ADR_WIDTH
+
+
+/* Wait for GMII access to complete */
+static int falcon_gmii_wait(struct efx_nic *efx)
+{
+ efx_dword_t md_stat;
+ int count;
+
+ for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+ falcon_readl(efx, &md_stat, MD_STAT_REG_KER);
+ if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) {
+ if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 ||
+ EFX_DWORD_FIELD(md_stat, MD_BSERR) != 0) {
+ EFX_ERR(efx, "error from GMII access "
+ EFX_DWORD_FMT"\n",
+ EFX_DWORD_VAL(md_stat));
+ return -EIO;
+ }
+ return 0;
+ }
+ udelay(10);
+ }
+ EFX_ERR(efx, "timed out waiting for GMII\n");
+ return -ETIMEDOUT;
+}
+
+/* Writes a GMII register of a PHY connected to Falcon using MDIO. */
+static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
+ int addr, int value)
+{
+ struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
+ unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK;
+ efx_oword_t reg;
+
+ /* The 'generic' prt/dev packing in mdio_10g.h is conveniently
+ * chosen so that the only current user, Falcon, can take the
+ * packed value and use them directly.
+ * Fail to build if this assumption is broken.
+ */
+ BUILD_BUG_ON(FALCON_PHY_ID_10G != MDIO45_XPRT_ID_IS10G);
+ BUILD_BUG_ON(FALCON_PHY_ID_ID_WIDTH != MDIO45_PRT_DEV_WIDTH);
+ BUILD_BUG_ON(MD_PRT_ADR_COMP_LBN != MDIO45_PRT_ID_COMP_LBN);
+ BUILD_BUG_ON(MD_DEV_ADR_COMP_LBN != MDIO45_DEV_ID_COMP_LBN);
+
+ if (phy_id2 == PHY_ADDR_INVALID)
+ return;
+
+ /* See falcon_mdio_read for an explanation. */
+ if (!(phy_id & FALCON_PHY_ID_10G)) {
+ int mmd = ffs(efx->phy_op->mmds) - 1;
+ EFX_TRACE(efx, "Fixing erroneous clause22 write\n");
+ phy_id2 = mdio_clause45_pack(phy_id2, mmd)
+ & FALCON_PHY_ID_ID_MASK;
+ }
+
+ EFX_REGDUMP(efx, "writing GMII %d register %02x with %04x\n", phy_id,
+ addr, value);
+
+ spin_lock_bh(&efx->phy_lock);
+
+ /* Check MII not currently being accessed */
+ if (falcon_gmii_wait(efx) != 0)
+ goto out;
+
+ /* Write the address/ID register */
+ EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
+ falcon_write(efx, ®, MD_PHY_ADR_REG_KER);
+
+ EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_id2);
+ falcon_write(efx, ®, MD_ID_REG_KER);
+
+ /* Write data */
+ EFX_POPULATE_OWORD_1(reg, MD_TXD, value);
+ falcon_write(efx, ®, MD_TXD_REG_KER);
+
+ EFX_POPULATE_OWORD_2(reg,
+ MD_WRC, 1,
+ MD_GC, 0);
+ falcon_write(efx, ®, MD_CS_REG_KER);
+
+ /* Wait for data to be written */
+ if (falcon_gmii_wait(efx) != 0) {
+ /* Abort the write operation */
+ EFX_POPULATE_OWORD_2(reg,
+ MD_WRC, 0,
+ MD_GC, 1);
+ falcon_write(efx, ®, MD_CS_REG_KER);
+ udelay(10);
+ }
+
+ out:
+ spin_unlock_bh(&efx->phy_lock);
+}
+
+/* Reads a GMII register from a PHY connected to Falcon. If no value
+ * could be read, -1 will be returned. */
+static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
+{
+ struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
+ unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK;
+ efx_oword_t reg;
+ int value = -1;
+
+ if (phy_addr == PHY_ADDR_INVALID)
+ return -1;
+
+ /* Our PHY code knows whether it needs to talk clause 22(1G) or 45(10G)
+ * but the generic Linux code does not make any distinction or have
+ * any state for this.
+ * We spot the case where someone tried to talk 22 to a 45 PHY and
+ * redirect the request to the lowest numbered MMD as a clause45
+ * request. This is enough to allow simple queries like id and link
+ * state to succeed. TODO: We may need to do more in future.
+ */
+ if (!(phy_id & FALCON_PHY_ID_10G)) {
+ int mmd = ffs(efx->phy_op->mmds) - 1;
+ EFX_TRACE(efx, "Fixing erroneous clause22 read\n");
+ phy_addr = mdio_clause45_pack(phy_addr, mmd)
+ & FALCON_PHY_ID_ID_MASK;
+ }
+
+ spin_lock_bh(&efx->phy_lock);
+
+ /* Check MII not currently being accessed */
+ if (falcon_gmii_wait(efx) != 0)
+ goto out;
+
+ EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
+ falcon_write(efx, ®, MD_PHY_ADR_REG_KER);
+
+ EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_addr);
+ falcon_write(efx, ®, MD_ID_REG_KER);
+
+ /* Request data to be read */
+ EFX_POPULATE_OWORD_2(reg, MD_RDC, 1, MD_GC, 0);
+ falcon_write(efx, ®, MD_CS_REG_KER);
+
+ /* Wait for data to become available */
+ value = falcon_gmii_wait(efx);
+ if (value == 0) {
+ falcon_read(efx, ®, MD_RXD_REG_KER);
+ value = EFX_OWORD_FIELD(reg, MD_RXD);
+ EFX_REGDUMP(efx, "read from GMII %d register %02x, got %04x\n",
+ phy_id, addr, value);
+ } else {
+ /* Abort the read operation */
+ EFX_POPULATE_OWORD_2(reg,
+ MD_RIC, 0,
+ MD_GC, 1);
+ falcon_write(efx, ®, MD_CS_REG_KER);
+
+ EFX_LOG(efx, "read from GMII 0x%x register %02x, got "
+ "error %d\n", phy_id, addr, value);
+ }
+
+ out:
+ spin_unlock_bh(&efx->phy_lock);
+
+ return value;
+}
+
+static void falcon_init_mdio(struct mii_if_info *gmii)
+{
+ gmii->mdio_read = falcon_mdio_read;
+ gmii->mdio_write = falcon_mdio_write;
+ gmii->phy_id_mask = FALCON_PHY_ID_MASK;
+ gmii->reg_num_mask = ((1 << EFX_WIDTH(MD_PHY_ADR)) - 1);
+}
+
+static int falcon_probe_phy(struct efx_nic *efx)
+{
+ switch (efx->phy_type) {
+ case PHY_TYPE_10XPRESS:
+ efx->phy_op = &falcon_tenxpress_phy_ops;
+ break;
+ case PHY_TYPE_XFP:
+ efx->phy_op = &falcon_xfp_phy_ops;
+ break;
+ default:
+ EFX_ERR(efx, "Unknown PHY type %d\n",
+ efx->phy_type);
+ return -1;
+ }
+ return 0;
+}
+
+/* This call is responsible for hooking in the MAC and PHY operations */
+int falcon_probe_port(struct efx_nic *efx)
+{
+ int rc;
+
+ /* Hook in PHY operations table */
+ rc = falcon_probe_phy(efx);
+ if (rc)
+ return rc;
+
+ /* Set up GMII structure for PHY */
+ efx->mii.supports_gmii = 1;
+ falcon_init_mdio(&efx->mii);
+
+ /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ efx->flow_control = EFX_FC_RX | EFX_FC_TX;
+ else
+ efx->flow_control = EFX_FC_RX;
+
+ /* Allocate buffer for stats */
+ rc = falcon_alloc_buffer(efx, &efx->stats_buffer,
+ FALCON_MAC_STATS_SIZE);
+ if (rc)
+ return rc;
+ EFX_LOG(efx, "stats buffer at %llx (virt %p phys %lx)\n",
+ (unsigned long long)efx->stats_buffer.dma_addr,
+ efx->stats_buffer.addr,
+ virt_to_phys(efx->stats_buffer.addr));
+
+ return 0;
+}
+
+void falcon_remove_port(struct efx_nic *efx)
+{
+ falcon_free_buffer(efx, &efx->stats_buffer);
+}
+
+/**************************************************************************
+ *
+ * Multicast filtering
+ *
+ **************************************************************************
+ */
+
+void falcon_set_multicast_hash(struct efx_nic *efx)
+{
+ union efx_multicast_hash *mc_hash = &efx->multicast_hash;
+
+ /* Broadcast packets go through the multicast hash filter.
+ * ether_crc_le() of the broadcast address is 0xbe2612ff
+ * so we always add bit 0xff to the mask.
+ */
+ set_bit_le(0xff, mc_hash->byte);
+
+ falcon_write(efx, &mc_hash->oword[0], MAC_MCAST_HASH_REG0_KER);
+ falcon_write(efx, &mc_hash->oword[1], MAC_MCAST_HASH_REG1_KER);
+}
+
+/**************************************************************************
+ *
+ * Device reset
+ *
+ **************************************************************************
+ */
+
+/* Resets NIC to known state. This routine must be called in process
+ * context and is allowed to sleep. */
+int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+ efx_oword_t glb_ctl_reg_ker;
+ int rc;
+
+ EFX_LOG(efx, "performing hardware reset (%d)\n", method);
+
+ /* Initiate device reset */
+ if (method == RESET_TYPE_WORLD) {
+ rc = pci_save_state(efx->pci_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed to backup PCI state of primary "
+ "function prior to hardware reset\n");
+ goto fail1;
+ }
+ if (FALCON_IS_DUAL_FUNC(efx)) {
+ rc = pci_save_state(nic_data->pci_dev2);
+ if (rc) {
+ EFX_ERR(efx, "failed to backup PCI state of "
+ "secondary function prior to "
+ "hardware reset\n");
+ goto fail2;
+ }
+ }
+
+ EFX_POPULATE_OWORD_2(glb_ctl_reg_ker,
+ EXT_PHY_RST_DUR, 0x7,
+ SWRST, 1);
+ } else {
+ int reset_phy = (method == RESET_TYPE_INVISIBLE ?
+ EXCLUDE_FROM_RESET : 0);
+
+ EFX_POPULATE_OWORD_7(glb_ctl_reg_ker,
+ EXT_PHY_RST_CTL, reset_phy,
+ PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
+ PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
+ PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
+ EE_RST_CTL, EXCLUDE_FROM_RESET,
+ EXT_PHY_RST_DUR, 0x7 /* 10ms */,
+ SWRST, 1);
+ }
+ falcon_write(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
+
+ EFX_LOG(efx, "waiting for hardware reset\n");
+ schedule_timeout_uninterruptible(HZ / 20);
+
+ /* Restore PCI configuration if needed */
+ if (method == RESET_TYPE_WORLD) {
+ if (FALCON_IS_DUAL_FUNC(efx)) {
+ rc = pci_restore_state(nic_data->pci_dev2);
+ if (rc) {
+ EFX_ERR(efx, "failed to restore PCI config for "
+ "the secondary function\n");
+ goto fail3;
+ }
+ }
+ rc = pci_restore_state(efx->pci_dev);
+ if (rc) {
+ EFX_ERR(efx, "failed to restore PCI config for the "
+ "primary function\n");
+ goto fail4;
+ }
+ EFX_LOG(efx, "successfully restored PCI config\n");
+ }
+
+ /* Assert that reset complete */
+ falcon_read(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
+ if (EFX_OWORD_FIELD(glb_ctl_reg_ker, SWRST) != 0) {
+ rc = -ETIMEDOUT;
+ EFX_ERR(efx, "timed out waiting for hardware reset\n");
+ goto fail5;
+ }
+ EFX_LOG(efx, "hardware reset complete\n");
+
+ return 0;
+
+ /* pci_save_state() and pci_restore_state() MUST be called in pairs */
+fail2:
+fail3:
+ pci_restore_state(efx->pci_dev);
+fail1:
+fail4:
+fail5:
+ return rc;
+}
+
+/* Zeroes out the SRAM contents. This routine must be called in
+ * process context and is allowed to sleep.
+ */
+static int falcon_reset_sram(struct efx_nic *efx)
+{
+ efx_oword_t srm_cfg_reg_ker, gpio_cfg_reg_ker;
+ int count;
+
+ /* Set the SRAM wake/sleep GPIO appropriately. */
+ falcon_read(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OEN, 1);
+ EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, 1);
+ falcon_write(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
+
+ /* Initiate SRAM reset */
+ EFX_POPULATE_OWORD_2(srm_cfg_reg_ker,
+ SRAM_OOB_BT_INIT_EN, 1,
+ SRM_NUM_BANKS_AND_BANK_SIZE, 0);
+ falcon_write(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
+
+ /* Wait for SRAM reset to complete */
+ count = 0;
+ do {
+ EFX_LOG(efx, "waiting for SRAM reset (attempt %d)...\n", count);
+
+ /* SRAM reset is slow; expect around 16ms */
+ schedule_timeout_uninterruptible(HZ / 50);
+
+ /* Check for reset complete */
+ falcon_read(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
+ if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, SRAM_OOB_BT_INIT_EN)) {
+ EFX_LOG(efx, "SRAM reset complete\n");
+
+ return 0;
+ }
+ } while (++count < 20); /* wait upto 0.4 sec */
+
+ EFX_ERR(efx, "timed out waiting for SRAM reset\n");
+ return -ETIMEDOUT;
+}
+
+/* Extract non-volatile configuration */
+static int falcon_probe_nvconfig(struct efx_nic *efx)
+{
+ struct falcon_nvconfig *nvconfig;
+ efx_oword_t nic_stat;
+ int device_id;
+ unsigned addr_len;
+ size_t offset, len;
+ int magic_num, struct_ver, board_rev;
+ int rc;
+
+ /* Find the boot device. */
+ falcon_read(efx, &nic_stat, NIC_STAT_REG);
+ if (EFX_OWORD_FIELD(nic_stat, SF_PRST)) {
+ device_id = EE_SPI_FLASH;
+ addr_len = 3;
+ } else if (EFX_OWORD_FIELD(nic_stat, EE_PRST)) {
+ device_id = EE_SPI_EEPROM;
+ addr_len = 2;
+ } else {
+ return -ENODEV;
+ }
+
+ nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
+
+ /* Read the whole configuration structure into memory. */
+ for (offset = 0; offset < sizeof(*nvconfig); offset += len) {
+ len = min(sizeof(*nvconfig) - offset,
+ (size_t) FALCON_SPI_MAX_LEN);
+ rc = falcon_spi_read(efx, device_id, SPI_READ,
+ NVCONFIG_BASE + offset, addr_len,
+ (char *)nvconfig + offset, len);
+ if (rc)
+ goto out;
+ }
+
+ /* Read the MAC addresses */
+ memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
+
+ /* Read the board configuration. */
+ magic_num = le16_to_cpu(nvconfig->board_magic_num);
+ struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
+
+ if (magic_num != NVCONFIG_BOARD_MAGIC_NUM || struct_ver < 2) {
+ EFX_ERR(efx, "Non volatile memory bad magic=%x ver=%x "
+ "therefore using defaults\n", magic_num, struct_ver);
+ efx->phy_type = PHY_TYPE_NONE;
+ efx->mii.phy_id = PHY_ADDR_INVALID;
+ board_rev = 0;
+ } else {
+ struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
+
+ efx->phy_type = v2->port0_phy_type;
+ efx->mii.phy_id = v2->port0_phy_addr;
+ board_rev = le16_to_cpu(v2->board_revision);
+ }
+
+ EFX_LOG(efx, "PHY is %d phy_id %d\n", efx->phy_type, efx->mii.phy_id);
+
+ efx_set_board_info(efx, board_rev);
+
+ out:
+ kfree(nvconfig);
+ return rc;
+}
+
+/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port
+ * count, port speed). Set workaround and feature flags accordingly.
+ */
+static int falcon_probe_nic_variant(struct efx_nic *efx)
+{
+ efx_oword_t altera_build;
+
+ falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
+ if (EFX_OWORD_FIELD(altera_build, VER_ALL)) {
+ EFX_ERR(efx, "Falcon FPGA not supported\n");
+ return -ENODEV;
+ }
+
+ switch (FALCON_REV(efx)) {
+ case FALCON_REV_A0:
+ case 0xff:
+ EFX_ERR(efx, "Falcon rev A0 not supported\n");
+ return -ENODEV;
+
+ case FALCON_REV_A1:{
+ efx_oword_t nic_stat;
+
+ falcon_read(efx, &nic_stat, NIC_STAT_REG);
+
+ if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) {
+ EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
+ return -ENODEV;
+ }
+ if (!EFX_OWORD_FIELD(nic_stat, STRAP_10G)) {
+ EFX_ERR(efx, "1G mode not supported\n");
+ return -ENODEV;
+ }
+ break;
+ }
+
+ case FALCON_REV_B0:
+ break;
+
+ default:
+ EFX_ERR(efx, "Unknown Falcon rev %d\n", FALCON_REV(efx));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int falcon_probe_nic(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data;
+ int rc;
+
+ /* Initialise I2C interface state */
+ efx->i2c.efx = efx;
+ efx->i2c.op = &falcon_i2c_bit_operations;
+ efx->i2c.sda = 1;
+ efx->i2c.scl = 1;
+
+ /* Allocate storage for hardware specific data */
+ nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
+ efx->nic_data = (void *) nic_data;
+
+ /* Determine number of ports etc. */
+ rc = falcon_probe_nic_variant(efx);
+ if (rc)
+ goto fail1;
+
+ /* Probe secondary function if expected */
+ if (FALCON_IS_DUAL_FUNC(efx)) {
+ struct pci_dev *dev = pci_dev_get(efx->pci_dev);
+
+ while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID,
+ dev))) {
+ if (dev->bus == efx->pci_dev->bus &&
+ dev->devfn == efx->pci_dev->devfn + 1) {
+ nic_data->pci_dev2 = dev;
+ break;
+ }
+ }
+ if (!nic_data->pci_dev2) {
+ EFX_ERR(efx, "failed to find secondary function\n");
+ rc = -ENODEV;
+ goto fail2;
+ }
+ }
+
+ /* Now we can reset the NIC */
+ rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
+ if (rc) {
+ EFX_ERR(efx, "failed to reset NIC\n");
+ goto fail3;
+ }
+
+ /* Allocate memory for INT_KER */
+ rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t));
+ if (rc)
+ goto fail4;
+ BUG_ON(efx->irq_status.dma_addr & 0x0f);
+
+ EFX_LOG(efx, "INT_KER at %llx (virt %p phys %lx)\n",
+ (unsigned long long)efx->irq_status.dma_addr,
+ efx->irq_status.addr, virt_to_phys(efx->irq_status.addr));
+
+ /* Read in the non-volatile configuration */
+ rc = falcon_probe_nvconfig(efx);
+ if (rc)
+ goto fail5;
+
+ return 0;
+
+ fail5:
+ falcon_free_buffer(efx, &efx->irq_status);
+ fail4:
+ /* fall-thru */
+ fail3:
+ if (nic_data->pci_dev2) {
+ pci_dev_put(nic_data->pci_dev2);
+ nic_data->pci_dev2 = NULL;
+ }
+ fail2:
+ /* fall-thru */
+ fail1:
+ kfree(efx->nic_data);
+ return rc;
+}
+
+/* This call performs hardware-specific global initialisation, such as
+ * defining the descriptor cache sizes and number of RSS channels.
+ * It does not set up any buffers, descriptor rings or event queues.
+ */
+int falcon_init_nic(struct efx_nic *efx)
+{
+ struct falcon_nic_data *data;
+ efx_oword_t temp;
+ unsigned thresh;
+ int rc;
+
+ data = (struct falcon_nic_data *)efx->nic_data;
+
+ /* Set up the address region register. This is only needed
+ * for the B0 FPGA, but since we are just pushing in the
+ * reset defaults this may as well be unconditional. */
+ EFX_POPULATE_OWORD_4(temp, ADR_REGION0, 0,
+ ADR_REGION1, (1 << 16),
+ ADR_REGION2, (2 << 16),
+ ADR_REGION3, (3 << 16));
+ falcon_write(efx, &temp, ADR_REGION_REG_KER);
+
+ /* Use on-chip SRAM */
+ falcon_read(efx, &temp, NIC_STAT_REG);
+ EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1);
+ falcon_write(efx, &temp, NIC_STAT_REG);
+
+ /* Set buffer table mode */
+ EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL);
+ falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER);
+
+ rc = falcon_reset_sram(efx);
+ if (rc)
+ return rc;
+
+ /* Set positions of descriptor caches in SRAM. */
+ EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8);
+ falcon_write(efx, &temp, SRM_TX_DC_CFG_REG_KER);
+ EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8);
+ falcon_write(efx, &temp, SRM_RX_DC_CFG_REG_KER);
+
+ /* Set TX descriptor cache size. */
+ BUILD_BUG_ON(TX_DC_ENTRIES != (16 << TX_DC_ENTRIES_ORDER));
+ EFX_POPULATE_OWORD_1(temp, TX_DC_SIZE, TX_DC_ENTRIES_ORDER);
+ falcon_write(efx, &temp, TX_DC_CFG_REG_KER);
+
+ /* Set RX descriptor cache size. Set low watermark to size-8, as
+ * this allows most efficient prefetching.
+ */
+ BUILD_BUG_ON(RX_DC_ENTRIES != (16 << RX_DC_ENTRIES_ORDER));
+ EFX_POPULATE_OWORD_1(temp, RX_DC_SIZE, RX_DC_ENTRIES_ORDER);
+ falcon_write(efx, &temp, RX_DC_CFG_REG_KER);
+ EFX_POPULATE_OWORD_1(temp, RX_DC_PF_LWM, RX_DC_ENTRIES - 8);
+ falcon_write(efx, &temp, RX_DC_PF_WM_REG_KER);
+
+ /* Clear the parity enables on the TX data fifos as
+ * they produce false parity errors because of timing issues
+ */
+ if (EFX_WORKAROUND_5129(efx)) {
+ falcon_read(efx, &temp, SPARE_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, MEM_PERR_EN_TX_DATA, 0);
+ falcon_write(efx, &temp, SPARE_REG_KER);
+ }
+
+ /* Enable all the genuinely fatal interrupts. (They are still
+ * masked by the overall interrupt mask, controlled by
+ * falcon_interrupts()).
+ *
+ * Note: All other fatal interrupts are enabled
+ */
+ EFX_POPULATE_OWORD_3(temp,
+ ILL_ADR_INT_KER_EN, 1,
+ RBUF_OWN_INT_KER_EN, 1,
+ TBUF_OWN_INT_KER_EN, 1);
+ EFX_INVERT_OWORD(temp);
+ falcon_write(efx, &temp, FATAL_INTR_REG_KER);
+
+ /* Set number of RSS queues for receive path. */
+ falcon_read(efx, &temp, RX_FILTER_CTL_REG);
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ EFX_SET_OWORD_FIELD(temp, NUM_KER, 0);
+ else
+ EFX_SET_OWORD_FIELD(temp, NUM_KER, efx->rss_queues - 1);
+ if (EFX_WORKAROUND_7244(efx)) {
+ EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8);
+ EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8);
+ }
+ falcon_write(efx, &temp, RX_FILTER_CTL_REG);
+
+ falcon_setup_rss_indir_table(efx);
+
+ /* Setup RX. Wait for descriptor is broken and must
+ * be disabled. RXDP recovery shouldn't be needed, but is.
+ */
+ falcon_read(efx, &temp, RX_SELF_RST_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, RX_NODESC_WAIT_DIS, 1);
+ EFX_SET_OWORD_FIELD(temp, RX_RECOVERY_EN, 1);
+ if (EFX_WORKAROUND_5583(efx))
+ EFX_SET_OWORD_FIELD(temp, RX_ISCSI_DIS, 1);
+ falcon_write(efx, &temp, RX_SELF_RST_REG_KER);
+
+ /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
+ * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
+ */
+ falcon_read(efx, &temp, TX_CFG2_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER, 0xfe);
+ EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER_EN, 1);
+ EFX_SET_OWORD_FIELD(temp, TX_ONE_PKT_PER_Q, 1);
+ EFX_SET_OWORD_FIELD(temp, TX_CSR_PUSH_EN, 0);
+ EFX_SET_OWORD_FIELD(temp, TX_DIS_NON_IP_EV, 1);
+ /* Enable SW_EV to inherit in char driver - assume harmless here */
+ EFX_SET_OWORD_FIELD(temp, TX_SW_EV_EN, 1);
+ /* Prefetch threshold 2 => fetch when descriptor cache half empty */
+ EFX_SET_OWORD_FIELD(temp, TX_PREF_THRESHOLD, 2);
+ /* Squash TX of packets of 16 bytes or less */
+ if (FALCON_REV(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
+ EFX_SET_OWORD_FIELD(temp, TX_FLUSH_MIN_LEN_EN_B0, 1);
+ falcon_write(efx, &temp, TX_CFG2_REG_KER);
+
+ /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16
+ * descriptors (which is bad).
+ */
+ falcon_read(efx, &temp, TX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD(temp, TX_NO_EOP_DISC_EN, 0);
+ falcon_write(efx, &temp, TX_CFG_REG_KER);
+
+ /* RX config */
+ falcon_read(efx, &temp, RX_CFG_REG_KER);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_DESC_PUSH_EN, 0);
+ if (EFX_WORKAROUND_7575(efx))
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_USR_BUF_SIZE,
+ (3 * 4096) / 32);
+ if (FALCON_REV(efx) >= FALCON_REV_B0)
+ EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 1);
+
+ /* RX FIFO flow control thresholds */
+ thresh = ((rx_xon_thresh_bytes >= 0) ?
+ rx_xon_thresh_bytes : efx->type->rx_xon_thresh);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_MAC_TH, thresh / 256);
+ thresh = ((rx_xoff_thresh_bytes >= 0) ?
+ rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256);
+ /* RX control FIFO thresholds [32 entries] */
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 25);
+ EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 20);
+ falcon_write(efx, &temp, RX_CFG_REG_KER);
+
+ /* Set destination of both TX and RX Flush events */
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ EFX_POPULATE_OWORD_1(temp, FLS_EVQ_ID, 0);
+ falcon_write(efx, &temp, DP_CTRL_REG);
+ }
+
+ return 0;
+}
+
+void falcon_remove_nic(struct efx_nic *efx)
+{
+ struct falcon_nic_data *nic_data = efx->nic_data;
+
+ falcon_free_buffer(efx, &efx->irq_status);
+
+ (void) falcon_reset_hw(efx, RESET_TYPE_ALL);
+
+ /* Release the second function after the reset */
+ if (nic_data->pci_dev2) {
+ pci_dev_put(nic_data->pci_dev2);
+ nic_data->pci_dev2 = NULL;
+ }
+
+ /* Tear down the private nic state */
+ kfree(efx->nic_data);
+ efx->nic_data = NULL;
+}
+
+void falcon_update_nic_stats(struct efx_nic *efx)
+{
+ efx_oword_t cnt;
+
+ falcon_read(efx, &cnt, RX_NODESC_DROP_REG_KER);
+ efx->n_rx_nodesc_drop_cnt += EFX_OWORD_FIELD(cnt, RX_NODESC_DROP_CNT);
+}
+
+/**************************************************************************
+ *
+ * Revision-dependent attributes used by efx.c
+ *
+ **************************************************************************
+ */
+
+struct efx_nic_type falcon_a_nic_type = {
+ .mem_bar = 2,
+ .mem_map_size = 0x20000,
+ .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_A1,
+ .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_A1,
+ .buf_tbl_base = BUF_TBL_KER_A1,
+ .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_A1,
+ .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_A1,
+ .txd_ring_mask = FALCON_TXD_RING_MASK,
+ .rxd_ring_mask = FALCON_RXD_RING_MASK,
+ .evq_size = FALCON_EVQ_SIZE,
+ .max_dma_mask = FALCON_DMA_MASK,
+ .tx_dma_mask = FALCON_TX_DMA_MASK,
+ .bug5391_mask = 0xf,
+ .rx_xoff_thresh = 2048,
+ .rx_xon_thresh = 512,
+ .rx_buffer_padding = 0x24,
+ .max_interrupt_mode = EFX_INT_MODE_MSI,
+ .phys_addr_channels = 4,
+};
+
+struct efx_nic_type falcon_b_nic_type = {
+ .mem_bar = 2,
+ /* Map everything up to and including the RSS indirection
+ * table. Don't map MSI-X table, MSI-X PBA since Linux
+ * requires that they not be mapped. */
+ .mem_map_size = RX_RSS_INDIR_TBL_B0 + 0x800,
+ .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_B0,
+ .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_B0,
+ .buf_tbl_base = BUF_TBL_KER_B0,
+ .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_B0,
+ .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_B0,
+ .txd_ring_mask = FALCON_TXD_RING_MASK,
+ .rxd_ring_mask = FALCON_RXD_RING_MASK,
+ .evq_size = FALCON_EVQ_SIZE,
+ .max_dma_mask = FALCON_DMA_MASK,
+ .tx_dma_mask = FALCON_TX_DMA_MASK,
+ .bug5391_mask = 0,
+ .rx_xoff_thresh = 54272, /* ~80Kb - 3*max MTU */
+ .rx_xon_thresh = 27648, /* ~3*max MTU */
+ .rx_buffer_padding = 0,
+ .max_interrupt_mode = EFX_INT_MODE_MSIX,
+ .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
+ * interrupt handler only supports 32
+ * channels */
+};
+
diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h
new file mode 100644
index 0000000..6117403
--- /dev/null
+++ b/drivers/net/sfc/falcon.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_FALCON_H
+#define EFX_FALCON_H
+
+#include "net_driver.h"
+
+/*
+ * Falcon hardware control
+ */
+
+enum falcon_revision {
+ FALCON_REV_A0 = 0,
+ FALCON_REV_A1 = 1,
+ FALCON_REV_B0 = 2,
+};
+
+#define FALCON_REV(efx) ((efx)->pci_dev->revision)
+
+extern struct efx_nic_type falcon_a_nic_type;
+extern struct efx_nic_type falcon_b_nic_type;
+
+/**************************************************************************
+ *
+ * Externs
+ *
+ **************************************************************************
+ */
+
+/* TX data path */
+extern int falcon_probe_tx(struct efx_tx_queue *tx_queue);
+extern int falcon_init_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_fini_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_remove_tx(struct efx_tx_queue *tx_queue);
+extern void falcon_push_buffers(struct efx_tx_queue *tx_queue);
+
+/* RX data path */
+extern int falcon_probe_rx(struct efx_rx_queue *rx_queue);
+extern int falcon_init_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_fini_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_remove_rx(struct efx_rx_queue *rx_queue);
+extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue);
+
+/* Event data path */
+extern int falcon_probe_eventq(struct efx_channel *channel);
+extern int falcon_init_eventq(struct efx_channel *channel);
+extern void falcon_fini_eventq(struct efx_channel *channel);
+extern void falcon_remove_eventq(struct efx_channel *channel);
+extern int falcon_process_eventq(struct efx_channel *channel, int *rx_quota);
+extern void falcon_eventq_read_ack(struct efx_channel *channel);
+
+/* Ports */
+extern int falcon_probe_port(struct efx_nic *efx);
+extern void falcon_remove_port(struct efx_nic *efx);
+
+/* MAC/PHY */
+extern int falcon_xaui_link_ok(struct efx_nic *efx);
+extern int falcon_dma_stats(struct efx_nic *efx,
+ unsigned int done_offset);
+extern void falcon_drain_tx_fifo(struct efx_nic *efx);
+extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
+extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
+
+/* Interrupts and test events */
+extern int falcon_init_interrupt(struct efx_nic *efx);
+extern void falcon_enable_interrupts(struct efx_nic *efx);
+extern void falcon_generate_test_event(struct efx_channel *channel,
+ unsigned int magic);
+extern void falcon_generate_interrupt(struct efx_nic *efx);
+extern void falcon_set_int_moderation(struct efx_channel *channel);
+extern void falcon_disable_interrupts(struct efx_nic *efx);
+extern void falcon_fini_interrupt(struct efx_nic *efx);
+
+/* Global Resources */
+extern int falcon_probe_nic(struct efx_nic *efx);
+extern int falcon_probe_resources(struct efx_nic *efx);
+extern int falcon_init_nic(struct efx_nic *efx);
+extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
+extern void falcon_remove_resources(struct efx_nic *efx);
+extern void falcon_remove_nic(struct efx_nic *efx);
+extern void falcon_update_nic_stats(struct efx_nic *efx);
+extern void falcon_set_multicast_hash(struct efx_nic *efx);
+extern int falcon_reset_xaui(struct efx_nic *efx);
+
+/**************************************************************************
+ *
+ * Falcon MAC stats
+ *
+ **************************************************************************
+ */
+
+#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset)
+#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH)
+
+/* Retrieve statistic from statistics block */
+#define FALCON_STAT(efx, falcon_stat, efx_stat) do { \
+ if (FALCON_STAT_WIDTH(falcon_stat) == 16) \
+ (efx)->mac_stats.efx_stat += le16_to_cpu( \
+ *((__force __le16 *) \
+ (efx->stats_buffer.addr + \
+ FALCON_STAT_OFFSET(falcon_stat)))); \
+ else if (FALCON_STAT_WIDTH(falcon_stat) == 32) \
+ (efx)->mac_stats.efx_stat += le32_to_cpu( \
+ *((__force __le32 *) \
+ (efx->stats_buffer.addr + \
+ FALCON_STAT_OFFSET(falcon_stat)))); \
+ else \
+ (efx)->mac_stats.efx_stat += le64_to_cpu( \
+ *((__force __le64 *) \
+ (efx->stats_buffer.addr + \
+ FALCON_STAT_OFFSET(falcon_stat)))); \
+ } while (0)
+
+#define FALCON_MAC_STATS_SIZE 0x100
+
+#define MAC_DATA_LBN 0
+#define MAC_DATA_WIDTH 32
+
+extern void falcon_generate_event(struct efx_channel *channel,
+ efx_qword_t *event);
+
+#endif /* EFX_FALCON_H */
diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h
new file mode 100644
index 0000000..0485a63
--- /dev/null
+++ b/drivers/net/sfc/falcon_hwdefs.h
@@ -0,0 +1,1135 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_FALCON_HWDEFS_H
+#define EFX_FALCON_HWDEFS_H
+
+/*
+ * Falcon hardware value definitions.
+ * Falcon is the internal codename for the SFC4000 controller that is
+ * present in SFE400X evaluation boards
+ */
+
+/**************************************************************************
+ *
+ * Falcon registers
+ *
+ **************************************************************************
+ */
+
+/* Address region register */
+#define ADR_REGION_REG_KER 0x00
+#define ADR_REGION0_LBN 0
+#define ADR_REGION0_WIDTH 18
+#define ADR_REGION1_LBN 32
+#define ADR_REGION1_WIDTH 18
+#define ADR_REGION2_LBN 64
+#define ADR_REGION2_WIDTH 18
+#define ADR_REGION3_LBN 96
+#define ADR_REGION3_WIDTH 18
+
+/* Interrupt enable register */
+#define INT_EN_REG_KER 0x0010
+#define KER_INT_KER_LBN 3
+#define KER_INT_KER_WIDTH 1
+#define DRV_INT_EN_KER_LBN 0
+#define DRV_INT_EN_KER_WIDTH 1
+
+/* Interrupt status address register */
+#define INT_ADR_REG_KER 0x0030
+#define NORM_INT_VEC_DIS_KER_LBN 64
+#define NORM_INT_VEC_DIS_KER_WIDTH 1
+#define INT_ADR_KER_LBN 0
+#define INT_ADR_KER_WIDTH EFX_DMA_TYPE_WIDTH(64) /* not 46 for this one */
+
+/* Interrupt status register (B0 only) */
+#define INT_ISR0_B0 0x90
+#define INT_ISR1_B0 0xA0
+
+/* Interrupt acknowledge register (A0/A1 only) */
+#define INT_ACK_REG_KER_A1 0x0050
+#define INT_ACK_DUMMY_DATA_LBN 0
+#define INT_ACK_DUMMY_DATA_WIDTH 32
+
+/* Interrupt acknowledge work-around register (A0/A1 only )*/
+#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
+
+/* SPI host command register */
+#define EE_SPI_HCMD_REG_KER 0x0100
+#define EE_SPI_HCMD_CMD_EN_LBN 31
+#define EE_SPI_HCMD_CMD_EN_WIDTH 1
+#define EE_WR_TIMER_ACTIVE_LBN 28
+#define EE_WR_TIMER_ACTIVE_WIDTH 1
+#define EE_SPI_HCMD_SF_SEL_LBN 24
+#define EE_SPI_HCMD_SF_SEL_WIDTH 1
+#define EE_SPI_EEPROM 0
+#define EE_SPI_FLASH 1
+#define EE_SPI_HCMD_DABCNT_LBN 16
+#define EE_SPI_HCMD_DABCNT_WIDTH 5
+#define EE_SPI_HCMD_READ_LBN 15
+#define EE_SPI_HCMD_READ_WIDTH 1
+#define EE_SPI_READ 1
+#define EE_SPI_WRITE 0
+#define EE_SPI_HCMD_DUBCNT_LBN 12
+#define EE_SPI_HCMD_DUBCNT_WIDTH 2
+#define EE_SPI_HCMD_ADBCNT_LBN 8
+#define EE_SPI_HCMD_ADBCNT_WIDTH 2
+#define EE_SPI_HCMD_ENC_LBN 0
+#define EE_SPI_HCMD_ENC_WIDTH 8
+
+/* SPI host address register */
+#define EE_SPI_HADR_REG_KER 0x0110
+#define EE_SPI_HADR_ADR_LBN 0
+#define EE_SPI_HADR_ADR_WIDTH 24
+
+/* SPI host data register */
+#define EE_SPI_HDATA_REG_KER 0x0120
+
+/* PCIE CORE ACCESS REG */
+#define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68
+#define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70
+#define PCIE_CORE_ADDR_ACK_RPL_TIMER 0x700
+#define PCIE_CORE_ADDR_ACK_FREQ 0x70C
+
+/* NIC status register */
+#define NIC_STAT_REG 0x0200
+#define ONCHIP_SRAM_LBN 16
+#define ONCHIP_SRAM_WIDTH 1
+#define SF_PRST_LBN 9
+#define SF_PRST_WIDTH 1
+#define EE_PRST_LBN 8
+#define EE_PRST_WIDTH 1
+/* See pic_mode_t for decoding of this field */
+/* These bit definitions are extrapolated from the list of numerical
+ * values for STRAP_PINS.
+ */
+#define STRAP_10G_LBN 2
+#define STRAP_10G_WIDTH 1
+#define STRAP_PCIE_LBN 0
+#define STRAP_PCIE_WIDTH 1
+
+/* GPIO control register */
+#define GPIO_CTL_REG_KER 0x0210
+#define GPIO_OUTPUTS_LBN (16)
+#define GPIO_OUTPUTS_WIDTH (4)
+#define GPIO_INPUTS_LBN (8)
+#define GPIO_DIRECTION_LBN (24)
+#define GPIO_DIRECTION_WIDTH (4)
+#define GPIO_DIRECTION_OUT (1)
+#define GPIO_SRAM_SLEEP (1 << 1)
+
+#define GPIO3_OEN_LBN (GPIO_DIRECTION_LBN + 3)
+#define GPIO3_OEN_WIDTH 1
+#define GPIO2_OEN_LBN (GPIO_DIRECTION_LBN + 2)
+#define GPIO2_OEN_WIDTH 1
+#define GPIO1_OEN_LBN (GPIO_DIRECTION_LBN + 1)
+#define GPIO1_OEN_WIDTH 1
+#define GPIO0_OEN_LBN (GPIO_DIRECTION_LBN + 0)
+#define GPIO0_OEN_WIDTH 1
+
+#define GPIO3_OUT_LBN (GPIO_OUTPUTS_LBN + 3)
+#define GPIO3_OUT_WIDTH 1
+#define GPIO2_OUT_LBN (GPIO_OUTPUTS_LBN + 2)
+#define GPIO2_OUT_WIDTH 1
+#define GPIO1_OUT_LBN (GPIO_OUTPUTS_LBN + 1)
+#define GPIO1_OUT_WIDTH 1
+#define GPIO0_OUT_LBN (GPIO_OUTPUTS_LBN + 0)
+#define GPIO0_OUT_WIDTH 1
+
+#define GPIO3_IN_LBN (GPIO_INPUTS_LBN + 3)
+#define GPIO3_IN_WIDTH 1
+#define GPIO2_IN_WIDTH 1
+#define GPIO1_IN_WIDTH 1
+#define GPIO0_IN_LBN (GPIO_INPUTS_LBN + 0)
+#define GPIO0_IN_WIDTH 1
+
+/* Global control register */
+#define GLB_CTL_REG_KER 0x0220
+#define EXT_PHY_RST_CTL_LBN 63
+#define EXT_PHY_RST_CTL_WIDTH 1
+#define PCIE_SD_RST_CTL_LBN 61
+#define PCIE_SD_RST_CTL_WIDTH 1
+
+#define PCIE_NSTCK_RST_CTL_LBN 58
+#define PCIE_NSTCK_RST_CTL_WIDTH 1
+#define PCIE_CORE_RST_CTL_LBN 57
+#define PCIE_CORE_RST_CTL_WIDTH 1
+#define EE_RST_CTL_LBN 49
+#define EE_RST_CTL_WIDTH 1
+#define RST_XGRX_LBN 24
+#define RST_XGRX_WIDTH 1
+#define RST_XGTX_LBN 23
+#define RST_XGTX_WIDTH 1
+#define RST_EM_LBN 22
+#define RST_EM_WIDTH 1
+#define EXT_PHY_RST_DUR_LBN 1
+#define EXT_PHY_RST_DUR_WIDTH 3
+#define SWRST_LBN 0
+#define SWRST_WIDTH 1
+#define INCLUDE_IN_RESET 0
+#define EXCLUDE_FROM_RESET 1
+
+/* Fatal interrupt register */
+#define FATAL_INTR_REG_KER 0x0230
+#define RBUF_OWN_INT_KER_EN_LBN 39
+#define RBUF_OWN_INT_KER_EN_WIDTH 1
+#define TBUF_OWN_INT_KER_EN_LBN 38
+#define TBUF_OWN_INT_KER_EN_WIDTH 1
+#define ILL_ADR_INT_KER_EN_LBN 33
+#define ILL_ADR_INT_KER_EN_WIDTH 1
+#define MEM_PERR_INT_KER_LBN 8
+#define MEM_PERR_INT_KER_WIDTH 1
+#define INT_KER_ERROR_LBN 0
+#define INT_KER_ERROR_WIDTH 12
+
+#define DP_CTRL_REG 0x250
+#define FLS_EVQ_ID_LBN 0
+#define FLS_EVQ_ID_WIDTH 11
+
+#define MEM_STAT_REG_KER 0x260
+
+/* Debug probe register */
+#define DEBUG_BLK_SEL_MISC 7
+#define DEBUG_BLK_SEL_SERDES 6
+#define DEBUG_BLK_SEL_EM 5
+#define DEBUG_BLK_SEL_SR 4
+#define DEBUG_BLK_SEL_EV 3
+#define DEBUG_BLK_SEL_RX 2
+#define DEBUG_BLK_SEL_TX 1
+#define DEBUG_BLK_SEL_BIU 0
+
+/* FPGA build version */
+#define ALTERA_BUILD_REG_KER 0x0300
+#define VER_ALL_LBN 0
+#define VER_ALL_WIDTH 32
+
+/* Spare EEPROM bits register (flash 0x390) */
+#define SPARE_REG_KER 0x310
+#define MEM_PERR_EN_TX_DATA_LBN 72
+#define MEM_PERR_EN_TX_DATA_WIDTH 2
+
+/* Timer table for kernel access */
+#define TIMER_CMD_REG_KER 0x420
+#define TIMER_MODE_LBN 12
+#define TIMER_MODE_WIDTH 2
+#define TIMER_MODE_DIS 0
+#define TIMER_MODE_INT_HLDOFF 2
+#define TIMER_VAL_LBN 0
+#define TIMER_VAL_WIDTH 12
+
+/* Driver generated event register */
+#define DRV_EV_REG_KER 0x440
+#define DRV_EV_QID_LBN 64
+#define DRV_EV_QID_WIDTH 12
+#define DRV_EV_DATA_LBN 0
+#define DRV_EV_DATA_WIDTH 64
+
+/* Buffer table configuration register */
+#define BUF_TBL_CFG_REG_KER 0x600
+#define BUF_TBL_MODE_LBN 3
+#define BUF_TBL_MODE_WIDTH 1
+#define BUF_TBL_MODE_HALF 0
+#define BUF_TBL_MODE_FULL 1
+
+/* SRAM receive descriptor cache configuration register */
+#define SRM_RX_DC_CFG_REG_KER 0x610
+#define SRM_RX_DC_BASE_ADR_LBN 0
+#define SRM_RX_DC_BASE_ADR_WIDTH 21
+
+/* SRAM transmit descriptor cache configuration register */
+#define SRM_TX_DC_CFG_REG_KER 0x620
+#define SRM_TX_DC_BASE_ADR_LBN 0
+#define SRM_TX_DC_BASE_ADR_WIDTH 21
+
+/* SRAM configuration register */
+#define SRM_CFG_REG_KER 0x630
+#define SRAM_OOB_BT_INIT_EN_LBN 3
+#define SRAM_OOB_BT_INIT_EN_WIDTH 1
+#define SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
+#define SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
+#define SRM_NB_BSZ_1BANKS_2M 0
+#define SRM_NB_BSZ_1BANKS_4M 1
+#define SRM_NB_BSZ_1BANKS_8M 2
+#define SRM_NB_BSZ_DEFAULT 3 /* char driver will set the default */
+#define SRM_NB_BSZ_2BANKS_4M 4
+#define SRM_NB_BSZ_2BANKS_8M 5
+#define SRM_NB_BSZ_2BANKS_16M 6
+#define SRM_NB_BSZ_RESERVED 7
+
+/* Special buffer table update register */
+#define BUF_TBL_UPD_REG_KER 0x0650
+#define BUF_UPD_CMD_LBN 63
+#define BUF_UPD_CMD_WIDTH 1
+#define BUF_CLR_CMD_LBN 62
+#define BUF_CLR_CMD_WIDTH 1
+#define BUF_CLR_END_ID_LBN 32
+#define BUF_CLR_END_ID_WIDTH 20
+#define BUF_CLR_START_ID_LBN 0
+#define BUF_CLR_START_ID_WIDTH 20
+
+/* Receive configuration register */
+#define RX_CFG_REG_KER 0x800
+
+/* B0 */
+#define RX_INGR_EN_B0_LBN 47
+#define RX_INGR_EN_B0_WIDTH 1
+#define RX_DESC_PUSH_EN_B0_LBN 43
+#define RX_DESC_PUSH_EN_B0_WIDTH 1
+#define RX_XON_TX_TH_B0_LBN 33
+#define RX_XON_TX_TH_B0_WIDTH 5
+#define RX_XOFF_TX_TH_B0_LBN 28
+#define RX_XOFF_TX_TH_B0_WIDTH 5
+#define RX_USR_BUF_SIZE_B0_LBN 19
+#define RX_USR_BUF_SIZE_B0_WIDTH 9
+#define RX_XON_MAC_TH_B0_LBN 10
+#define RX_XON_MAC_TH_B0_WIDTH 9
+#define RX_XOFF_MAC_TH_B0_LBN 1
+#define RX_XOFF_MAC_TH_B0_WIDTH 9
+#define RX_XOFF_MAC_EN_B0_LBN 0
+#define RX_XOFF_MAC_EN_B0_WIDTH 1
+
+/* A1 */
+#define RX_DESC_PUSH_EN_A1_LBN 35
+#define RX_DESC_PUSH_EN_A1_WIDTH 1
+#define RX_XON_TX_TH_A1_LBN 25
+#define RX_XON_TX_TH_A1_WIDTH 5
+#define RX_XOFF_TX_TH_A1_LBN 20
+#define RX_XOFF_TX_TH_A1_WIDTH 5
+#define RX_USR_BUF_SIZE_A1_LBN 11
+#define RX_USR_BUF_SIZE_A1_WIDTH 9
+#define RX_XON_MAC_TH_A1_LBN 6
+#define RX_XON_MAC_TH_A1_WIDTH 5
+#define RX_XOFF_MAC_TH_A1_LBN 1
+#define RX_XOFF_MAC_TH_A1_WIDTH 5
+#define RX_XOFF_MAC_EN_A1_LBN 0
+#define RX_XOFF_MAC_EN_A1_WIDTH 1
+
+/* Receive filter control register */
+#define RX_FILTER_CTL_REG 0x810
+#define UDP_FULL_SRCH_LIMIT_LBN 32
+#define UDP_FULL_SRCH_LIMIT_WIDTH 8
+#define NUM_KER_LBN 24
+#define NUM_KER_WIDTH 2
+#define UDP_WILD_SRCH_LIMIT_LBN 16
+#define UDP_WILD_SRCH_LIMIT_WIDTH 8
+#define TCP_WILD_SRCH_LIMIT_LBN 8
+#define TCP_WILD_SRCH_LIMIT_WIDTH 8
+#define TCP_FULL_SRCH_LIMIT_LBN 0
+#define TCP_FULL_SRCH_LIMIT_WIDTH 8
+
+/* RX queue flush register */
+#define RX_FLUSH_DESCQ_REG_KER 0x0820
+#define RX_FLUSH_DESCQ_CMD_LBN 24
+#define RX_FLUSH_DESCQ_CMD_WIDTH 1
+#define RX_FLUSH_DESCQ_LBN 0
+#define RX_FLUSH_DESCQ_WIDTH 12
+
+/* Receive descriptor update register */
+#define RX_DESC_UPD_REG_KER_DWORD (0x830 + 12)
+#define RX_DESC_WPTR_DWORD_LBN 0
+#define RX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Receive descriptor cache configuration register */
+#define RX_DC_CFG_REG_KER 0x840
+#define RX_DC_SIZE_LBN 0
+#define RX_DC_SIZE_WIDTH 2
+
+#define RX_DC_PF_WM_REG_KER 0x850
+#define RX_DC_PF_LWM_LBN 0
+#define RX_DC_PF_LWM_WIDTH 6
+
+/* RX no descriptor drop counter */
+#define RX_NODESC_DROP_REG_KER 0x880
+#define RX_NODESC_DROP_CNT_LBN 0
+#define RX_NODESC_DROP_CNT_WIDTH 16
+
+/* RX black magic register */
+#define RX_SELF_RST_REG_KER 0x890
+#define RX_ISCSI_DIS_LBN 17
+#define RX_ISCSI_DIS_WIDTH 1
+#define RX_NODESC_WAIT_DIS_LBN 9
+#define RX_NODESC_WAIT_DIS_WIDTH 1
+#define RX_RECOVERY_EN_LBN 8
+#define RX_RECOVERY_EN_WIDTH 1
+
+/* TX queue flush register */
+#define TX_FLUSH_DESCQ_REG_KER 0x0a00
+#define TX_FLUSH_DESCQ_CMD_LBN 12
+#define TX_FLUSH_DESCQ_CMD_WIDTH 1
+#define TX_FLUSH_DESCQ_LBN 0
+#define TX_FLUSH_DESCQ_WIDTH 12
+
+/* Transmit descriptor update register */
+#define TX_DESC_UPD_REG_KER_DWORD (0xa10 + 12)
+#define TX_DESC_WPTR_DWORD_LBN 0
+#define TX_DESC_WPTR_DWORD_WIDTH 12
+
+/* Transmit descriptor cache configuration register */
+#define TX_DC_CFG_REG_KER 0xa20
+#define TX_DC_SIZE_LBN 0
+#define TX_DC_SIZE_WIDTH 2
+
+/* Transmit checksum configuration register (A0/A1 only) */
+#define TX_CHKSM_CFG_REG_KER_A1 0xa30
+
+/* Transmit configuration register */
+#define TX_CFG_REG_KER 0xa50
+#define TX_NO_EOP_DISC_EN_LBN 5
+#define TX_NO_EOP_DISC_EN_WIDTH 1
+
+/* Transmit configuration register 2 */
+#define TX_CFG2_REG_KER 0xa80
+#define TX_CSR_PUSH_EN_LBN 89
+#define TX_CSR_PUSH_EN_WIDTH 1
+#define TX_RX_SPACER_LBN 64
+#define TX_RX_SPACER_WIDTH 8
+#define TX_SW_EV_EN_LBN 59
+#define TX_SW_EV_EN_WIDTH 1
+#define TX_RX_SPACER_EN_LBN 57
+#define TX_RX_SPACER_EN_WIDTH 1
+#define TX_PREF_THRESHOLD_LBN 19
+#define TX_PREF_THRESHOLD_WIDTH 2
+#define TX_ONE_PKT_PER_Q_LBN 18
+#define TX_ONE_PKT_PER_Q_WIDTH 1
+#define TX_DIS_NON_IP_EV_LBN 17
+#define TX_DIS_NON_IP_EV_WIDTH 1
+#define TX_FLUSH_MIN_LEN_EN_B0_LBN 7
+#define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1
+
+/* PHY management transmit data register */
+#define MD_TXD_REG_KER 0xc00
+#define MD_TXD_LBN 0
+#define MD_TXD_WIDTH 16
+
+/* PHY management receive data register */
+#define MD_RXD_REG_KER 0xc10
+#define MD_RXD_LBN 0
+#define MD_RXD_WIDTH 16
+
+/* PHY management configuration & status register */
+#define MD_CS_REG_KER 0xc20
+#define MD_GC_LBN 4
+#define MD_GC_WIDTH 1
+#define MD_RIC_LBN 2
+#define MD_RIC_WIDTH 1
+#define MD_RDC_LBN 1
+#define MD_RDC_WIDTH 1
+#define MD_WRC_LBN 0
+#define MD_WRC_WIDTH 1
+
+/* PHY management PHY address register */
+#define MD_PHY_ADR_REG_KER 0xc30
+#define MD_PHY_ADR_LBN 0
+#define MD_PHY_ADR_WIDTH 16
+
+/* PHY management ID register */
+#define MD_ID_REG_KER 0xc40
+#define MD_PRT_ADR_LBN 11
+#define MD_PRT_ADR_WIDTH 5
+#define MD_DEV_ADR_LBN 6
+#define MD_DEV_ADR_WIDTH 5
+/* Used for writing both at once */
+#define MD_PRT_DEV_ADR_LBN 6
+#define MD_PRT_DEV_ADR_WIDTH 10
+
+/* PHY management status & mask register (DWORD read only) */
+#define MD_STAT_REG_KER 0xc50
+#define MD_BSERR_LBN 2
+#define MD_BSERR_WIDTH 1
+#define MD_LNFL_LBN 1
+#define MD_LNFL_WIDTH 1
+#define MD_BSY_LBN 0
+#define MD_BSY_WIDTH 1
+
+/* Port 0 and 1 MAC stats registers */
+#define MAC0_STAT_DMA_REG_KER 0xc60
+#define MAC_STAT_DMA_CMD_LBN 48
+#define MAC_STAT_DMA_CMD_WIDTH 1
+#define MAC_STAT_DMA_ADR_LBN 0
+#define MAC_STAT_DMA_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
+
+/* Port 0 and 1 MAC control registers */
+#define MAC0_CTRL_REG_KER 0xc80
+#define MAC_XOFF_VAL_LBN 16
+#define MAC_XOFF_VAL_WIDTH 16
+#define TXFIFO_DRAIN_EN_B0_LBN 7
+#define TXFIFO_DRAIN_EN_B0_WIDTH 1
+#define MAC_BCAD_ACPT_LBN 4
+#define MAC_BCAD_ACPT_WIDTH 1
+#define MAC_UC_PROM_LBN 3
+#define MAC_UC_PROM_WIDTH 1
+#define MAC_LINK_STATUS_LBN 2
+#define MAC_LINK_STATUS_WIDTH 1
+#define MAC_SPEED_LBN 0
+#define MAC_SPEED_WIDTH 2
+
+/* 10G XAUI XGXS default values */
+#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
+#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
+#define XX_SD_CTL_DRV_DEFAULT 0 /* 20mA */
+
+/* Multicast address hash table */
+#define MAC_MCAST_HASH_REG0_KER 0xca0
+#define MAC_MCAST_HASH_REG1_KER 0xcb0
+
+/* GMAC registers */
+#define FALCON_GMAC_REGBANK 0xe00
+#define FALCON_GMAC_REGBANK_SIZE 0x200
+#define FALCON_GMAC_REG_SIZE 0x10
+
+/* XMAC registers */
+#define FALCON_XMAC_REGBANK 0x1200
+#define FALCON_XMAC_REGBANK_SIZE 0x200
+#define FALCON_XMAC_REG_SIZE 0x10
+
+/* XGMAC address register low */
+#define XM_ADR_LO_REG_MAC 0x00
+#define XM_ADR_3_LBN 24
+#define XM_ADR_3_WIDTH 8
+#define XM_ADR_2_LBN 16
+#define XM_ADR_2_WIDTH 8
+#define XM_ADR_1_LBN 8
+#define XM_ADR_1_WIDTH 8
+#define XM_ADR_0_LBN 0
+#define XM_ADR_0_WIDTH 8
+
+/* XGMAC address register high */
+#define XM_ADR_HI_REG_MAC 0x01
+#define XM_ADR_5_LBN 8
+#define XM_ADR_5_WIDTH 8
+#define XM_ADR_4_LBN 0
+#define XM_ADR_4_WIDTH 8
+
+/* XGMAC global configuration */
+#define XM_GLB_CFG_REG_MAC 0x02
+#define XM_RX_STAT_EN_LBN 11
+#define XM_RX_STAT_EN_WIDTH 1
+#define XM_TX_STAT_EN_LBN 10
+#define XM_TX_STAT_EN_WIDTH 1
+#define XM_RX_JUMBO_MODE_LBN 6
+#define XM_RX_JUMBO_MODE_WIDTH 1
+#define XM_INTCLR_MODE_LBN 3
+#define XM_INTCLR_MODE_WIDTH 1
+#define XM_CORE_RST_LBN 0
+#define XM_CORE_RST_WIDTH 1
+
+/* XGMAC transmit configuration */
+#define XM_TX_CFG_REG_MAC 0x03
+#define XM_IPG_LBN 16
+#define XM_IPG_WIDTH 4
+#define XM_FCNTL_LBN 10
+#define XM_FCNTL_WIDTH 1
+#define XM_TXCRC_LBN 8
+#define XM_TXCRC_WIDTH 1
+#define XM_AUTO_PAD_LBN 5
+#define XM_AUTO_PAD_WIDTH 1
+#define XM_TX_PRMBL_LBN 2
+#define XM_TX_PRMBL_WIDTH 1
+#define XM_TXEN_LBN 1
+#define XM_TXEN_WIDTH 1
+
+/* XGMAC receive configuration */
+#define XM_RX_CFG_REG_MAC 0x04
+#define XM_PASS_CRC_ERR_LBN 25
+#define XM_PASS_CRC_ERR_WIDTH 1
+#define XM_ACPT_ALL_MCAST_LBN 11
+#define XM_ACPT_ALL_MCAST_WIDTH 1
+#define XM_ACPT_ALL_UCAST_LBN 9
+#define XM_ACPT_ALL_UCAST_WIDTH 1
+#define XM_AUTO_DEPAD_LBN 8
+#define XM_AUTO_DEPAD_WIDTH 1
+#define XM_RXEN_LBN 1
+#define XM_RXEN_WIDTH 1
+
+/* XGMAC management interrupt mask register */
+#define XM_MGT_INT_MSK_REG_MAC_B0 0x5
+#define XM_MSK_PRMBLE_ERR_LBN 2
+#define XM_MSK_PRMBLE_ERR_WIDTH 1
+#define XM_MSK_RMTFLT_LBN 1
+#define XM_MSK_RMTFLT_WIDTH 1
+#define XM_MSK_LCLFLT_LBN 0
+#define XM_MSK_LCLFLT_WIDTH 1
+
+/* XGMAC flow control register */
+#define XM_FC_REG_MAC 0x7
+#define XM_PAUSE_TIME_LBN 16
+#define XM_PAUSE_TIME_WIDTH 16
+#define XM_DIS_FCNTL_LBN 0
+#define XM_DIS_FCNTL_WIDTH 1
+
+/* XGMAC pause time count register */
+#define XM_PAUSE_TIME_REG_MAC 0x9
+
+/* XGMAC transmit parameter register */
+#define XM_TX_PARAM_REG_MAC 0x0d
+#define XM_TX_JUMBO_MODE_LBN 31
+#define XM_TX_JUMBO_MODE_WIDTH 1
+#define XM_MAX_TX_FRM_SIZE_LBN 16
+#define XM_MAX_TX_FRM_SIZE_WIDTH 14
+
+/* XGMAC receive parameter register */
+#define XM_RX_PARAM_REG_MAC 0x0e
+#define XM_MAX_RX_FRM_SIZE_LBN 0
+#define XM_MAX_RX_FRM_SIZE_WIDTH 14
+
+/* XGMAC management interrupt status register */
+#define XM_MGT_INT_REG_MAC_B0 0x0f
+#define XM_PRMBLE_ERR 2
+#define XM_PRMBLE_WIDTH 1
+#define XM_RMTFLT_LBN 1
+#define XM_RMTFLT_WIDTH 1
+#define XM_LCLFLT_LBN 0
+#define XM_LCLFLT_WIDTH 1
+
+/* XGXS/XAUI powerdown/reset register */
+#define XX_PWR_RST_REG_MAC 0x10
+
+#define XX_PWRDND_EN_LBN 15
+#define XX_PWRDND_EN_WIDTH 1
+#define XX_PWRDNC_EN_LBN 14
+#define XX_PWRDNC_EN_WIDTH 1
+#define XX_PWRDNB_EN_LBN 13
+#define XX_PWRDNB_EN_WIDTH 1
+#define XX_PWRDNA_EN_LBN 12
+#define XX_PWRDNA_EN_WIDTH 1
+#define XX_RSTPLLCD_EN_LBN 9
+#define XX_RSTPLLCD_EN_WIDTH 1
+#define XX_RSTPLLAB_EN_LBN 8
+#define XX_RSTPLLAB_EN_WIDTH 1
+#define XX_RESETD_EN_LBN 7
+#define XX_RESETD_EN_WIDTH 1
+#define XX_RESETC_EN_LBN 6
+#define XX_RESETC_EN_WIDTH 1
+#define XX_RESETB_EN_LBN 5
+#define XX_RESETB_EN_WIDTH 1
+#define XX_RESETA_EN_LBN 4
+#define XX_RESETA_EN_WIDTH 1
+#define XX_RSTXGXSRX_EN_LBN 2
+#define XX_RSTXGXSRX_EN_WIDTH 1
+#define XX_RSTXGXSTX_EN_LBN 1
+#define XX_RSTXGXSTX_EN_WIDTH 1
+#define XX_RST_XX_EN_LBN 0
+#define XX_RST_XX_EN_WIDTH 1
+
+/* XGXS/XAUI powerdown/reset control register */
+#define XX_SD_CTL_REG_MAC 0x11
+#define XX_HIDRVD_LBN 15
+#define XX_HIDRVD_WIDTH 1
+#define XX_LODRVD_LBN 14
+#define XX_LODRVD_WIDTH 1
+#define XX_HIDRVC_LBN 13
+#define XX_HIDRVC_WIDTH 1
+#define XX_LODRVC_LBN 12
+#define XX_LODRVC_WIDTH 1
+#define XX_HIDRVB_LBN 11
+#define XX_HIDRVB_WIDTH 1
+#define XX_LODRVB_LBN 10
+#define XX_LODRVB_WIDTH 1
+#define XX_HIDRVA_LBN 9
+#define XX_HIDRVA_WIDTH 1
+#define XX_LODRVA_LBN 8
+#define XX_LODRVA_WIDTH 1
+
+#define XX_TXDRV_CTL_REG_MAC 0x12
+#define XX_DEQD_LBN 28
+#define XX_DEQD_WIDTH 4
+#define XX_DEQC_LBN 24
+#define XX_DEQC_WIDTH 4
+#define XX_DEQB_LBN 20
+#define XX_DEQB_WIDTH 4
+#define XX_DEQA_LBN 16
+#define XX_DEQA_WIDTH 4
+#define XX_DTXD_LBN 12
+#define XX_DTXD_WIDTH 4
+#define XX_DTXC_LBN 8
+#define XX_DTXC_WIDTH 4
+#define XX_DTXB_LBN 4
+#define XX_DTXB_WIDTH 4
+#define XX_DTXA_LBN 0
+#define XX_DTXA_WIDTH 4
+
+/* XAUI XGXS core status register */
+#define XX_FORCE_SIG_DECODE_FORCED 0xff
+#define XX_CORE_STAT_REG_MAC 0x16
+#define XX_ALIGN_DONE_LBN 20
+#define XX_ALIGN_DONE_WIDTH 1
+#define XX_SYNC_STAT_LBN 16
+#define XX_SYNC_STAT_WIDTH 4
+#define XX_SYNC_STAT_DECODE_SYNCED 0xf
+#define XX_COMMA_DET_LBN 12
+#define XX_COMMA_DET_WIDTH 4
+#define XX_COMMA_DET_DECODE_DETECTED 0xf
+#define XX_COMMA_DET_RESET 0xf
+#define XX_CHARERR_LBN 4
+#define XX_CHARERR_WIDTH 4
+#define XX_CHARERR_RESET 0xf
+#define XX_DISPERR_LBN 0
+#define XX_DISPERR_WIDTH 4
+#define XX_DISPERR_RESET 0xf
+
+/* Receive filter table */
+#define RX_FILTER_TBL0 0xF00000
+
+/* Receive descriptor pointer table */
+#define RX_DESC_PTR_TBL_KER_A1 0x11800
+#define RX_DESC_PTR_TBL_KER_B0 0xF40000
+#define RX_DESC_PTR_TBL_KER_P0 0x900
+#define RX_ISCSI_DDIG_EN_LBN 88
+#define RX_ISCSI_DDIG_EN_WIDTH 1
+#define RX_ISCSI_HDIG_EN_LBN 87
+#define RX_ISCSI_HDIG_EN_WIDTH 1
+#define RX_DESCQ_BUF_BASE_ID_LBN 36
+#define RX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define RX_DESCQ_EVQ_ID_LBN 24
+#define RX_DESCQ_EVQ_ID_WIDTH 12
+#define RX_DESCQ_OWNER_ID_LBN 10
+#define RX_DESCQ_OWNER_ID_WIDTH 14
+#define RX_DESCQ_LABEL_LBN 5
+#define RX_DESCQ_LABEL_WIDTH 5
+#define RX_DESCQ_SIZE_LBN 3
+#define RX_DESCQ_SIZE_WIDTH 2
+#define RX_DESCQ_SIZE_4K 3
+#define RX_DESCQ_SIZE_2K 2
+#define RX_DESCQ_SIZE_1K 1
+#define RX_DESCQ_SIZE_512 0
+#define RX_DESCQ_TYPE_LBN 2
+#define RX_DESCQ_TYPE_WIDTH 1
+#define RX_DESCQ_JUMBO_LBN 1
+#define RX_DESCQ_JUMBO_WIDTH 1
+#define RX_DESCQ_EN_LBN 0
+#define RX_DESCQ_EN_WIDTH 1
+
+/* Transmit descriptor pointer table */
+#define TX_DESC_PTR_TBL_KER_A1 0x11900
+#define TX_DESC_PTR_TBL_KER_B0 0xF50000
+#define TX_DESC_PTR_TBL_KER_P0 0xa40
+#define TX_NON_IP_DROP_DIS_B0_LBN 91
+#define TX_NON_IP_DROP_DIS_B0_WIDTH 1
+#define TX_IP_CHKSM_DIS_B0_LBN 90
+#define TX_IP_CHKSM_DIS_B0_WIDTH 1
+#define TX_TCP_CHKSM_DIS_B0_LBN 89
+#define TX_TCP_CHKSM_DIS_B0_WIDTH 1
+#define TX_DESCQ_EN_LBN 88
+#define TX_DESCQ_EN_WIDTH 1
+#define TX_ISCSI_DDIG_EN_LBN 87
+#define TX_ISCSI_DDIG_EN_WIDTH 1
+#define TX_ISCSI_HDIG_EN_LBN 86
+#define TX_ISCSI_HDIG_EN_WIDTH 1
+#define TX_DESCQ_BUF_BASE_ID_LBN 36
+#define TX_DESCQ_BUF_BASE_ID_WIDTH 20
+#define TX_DESCQ_EVQ_ID_LBN 24
+#define TX_DESCQ_EVQ_ID_WIDTH 12
+#define TX_DESCQ_OWNER_ID_LBN 10
+#define TX_DESCQ_OWNER_ID_WIDTH 14
+#define TX_DESCQ_LABEL_LBN 5
+#define TX_DESCQ_LABEL_WIDTH 5
+#define TX_DESCQ_SIZE_LBN 3
+#define TX_DESCQ_SIZE_WIDTH 2
+#define TX_DESCQ_SIZE_4K 3
+#define TX_DESCQ_SIZE_2K 2
+#define TX_DESCQ_SIZE_1K 1
+#define TX_DESCQ_SIZE_512 0
+#define TX_DESCQ_TYPE_LBN 1
+#define TX_DESCQ_TYPE_WIDTH 2
+
+/* Event queue pointer */
+#define EVQ_PTR_TBL_KER_A1 0x11a00
+#define EVQ_PTR_TBL_KER_B0 0xf60000
+#define EVQ_PTR_TBL_KER_P0 0x500
+#define EVQ_EN_LBN 23
+#define EVQ_EN_WIDTH 1
+#define EVQ_SIZE_LBN 20
+#define EVQ_SIZE_WIDTH 3
+#define EVQ_SIZE_32K 6
+#define EVQ_SIZE_16K 5
+#define EVQ_SIZE_8K 4
+#define EVQ_SIZE_4K 3
+#define EVQ_SIZE_2K 2
+#define EVQ_SIZE_1K 1
+#define EVQ_SIZE_512 0
+#define EVQ_BUF_BASE_ID_LBN 0
+#define EVQ_BUF_BASE_ID_WIDTH 20
+
+/* Event queue read pointer */
+#define EVQ_RPTR_REG_KER_A1 0x11b00
+#define EVQ_RPTR_REG_KER_B0 0xfa0000
+#define EVQ_RPTR_REG_KER_DWORD (EVQ_RPTR_REG_KER + 0)
+#define EVQ_RPTR_DWORD_LBN 0
+#define EVQ_RPTR_DWORD_WIDTH 14
+
+/* RSS indirection table */
+#define RX_RSS_INDIR_TBL_B0 0xFB0000
+#define RX_RSS_INDIR_ENT_B0_LBN 0
+#define RX_RSS_INDIR_ENT_B0_WIDTH 6
+
+/* Special buffer descriptors (full-mode) */
+#define BUF_FULL_TBL_KER_A1 0x8000
+#define BUF_FULL_TBL_KER_B0 0x800000
+#define IP_DAT_BUF_SIZE_LBN 50
+#define IP_DAT_BUF_SIZE_WIDTH 1
+#define IP_DAT_BUF_SIZE_8K 1
+#define IP_DAT_BUF_SIZE_4K 0
+#define BUF_ADR_REGION_LBN 48
+#define BUF_ADR_REGION_WIDTH 2
+#define BUF_ADR_FBUF_LBN 14
+#define BUF_ADR_FBUF_WIDTH 34
+#define BUF_OWNER_ID_FBUF_LBN 0
+#define BUF_OWNER_ID_FBUF_WIDTH 14
+
+/* Transmit descriptor */
+#define TX_KER_PORT_LBN 63
+#define TX_KER_PORT_WIDTH 1
+#define TX_KER_CONT_LBN 62
+#define TX_KER_CONT_WIDTH 1
+#define TX_KER_BYTE_CNT_LBN 48
+#define TX_KER_BYTE_CNT_WIDTH 14
+#define TX_KER_BUF_REGION_LBN 46
+#define TX_KER_BUF_REGION_WIDTH 2
+#define TX_KER_BUF_REGION0_DECODE 0
+#define TX_KER_BUF_REGION1_DECODE 1
+#define TX_KER_BUF_REGION2_DECODE 2
+#define TX_KER_BUF_REGION3_DECODE 3
+#define TX_KER_BUF_ADR_LBN 0
+#define TX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
+
+/* Receive descriptor */
+#define RX_KER_BUF_SIZE_LBN 48
+#define RX_KER_BUF_SIZE_WIDTH 14
+#define RX_KER_BUF_REGION_LBN 46
+#define RX_KER_BUF_REGION_WIDTH 2
+#define RX_KER_BUF_REGION0_DECODE 0
+#define RX_KER_BUF_REGION1_DECODE 1
+#define RX_KER_BUF_REGION2_DECODE 2
+#define RX_KER_BUF_REGION3_DECODE 3
+#define RX_KER_BUF_ADR_LBN 0
+#define RX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
+
+/**************************************************************************
+ *
+ * Falcon events
+ *
+ **************************************************************************
+ */
+
+/* Event queue entries */
+#define EV_CODE_LBN 60
+#define EV_CODE_WIDTH 4
+#define RX_IP_EV_DECODE 0
+#define TX_IP_EV_DECODE 2
+#define DRIVER_EV_DECODE 5
+#define GLOBAL_EV_DECODE 6
+#define DRV_GEN_EV_DECODE 7
+#define WHOLE_EVENT_LBN 0
+#define WHOLE_EVENT_WIDTH 64
+
+/* Receive events */
+#define RX_EV_PKT_OK_LBN 56
+#define RX_EV_PKT_OK_WIDTH 1
+#define RX_EV_PAUSE_FRM_ERR_LBN 55
+#define RX_EV_PAUSE_FRM_ERR_WIDTH 1
+#define RX_EV_BUF_OWNER_ID_ERR_LBN 54
+#define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
+#define RX_EV_IF_FRAG_ERR_LBN 53
+#define RX_EV_IF_FRAG_ERR_WIDTH 1
+#define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
+#define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
+#define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
+#define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
+#define RX_EV_ETH_CRC_ERR_LBN 50
+#define RX_EV_ETH_CRC_ERR_WIDTH 1
+#define RX_EV_FRM_TRUNC_LBN 49
+#define RX_EV_FRM_TRUNC_WIDTH 1
+#define RX_EV_DRIB_NIB_LBN 48
+#define RX_EV_DRIB_NIB_WIDTH 1
+#define RX_EV_TOBE_DISC_LBN 47
+#define RX_EV_TOBE_DISC_WIDTH 1
+#define RX_EV_PKT_TYPE_LBN 44
+#define RX_EV_PKT_TYPE_WIDTH 3
+#define RX_EV_PKT_TYPE_ETH_DECODE 0
+#define RX_EV_PKT_TYPE_LLC_DECODE 1
+#define RX_EV_PKT_TYPE_JUMBO_DECODE 2
+#define RX_EV_PKT_TYPE_VLAN_DECODE 3
+#define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4
+#define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5
+#define RX_EV_HDR_TYPE_LBN 42
+#define RX_EV_HDR_TYPE_WIDTH 2
+#define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0
+#define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1
+#define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2
+#define RX_EV_HDR_TYPE_NON_IP_DECODE 3
+#define RX_EV_HDR_TYPE_HAS_CHECKSUMS(hdr_type) \
+ ((hdr_type) <= RX_EV_HDR_TYPE_UDP_IPV4_DECODE)
+#define RX_EV_MCAST_HASH_MATCH_LBN 40
+#define RX_EV_MCAST_HASH_MATCH_WIDTH 1
+#define RX_EV_MCAST_PKT_LBN 39
+#define RX_EV_MCAST_PKT_WIDTH 1
+#define RX_EV_Q_LABEL_LBN 32
+#define RX_EV_Q_LABEL_WIDTH 5
+#define RX_EV_JUMBO_CONT_LBN 31
+#define RX_EV_JUMBO_CONT_WIDTH 1
+#define RX_EV_BYTE_CNT_LBN 16
+#define RX_EV_BYTE_CNT_WIDTH 14
+#define RX_EV_SOP_LBN 15
+#define RX_EV_SOP_WIDTH 1
+#define RX_EV_DESC_PTR_LBN 0
+#define RX_EV_DESC_PTR_WIDTH 12
+
+/* Transmit events */
+#define TX_EV_PKT_ERR_LBN 38
+#define TX_EV_PKT_ERR_WIDTH 1
+#define TX_EV_Q_LABEL_LBN 32
+#define TX_EV_Q_LABEL_WIDTH 5
+#define TX_EV_WQ_FF_FULL_LBN 15
+#define TX_EV_WQ_FF_FULL_WIDTH 1
+#define TX_EV_COMP_LBN 12
+#define TX_EV_COMP_WIDTH 1
+#define TX_EV_DESC_PTR_LBN 0
+#define TX_EV_DESC_PTR_WIDTH 12
+
+/* Driver events */
+#define DRIVER_EV_SUB_CODE_LBN 56
+#define DRIVER_EV_SUB_CODE_WIDTH 4
+#define DRIVER_EV_SUB_DATA_LBN 0
+#define DRIVER_EV_SUB_DATA_WIDTH 14
+#define TX_DESCQ_FLS_DONE_EV_DECODE 0
+#define RX_DESCQ_FLS_DONE_EV_DECODE 1
+#define EVQ_INIT_DONE_EV_DECODE 2
+#define EVQ_NOT_EN_EV_DECODE 3
+#define RX_DESCQ_FLSFF_OVFL_EV_DECODE 4
+#define SRM_UPD_DONE_EV_DECODE 5
+#define WAKE_UP_EV_DECODE 6
+#define TX_PKT_NON_TCP_UDP_DECODE 9
+#define TIMER_EV_DECODE 10
+#define RX_RECOVERY_EV_DECODE 11
+#define RX_DSC_ERROR_EV_DECODE 14
+#define TX_DSC_ERROR_EV_DECODE 15
+#define DRIVER_EV_TX_DESCQ_ID_LBN 0
+#define DRIVER_EV_TX_DESCQ_ID_WIDTH 12
+#define DRIVER_EV_RX_FLUSH_FAIL_LBN 12
+#define DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1
+#define DRIVER_EV_RX_DESCQ_ID_LBN 0
+#define DRIVER_EV_RX_DESCQ_ID_WIDTH 12
+#define SRM_CLR_EV_DECODE 0
+#define SRM_UPD_EV_DECODE 1
+#define SRM_ILLCLR_EV_DECODE 2
+
+/* Global events */
+#define RX_RECOVERY_B0_LBN 12
+#define RX_RECOVERY_B0_WIDTH 1
+#define XG_MNT_INTR_B0_LBN 11
+#define XG_MNT_INTR_B0_WIDTH 1
+#define RX_RECOVERY_A1_LBN 11
+#define RX_RECOVERY_A1_WIDTH 1
+#define XG_PHY_INTR_LBN 9
+#define XG_PHY_INTR_WIDTH 1
+#define G_PHY1_INTR_LBN 8
+#define G_PHY1_INTR_WIDTH 1
+#define G_PHY0_INTR_LBN 7
+#define G_PHY0_INTR_WIDTH 1
+
+/* Driver-generated test events */
+#define EVQ_MAGIC_LBN 0
+#define EVQ_MAGIC_WIDTH 32
+
+/**************************************************************************
+ *
+ * Falcon MAC stats
+ *
+ **************************************************************************
+ *
+ */
+#define GRxGoodOct_offset 0x0
+#define GRxBadOct_offset 0x8
+#define GRxMissPkt_offset 0x10
+#define GRxFalseCRS_offset 0x14
+#define GRxPausePkt_offset 0x18
+#define GRxBadPkt_offset 0x1C
+#define GRxUcastPkt_offset 0x20
+#define GRxMcastPkt_offset 0x24
+#define GRxBcastPkt_offset 0x28
+#define GRxGoodLt64Pkt_offset 0x2C
+#define GRxBadLt64Pkt_offset 0x30
+#define GRx64Pkt_offset 0x34
+#define GRx65to127Pkt_offset 0x38
+#define GRx128to255Pkt_offset 0x3C
+#define GRx256to511Pkt_offset 0x40
+#define GRx512to1023Pkt_offset 0x44
+#define GRx1024to15xxPkt_offset 0x48
+#define GRx15xxtoJumboPkt_offset 0x4C
+#define GRxGtJumboPkt_offset 0x50
+#define GRxFcsErr64to15xxPkt_offset 0x54
+#define GRxFcsErr15xxtoJumboPkt_offset 0x58
+#define GRxFcsErrGtJumboPkt_offset 0x5C
+#define GTxGoodBadOct_offset 0x80
+#define GTxGoodOct_offset 0x88
+#define GTxSglColPkt_offset 0x90
+#define GTxMultColPkt_offset 0x94
+#define GTxExColPkt_offset 0x98
+#define GTxDefPkt_offset 0x9C
+#define GTxLateCol_offset 0xA0
+#define GTxExDefPkt_offset 0xA4
+#define GTxPausePkt_offset 0xA8
+#define GTxBadPkt_offset 0xAC
+#define GTxUcastPkt_offset 0xB0
+#define GTxMcastPkt_offset 0xB4
+#define GTxBcastPkt_offset 0xB8
+#define GTxLt64Pkt_offset 0xBC
+#define GTx64Pkt_offset 0xC0
+#define GTx65to127Pkt_offset 0xC4
+#define GTx128to255Pkt_offset 0xC8
+#define GTx256to511Pkt_offset 0xCC
+#define GTx512to1023Pkt_offset 0xD0
+#define GTx1024to15xxPkt_offset 0xD4
+#define GTx15xxtoJumboPkt_offset 0xD8
+#define GTxGtJumboPkt_offset 0xDC
+#define GTxNonTcpUdpPkt_offset 0xE0
+#define GTxMacSrcErrPkt_offset 0xE4
+#define GTxIpSrcErrPkt_offset 0xE8
+#define GDmaDone_offset 0xEC
+
+#define XgRxOctets_offset 0x0
+#define XgRxOctets_WIDTH 48
+#define XgRxOctetsOK_offset 0x8
+#define XgRxOctetsOK_WIDTH 48
+#define XgRxPkts_offset 0x10
+#define XgRxPkts_WIDTH 32
+#define XgRxPktsOK_offset 0x14
+#define XgRxPktsOK_WIDTH 32
+#define XgRxBroadcastPkts_offset 0x18
+#define XgRxBroadcastPkts_WIDTH 32
+#define XgRxMulticastPkts_offset 0x1C
+#define XgRxMulticastPkts_WIDTH 32
+#define XgRxUnicastPkts_offset 0x20
+#define XgRxUnicastPkts_WIDTH 32
+#define XgRxUndersizePkts_offset 0x24
+#define XgRxUndersizePkts_WIDTH 32
+#define XgRxOversizePkts_offset 0x28
+#define XgRxOversizePkts_WIDTH 32
+#define XgRxJabberPkts_offset 0x2C
+#define XgRxJabberPkts_WIDTH 32
+#define XgRxUndersizeFCSerrorPkts_offset 0x30
+#define XgRxUndersizeFCSerrorPkts_WIDTH 32
+#define XgRxDropEvents_offset 0x34
+#define XgRxDropEvents_WIDTH 32
+#define XgRxFCSerrorPkts_offset 0x38
+#define XgRxFCSerrorPkts_WIDTH 32
+#define XgRxAlignError_offset 0x3C
+#define XgRxAlignError_WIDTH 32
+#define XgRxSymbolError_offset 0x40
+#define XgRxSymbolError_WIDTH 32
+#define XgRxInternalMACError_offset 0x44
+#define XgRxInternalMACError_WIDTH 32
+#define XgRxControlPkts_offset 0x48
+#define XgRxControlPkts_WIDTH 32
+#define XgRxPausePkts_offset 0x4C
+#define XgRxPausePkts_WIDTH 32
+#define XgRxPkts64Octets_offset 0x50
+#define XgRxPkts64Octets_WIDTH 32
+#define XgRxPkts65to127Octets_offset 0x54
+#define XgRxPkts65to127Octets_WIDTH 32
+#define XgRxPkts128to255Octets_offset 0x58
+#define XgRxPkts128to255Octets_WIDTH 32
+#define XgRxPkts256to511Octets_offset 0x5C
+#define XgRxPkts256to511Octets_WIDTH 32
+#define XgRxPkts512to1023Octets_offset 0x60
+#define XgRxPkts512to1023Octets_WIDTH 32
+#define XgRxPkts1024to15xxOctets_offset 0x64
+#define XgRxPkts1024to15xxOctets_WIDTH 32
+#define XgRxPkts15xxtoMaxOctets_offset 0x68
+#define XgRxPkts15xxtoMaxOctets_WIDTH 32
+#define XgRxLengthError_offset 0x6C
+#define XgRxLengthError_WIDTH 32
+#define XgTxPkts_offset 0x80
+#define XgTxPkts_WIDTH 32
+#define XgTxOctets_offset 0x88
+#define XgTxOctets_WIDTH 48
+#define XgTxMulticastPkts_offset 0x90
+#define XgTxMulticastPkts_WIDTH 32
+#define XgTxBroadcastPkts_offset 0x94
+#define XgTxBroadcastPkts_WIDTH 32
+#define XgTxUnicastPkts_offset 0x98
+#define XgTxUnicastPkts_WIDTH 32
+#define XgTxControlPkts_offset 0x9C
+#define XgTxControlPkts_WIDTH 32
+#define XgTxPausePkts_offset 0xA0
+#define XgTxPausePkts_WIDTH 32
+#define XgTxPkts64Octets_offset 0xA4
+#define XgTxPkts64Octets_WIDTH 32
+#define XgTxPkts65to127Octets_offset 0xA8
+#define XgTxPkts65to127Octets_WIDTH 32
+#define XgTxPkts128to255Octets_offset 0xAC
+#define XgTxPkts128to255Octets_WIDTH 32
+#define XgTxPkts256to511Octets_offset 0xB0
+#define XgTxPkts256to511Octets_WIDTH 32
+#define XgTxPkts512to1023Octets_offset 0xB4
+#define XgTxPkts512to1023Octets_WIDTH 32
+#define XgTxPkts1024to15xxOctets_offset 0xB8
+#define XgTxPkts1024to15xxOctets_WIDTH 32
+#define XgTxPkts1519toMaxOctets_offset 0xBC
+#define XgTxPkts1519toMaxOctets_WIDTH 32
+#define XgTxUndersizePkts_offset 0xC0
+#define XgTxUndersizePkts_WIDTH 32
+#define XgTxOversizePkts_offset 0xC4
+#define XgTxOversizePkts_WIDTH 32
+#define XgTxNonTcpUdpPkt_offset 0xC8
+#define XgTxNonTcpUdpPkt_WIDTH 16
+#define XgTxMacSrcErrPkt_offset 0xCC
+#define XgTxMacSrcErrPkt_WIDTH 16
+#define XgTxIpSrcErrPkt_offset 0xD0
+#define XgTxIpSrcErrPkt_WIDTH 16
+#define XgDmaDone_offset 0xD4
+
+#define FALCON_STATS_NOT_DONE 0x00000000
+#define FALCON_STATS_DONE 0xffffffff
+
+/* Interrupt status register bits */
+#define FATAL_INT_LBN 64
+#define FATAL_INT_WIDTH 1
+#define INT_EVQS_LBN 40
+#define INT_EVQS_WIDTH 4
+
+/**************************************************************************
+ *
+ * Falcon non-volatile configuration
+ *
+ **************************************************************************
+ */
+
+/* Board configuration v2 (v1 is obsolete; later versions are compatible) */
+struct falcon_nvconfig_board_v2 {
+ __le16 nports;
+ u8 port0_phy_addr;
+ u8 port0_phy_type;
+ u8 port1_phy_addr;
+ u8 port1_phy_type;
+ __le16 asic_sub_revision;
+ __le16 board_revision;
+} __attribute__ ((packed));
+
+#define NVCONFIG_BASE 0x300
+#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
+struct falcon_nvconfig {
+ efx_oword_t ee_vpd_cfg_reg; /* 0x300 */
+ u8 mac_address[2][8]; /* 0x310 */
+ efx_oword_t pcie_sd_ctl0123_reg; /* 0x320 */
+ efx_oword_t pcie_sd_ctl45_reg; /* 0x330 */
+ efx_oword_t pcie_pcs_ctl_stat_reg; /* 0x340 */
+ efx_oword_t hw_init_reg; /* 0x350 */
+ efx_oword_t nic_stat_reg; /* 0x360 */
+ efx_oword_t glb_ctl_reg; /* 0x370 */
+ efx_oword_t srm_cfg_reg; /* 0x380 */
+ efx_oword_t spare_reg; /* 0x390 */
+ __le16 board_magic_num; /* 0x3A0 */
+ __le16 board_struct_ver;
+ __le16 board_checksum;
+ struct falcon_nvconfig_board_v2 board_v2;
+} __attribute__ ((packed));
+
+#endif /* EFX_FALCON_HWDEFS_H */
diff --git a/drivers/net/sfc/falcon_io.h b/drivers/net/sfc/falcon_io.h
new file mode 100644
index 0000000..ea08184
--- /dev/null
+++ b/drivers/net/sfc/falcon_io.h
@@ -0,0 +1,243 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_FALCON_IO_H
+#define EFX_FALCON_IO_H
+
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include "net_driver.h"
+
+/**************************************************************************
+ *
+ * Falcon hardware access
+ *
+ **************************************************************************
+ *
+ * Notes on locking strategy:
+ *
+ * Most Falcon registers require 16-byte (or 8-byte, for SRAM
+ * registers) atomic writes which necessitates locking.
+ * Under normal operation few writes to the Falcon BAR are made and these
+ * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
+ * cased to allow 4-byte (hence lockless) accesses.
+ *
+ * It *is* safe to write to these 4-byte registers in the middle of an
+ * access to an 8-byte or 16-byte register. We therefore use a
+ * spinlock to protect accesses to the larger registers, but no locks
+ * for the 4-byte registers.
+ *
+ * A write barrier is needed to ensure that DW3 is written after DW0/1/2
+ * due to the way the 16byte registers are "collected" in the Falcon BIU
+ *
+ * We also lock when carrying out reads, to ensure consistency of the
+ * data (made possible since the BIU reads all 128 bits into a cache).
+ * Reads are very rare, so this isn't a significant performance
+ * impact. (Most data transferred from NIC to host is DMAed directly
+ * into host memory).
+ *
+ * I/O BAR access uses locks for both reads and writes (but is only provided
+ * for testing purposes).
+ */
+
+/* Special buffer descriptors (Falcon SRAM) */
+#define BUF_TBL_KER_A1 0x18000
+#define BUF_TBL_KER_B0 0x800000
+
+
+#if BITS_PER_LONG == 64
+#define FALCON_USE_QWORD_IO 1
+#endif
+
+#define _falcon_writeq(efx, value, reg) \
+ __raw_writeq((__force u64) (value), (efx)->membase + (reg))
+#define _falcon_writel(efx, value, reg) \
+ __raw_writel((__force u32) (value), (efx)->membase + (reg))
+#define _falcon_readq(efx, reg) \
+ ((__force __le64) __raw_readq((efx)->membase + (reg)))
+#define _falcon_readl(efx, reg) \
+ ((__force __le32) __raw_readl((efx)->membase + (reg)))
+
+/* Writes to a normal 16-byte Falcon register, locking as appropriate. */
+static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg)
+{
+ unsigned long flags;
+
+ EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef FALCON_USE_QWORD_IO
+ _falcon_writeq(efx, value->u64[0], reg + 0);
+ wmb();
+ _falcon_writeq(efx, value->u64[1], reg + 8);
+#else
+ _falcon_writel(efx, value->u32[0], reg + 0);
+ _falcon_writel(efx, value->u32[1], reg + 4);
+ _falcon_writel(efx, value->u32[2], reg + 8);
+ wmb();
+ _falcon_writel(efx, value->u32[3], reg + 12);
+#endif
+ mmiowb();
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Writes to an 8-byte Falcon SRAM register, locking as appropriate. */
+static inline void falcon_write_sram(struct efx_nic *efx, efx_qword_t *value,
+ unsigned int index)
+{
+ unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
+ unsigned long flags;
+
+ EFX_REGDUMP(efx, "writing SRAM register %x with " EFX_QWORD_FMT "\n",
+ reg, EFX_QWORD_VAL(*value));
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef FALCON_USE_QWORD_IO
+ _falcon_writeq(efx, value->u64[0], reg + 0);
+#else
+ _falcon_writel(efx, value->u32[0], reg + 0);
+ wmb();
+ _falcon_writel(efx, value->u32[1], reg + 4);
+#endif
+ mmiowb();
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+/* Write dword to Falcon register that allows partial writes
+ *
+ * Some Falcon registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
+ * TX_DESC_UPD_REG) can be written to as a single dword. This allows
+ * for lockless writes.
+ */
+static inline void falcon_writel(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg)
+{
+ EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
+
+ /* No lock required */
+ _falcon_writel(efx, value->u32[0], reg);
+}
+
+/* Read from a Falcon register
+ *
+ * This reads an entire 16-byte Falcon register in one go, locking as
+ * appropriate. It is essential to read the first dword first, as this
+ * prompts Falcon to load the current value into the shadow register.
+ */
+static inline void falcon_read(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+ value->u32[0] = _falcon_readl(efx, reg + 0);
+ rmb();
+ value->u32[1] = _falcon_readl(efx, reg + 4);
+ value->u32[2] = _falcon_readl(efx, reg + 8);
+ value->u32[3] = _falcon_readl(efx, reg + 12);
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+ EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
+ EFX_OWORD_VAL(*value));
+}
+
+/* This reads an 8-byte Falcon SRAM entry in one go. */
+static inline void falcon_read_sram(struct efx_nic *efx, efx_qword_t *value,
+ unsigned int index)
+{
+ unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
+ unsigned long flags;
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+#ifdef FALCON_USE_QWORD_IO
+ value->u64[0] = _falcon_readq(efx, reg + 0);
+#else
+ value->u32[0] = _falcon_readl(efx, reg + 0);
+ rmb();
+ value->u32[1] = _falcon_readl(efx, reg + 4);
+#endif
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+
+ EFX_REGDUMP(efx, "read from SRAM register %x, got "EFX_QWORD_FMT"\n",
+ reg, EFX_QWORD_VAL(*value));
+}
+
+/* Read dword from Falcon register that allows partial writes (sic) */
+static inline void falcon_readl(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg)
+{
+ value->u32[0] = _falcon_readl(efx, reg);
+ EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
+ reg, EFX_DWORD_VAL(*value));
+}
+
+/* Write to a register forming part of a table */
+static inline void falcon_write_table(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ falcon_write(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Read to a register forming part of a table */
+static inline void falcon_read_table(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ falcon_read(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Write to a dword register forming part of a table */
+static inline void falcon_writel_table(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int index)
+{
+ falcon_writel(efx, value, reg + index * sizeof(efx_oword_t));
+}
+
+/* Page-mapped register block size */
+#define FALCON_PAGE_BLOCK_SIZE 0x2000
+
+/* Calculate offset to page-mapped register block */
+#define FALCON_PAGED_REG(page, reg) \
+ ((page) * FALCON_PAGE_BLOCK_SIZE + (reg))
+
+/* As for falcon_write(), but for a page-mapped register. */
+static inline void falcon_write_page(struct efx_nic *efx, efx_oword_t *value,
+ unsigned int reg, unsigned int page)
+{
+ falcon_write(efx, value, FALCON_PAGED_REG(page, reg));
+}
+
+/* As for falcon_writel(), but for a page-mapped register. */
+static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value,
+ unsigned int reg, unsigned int page)
+{
+ falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
+}
+
+/* Write dword to Falcon page-mapped register with an extra lock.
+ *
+ * As for falcon_writel_page(), but for a register that suffers from
+ * SFC bug 3181. Take out a lock so the BIU collector cannot be
+ * confused. */
+static inline void falcon_writel_page_locked(struct efx_nic *efx,
+ efx_dword_t *value,
+ unsigned int reg,
+ unsigned int page)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&efx->biu_lock, flags);
+ falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
+ spin_unlock_irqrestore(&efx->biu_lock, flags);
+}
+
+#endif /* EFX_FALCON_IO_H */
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c
new file mode 100644
index 0000000..aa7521b
--- /dev/null
+++ b/drivers/net/sfc/falcon_xmac.c
@@ -0,0 +1,585 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "efx.h"
+#include "falcon.h"
+#include "falcon_hwdefs.h"
+#include "falcon_io.h"
+#include "mac.h"
+#include "gmii.h"
+#include "mdio_10g.h"
+#include "phy.h"
+#include "boards.h"
+#include "workarounds.h"
+
+/**************************************************************************
+ *
+ * MAC register access
+ *
+ **************************************************************************/
+
+/* Offset of an XMAC register within Falcon */
+#define FALCON_XMAC_REG(mac_reg) \
+ (FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE))
+
+void falcon_xmac_writel(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg)
+{
+ efx_oword_t temp;
+
+ EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA));
+ falcon_write(efx, &temp, FALCON_XMAC_REG(mac_reg));
+}
+
+void falcon_xmac_readl(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg)
+{
+ efx_oword_t temp;
+
+ falcon_read(efx, &temp, FALCON_XMAC_REG(mac_reg));
+ EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA));
+}
+
+/**************************************************************************
+ *
+ * MAC operations
+ *
+ *************************************************************************/
+static int falcon_reset_xmac(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int count;
+
+ EFX_POPULATE_DWORD_1(reg, XM_CORE_RST, 1);
+ falcon_xmac_writel(efx, ®, XM_GLB_CFG_REG_MAC);
+
+ for (count = 0; count < 10000; count++) { /* wait upto 100ms */
+ falcon_xmac_readl(efx, ®, XM_GLB_CFG_REG_MAC);
+ if (EFX_DWORD_FIELD(reg, XM_CORE_RST) == 0)
+ return 0;
+ udelay(10);
+ }
+
+ EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
+ return -ETIMEDOUT;
+}
+
+/* Configure the XAUI driver that is an output from Falcon */
+static void falcon_setup_xaui(struct efx_nic *efx)
+{
+ efx_dword_t sdctl, txdrv;
+
+ /* Move the XAUI into low power, unless there is no PHY, in
+ * which case the XAUI will have to drive a cable. */
+ if (efx->phy_type == PHY_TYPE_NONE)
+ return;
+
+ falcon_xmac_readl(efx, &sdctl, XX_SD_CTL_REG_MAC);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
+ EFX_SET_DWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
+ falcon_xmac_writel(efx, &sdctl, XX_SD_CTL_REG_MAC);
+
+ EFX_POPULATE_DWORD_8(txdrv,
+ XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
+ XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
+ XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
+ XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
+ XX_DTXD, XX_TXDRV_DTX_DEFAULT,
+ XX_DTXC, XX_TXDRV_DTX_DEFAULT,
+ XX_DTXB, XX_TXDRV_DTX_DEFAULT,
+ XX_DTXA, XX_TXDRV_DTX_DEFAULT);
+ falcon_xmac_writel(efx, &txdrv, XX_TXDRV_CTL_REG_MAC);
+}
+
+static void falcon_hold_xaui_in_rst(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ EFX_ZERO_DWORD(reg);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
+ EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+ udelay(10);
+}
+
+static int _falcon_reset_xaui_a(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ falcon_hold_xaui_in_rst(efx);
+ falcon_xmac_readl(efx, ®, XX_PWR_RST_REG_MAC);
+
+ /* Follow the RAMBUS XAUI data reset sequencing
+ * Channels A and B first: power down, reset PLL, reset, clear
+ */
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 0);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 0);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Channels C and D: power down, reset PLL, reset, clear */
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 0);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 0);
+ EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 0);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Setup XAUI */
+ falcon_setup_xaui(efx);
+ udelay(10);
+
+ /* Take XGXS out of reset */
+ EFX_ZERO_DWORD(reg);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ return 0;
+}
+
+static int _falcon_reset_xaui_b(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int count;
+
+ EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+
+ /* Give some time for the link to establish */
+ for (count = 0; count < 1000; count++) { /* wait upto 10ms */
+ falcon_xmac_readl(efx, ®, XX_PWR_RST_REG_MAC);
+ if (EFX_DWORD_FIELD(reg, XX_RST_XX_EN) == 0) {
+ falcon_setup_xaui(efx);
+ return 0;
+ }
+ udelay(10);
+ }
+ EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
+ return -ETIMEDOUT;
+}
+
+int falcon_reset_xaui(struct efx_nic *efx)
+{
+ int rc;
+
+ if (EFX_WORKAROUND_9388(efx)) {
+ falcon_hold_xaui_in_rst(efx);
+ efx->phy_op->reset_xaui(efx);
+ rc = _falcon_reset_xaui_a(efx);
+ } else {
+ rc = _falcon_reset_xaui_b(efx);
+ }
+ return rc;
+}
+
+static int falcon_xgmii_status(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return 1;
+
+ /* The ISR latches, so clear it and re-read */
+ falcon_xmac_readl(efx, ®, XM_MGT_INT_REG_MAC_B0);
+ falcon_xmac_readl(efx, ®, XM_MGT_INT_REG_MAC_B0);
+
+ if (EFX_DWORD_FIELD(reg, XM_LCLFLT) ||
+ EFX_DWORD_FIELD(reg, XM_RMTFLT)) {
+ EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg));
+ return 0;
+ }
+
+ return 1;
+}
+
+static void falcon_mask_status_intr(struct efx_nic *efx, int enable)
+{
+ efx_dword_t reg;
+
+ if (FALCON_REV(efx) < FALCON_REV_B0)
+ return;
+
+ /* Flush the ISR */
+ if (enable)
+ falcon_xmac_readl(efx, ®, XM_MGT_INT_REG_MAC_B0);
+
+ EFX_POPULATE_DWORD_2(reg,
+ XM_MSK_RMTFLT, !enable,
+ XM_MSK_LCLFLT, !enable);
+ falcon_xmac_writel(efx, ®, XM_MGT_INT_MSK_REG_MAC_B0);
+}
+
+int falcon_init_xmac(struct efx_nic *efx)
+{
+ int rc;
+
+ /* Initialize the PHY first so the clock is around */
+ rc = efx->phy_op->init(efx);
+ if (rc)
+ goto fail1;
+
+ rc = falcon_reset_xaui(efx);
+ if (rc)
+ goto fail2;
+
+ /* Wait again. Give the PHY and MAC time to come back */
+ schedule_timeout_uninterruptible(HZ / 10);
+
+ rc = falcon_reset_xmac(efx);
+ if (rc)
+ goto fail2;
+
+ falcon_mask_status_intr(efx, 1);
+ return 0;
+
+ fail2:
+ efx->phy_op->fini(efx);
+ fail1:
+ return rc;
+}
+
+int falcon_xaui_link_ok(struct efx_nic *efx)
+{
+ efx_dword_t reg;
+ int align_done, sync_status, link_ok = 0;
+
+ /* Read link status */
+ falcon_xmac_readl(efx, ®, XX_CORE_STAT_REG_MAC);
+
+ align_done = EFX_DWORD_FIELD(reg, XX_ALIGN_DONE);
+ sync_status = EFX_DWORD_FIELD(reg, XX_SYNC_STAT);
+ if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED))
+ link_ok = 1;
+
+ /* Clear link status ready for next read */
+ EFX_SET_DWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
+ EFX_SET_DWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
+ EFX_SET_DWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
+ falcon_xmac_writel(efx, ®, XX_CORE_STAT_REG_MAC);
+
+ /* If the link is up, then check the phy side of the xaui link
+ * (error conditions from the wire side propoagate back through
+ * the phy to the xaui side). */
+ if (efx->link_up && link_ok) {
+ int has_phyxs = efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS);
+ if (has_phyxs)
+ link_ok = mdio_clause45_phyxgxs_lane_sync(efx);
+ }
+
+ /* If the PHY and XAUI links are up, then check the mac's xgmii
+ * fault state */
+ if (efx->link_up && link_ok)
+ link_ok = falcon_xgmii_status(efx);
+
+ return link_ok;
+}
+
+static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
+{
+ unsigned int max_frame_len;
+ efx_dword_t reg;
+ int rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
+
+ /* Configure MAC - cut-thru mode is hard wired on */
+ EFX_POPULATE_DWORD_3(reg,
+ XM_RX_JUMBO_MODE, 1,
+ XM_TX_STAT_EN, 1,
+ XM_RX_STAT_EN, 1);
+ falcon_xmac_writel(efx, ®, XM_GLB_CFG_REG_MAC);
+
+ /* Configure TX */
+ EFX_POPULATE_DWORD_6(reg,
+ XM_TXEN, 1,
+ XM_TX_PRMBL, 1,
+ XM_AUTO_PAD, 1,
+ XM_TXCRC, 1,
+ XM_FCNTL, 1,
+ XM_IPG, 0x3);
+ falcon_xmac_writel(efx, ®, XM_TX_CFG_REG_MAC);
+
+ /* Configure RX */
+ EFX_POPULATE_DWORD_5(reg,
+ XM_RXEN, 1,
+ XM_AUTO_DEPAD, 0,
+ XM_ACPT_ALL_MCAST, 1,
+ XM_ACPT_ALL_UCAST, efx->promiscuous,
+ XM_PASS_CRC_ERR, 1);
+ falcon_xmac_writel(efx, ®, XM_RX_CFG_REG_MAC);
+
+ /* Set frame length */
+ max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
+ EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len);
+ falcon_xmac_writel(efx, ®, XM_RX_PARAM_REG_MAC);
+ EFX_POPULATE_DWORD_2(reg,
+ XM_MAX_TX_FRM_SIZE, max_frame_len,
+ XM_TX_JUMBO_MODE, 1);
+ falcon_xmac_writel(efx, ®, XM_TX_PARAM_REG_MAC);
+
+ EFX_POPULATE_DWORD_2(reg,
+ XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
+ XM_DIS_FCNTL, rx_fc ? 0 : 1);
+ falcon_xmac_writel(efx, ®, XM_FC_REG_MAC);
+
+ /* Set MAC address */
+ EFX_POPULATE_DWORD_4(reg,
+ XM_ADR_0, efx->net_dev->dev_addr[0],
+ XM_ADR_1, efx->net_dev->dev_addr[1],
+ XM_ADR_2, efx->net_dev->dev_addr[2],
+ XM_ADR_3, efx->net_dev->dev_addr[3]);
+ falcon_xmac_writel(efx, ®, XM_ADR_LO_REG_MAC);
+ EFX_POPULATE_DWORD_2(reg,
+ XM_ADR_4, efx->net_dev->dev_addr[4],
+ XM_ADR_5, efx->net_dev->dev_addr[5]);
+ falcon_xmac_writel(efx, ®, XM_ADR_HI_REG_MAC);
+}
+
+/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
+ * to come back up. Bash it until it comes back up */
+static int falcon_check_xaui_link_up(struct efx_nic *efx)
+{
+ int max_tries, tries;
+ tries = EFX_WORKAROUND_5147(efx) ? 5 : 1;
+ max_tries = tries;
+
+ if (efx->phy_type == PHY_TYPE_NONE)
+ return 0;
+
+ while (tries) {
+ if (falcon_xaui_link_ok(efx))
+ return 1;
+
+ EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n",
+ __func__, tries);
+ (void) falcon_reset_xaui(efx);
+ udelay(200);
+ tries--;
+ }
+
+ EFX_ERR(efx, "Failed to bring XAUI link back up in %d tries!\n",
+ max_tries);
+ return 0;
+}
+
+void falcon_reconfigure_xmac(struct efx_nic *efx)
+{
+ int xaui_link_ok;
+
+ falcon_mask_status_intr(efx, 0);
+
+ falcon_deconfigure_mac_wrapper(efx);
+ efx->phy_op->reconfigure(efx);
+ falcon_reconfigure_xmac_core(efx);
+ falcon_reconfigure_mac_wrapper(efx);
+
+ /* Ensure XAUI link is up */
+ xaui_link_ok = falcon_check_xaui_link_up(efx);
+
+ if (xaui_link_ok && efx->link_up)
+ falcon_mask_status_intr(efx, 1);
+}
+
+void falcon_fini_xmac(struct efx_nic *efx)
+{
+ /* Isolate the MAC - PHY */
+ falcon_deconfigure_mac_wrapper(efx);
+
+ /* Potentially power down the PHY */
+ efx->phy_op->fini(efx);
+}
+
+void falcon_update_stats_xmac(struct efx_nic *efx)
+{
+ struct efx_mac_stats *mac_stats = &efx->mac_stats;
+ int rc;
+
+ rc = falcon_dma_stats(efx, XgDmaDone_offset);
+ if (rc)
+ return;
+
+ /* Update MAC stats from DMAed values */
+ FALCON_STAT(efx, XgRxOctets, rx_bytes);
+ FALCON_STAT(efx, XgRxOctetsOK, rx_good_bytes);
+ FALCON_STAT(efx, XgRxPkts, rx_packets);
+ FALCON_STAT(efx, XgRxPktsOK, rx_good);
+ FALCON_STAT(efx, XgRxBroadcastPkts, rx_broadcast);
+ FALCON_STAT(efx, XgRxMulticastPkts, rx_multicast);
+ FALCON_STAT(efx, XgRxUnicastPkts, rx_unicast);
+ FALCON_STAT(efx, XgRxUndersizePkts, rx_lt64);
+ FALCON_STAT(efx, XgRxOversizePkts, rx_gtjumbo);
+ FALCON_STAT(efx, XgRxJabberPkts, rx_bad_gtjumbo);
+ FALCON_STAT(efx, XgRxUndersizeFCSerrorPkts, rx_bad_lt64);
+ FALCON_STAT(efx, XgRxDropEvents, rx_overflow);
+ FALCON_STAT(efx, XgRxFCSerrorPkts, rx_bad);
+ FALCON_STAT(efx, XgRxAlignError, rx_align_error);
+ FALCON_STAT(efx, XgRxSymbolError, rx_symbol_error);
+ FALCON_STAT(efx, XgRxInternalMACError, rx_internal_error);
+ FALCON_STAT(efx, XgRxControlPkts, rx_control);
+ FALCON_STAT(efx, XgRxPausePkts, rx_pause);
+ FALCON_STAT(efx, XgRxPkts64Octets, rx_64);
+ FALCON_STAT(efx, XgRxPkts65to127Octets, rx_65_to_127);
+ FALCON_STAT(efx, XgRxPkts128to255Octets, rx_128_to_255);
+ FALCON_STAT(efx, XgRxPkts256to511Octets, rx_256_to_511);
+ FALCON_STAT(efx, XgRxPkts512to1023Octets, rx_512_to_1023);
+ FALCON_STAT(efx, XgRxPkts1024to15xxOctets, rx_1024_to_15xx);
+ FALCON_STAT(efx, XgRxPkts15xxtoMaxOctets, rx_15xx_to_jumbo);
+ FALCON_STAT(efx, XgRxLengthError, rx_length_error);
+ FALCON_STAT(efx, XgTxPkts, tx_packets);
+ FALCON_STAT(efx, XgTxOctets, tx_bytes);
+ FALCON_STAT(efx, XgTxMulticastPkts, tx_multicast);
+ FALCON_STAT(efx, XgTxBroadcastPkts, tx_broadcast);
+ FALCON_STAT(efx, XgTxUnicastPkts, tx_unicast);
+ FALCON_STAT(efx, XgTxControlPkts, tx_control);
+ FALCON_STAT(efx, XgTxPausePkts, tx_pause);
+ FALCON_STAT(efx, XgTxPkts64Octets, tx_64);
+ FALCON_STAT(efx, XgTxPkts65to127Octets, tx_65_to_127);
+ FALCON_STAT(efx, XgTxPkts128to255Octets, tx_128_to_255);
+ FALCON_STAT(efx, XgTxPkts256to511Octets, tx_256_to_511);
+ FALCON_STAT(efx, XgTxPkts512to1023Octets, tx_512_to_1023);
+ FALCON_STAT(efx, XgTxPkts1024to15xxOctets, tx_1024_to_15xx);
+ FALCON_STAT(efx, XgTxPkts1519toMaxOctets, tx_15xx_to_jumbo);
+ FALCON_STAT(efx, XgTxUndersizePkts, tx_lt64);
+ FALCON_STAT(efx, XgTxOversizePkts, tx_gtjumbo);
+ FALCON_STAT(efx, XgTxNonTcpUdpPkt, tx_non_tcpudp);
+ FALCON_STAT(efx, XgTxMacSrcErrPkt, tx_mac_src_error);
+ FALCON_STAT(efx, XgTxIpSrcErrPkt, tx_ip_src_error);
+
+ /* Update derived statistics */
+ mac_stats->tx_good_bytes =
+ (mac_stats->tx_bytes - mac_stats->tx_bad_bytes);
+ mac_stats->rx_bad_bytes =
+ (mac_stats->rx_bytes - mac_stats->rx_good_bytes);
+}
+
+#define EFX_XAUI_RETRAIN_MAX 8
+
+int falcon_check_xmac(struct efx_nic *efx)
+{
+ unsigned xaui_link_ok;
+ int rc;
+
+ falcon_mask_status_intr(efx, 0);
+ xaui_link_ok = falcon_xaui_link_ok(efx);
+
+ if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok)
+ (void) falcon_reset_xaui(efx);
+
+ /* Call the PHY check_hw routine */
+ rc = efx->phy_op->check_hw(efx);
+
+ /* Unmask interrupt if everything was (and still is) ok */
+ if (xaui_link_ok && efx->link_up)
+ falcon_mask_status_intr(efx, 1);
+
+ return rc;
+}
+
+/* Simulate a PHY event */
+void falcon_xmac_sim_phy_event(struct efx_nic *efx)
+{
+ efx_qword_t phy_event;
+
+ EFX_POPULATE_QWORD_2(phy_event,
+ EV_CODE, GLOBAL_EV_DECODE,
+ XG_PHY_INTR, 1);
+ falcon_generate_event(&efx->channel[0], &phy_event);
+}
+
+int falcon_xmac_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ mdio_clause45_get_settings(efx, ecmd);
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->phy_address = efx->mii.phy_id;
+ ecmd->autoneg = AUTONEG_DISABLE;
+ ecmd->duplex = DUPLEX_FULL;
+ return 0;
+}
+
+int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd)
+{
+ if (ecmd->transceiver != XCVR_INTERNAL)
+ return -EINVAL;
+ if (ecmd->autoneg != AUTONEG_DISABLE)
+ return -EINVAL;
+ if (ecmd->duplex != DUPLEX_FULL)
+ return -EINVAL;
+
+ return mdio_clause45_set_settings(efx, ecmd);
+}
+
+
+int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control)
+{
+ int reset;
+
+ if (flow_control & EFX_FC_AUTO) {
+ EFX_LOG(efx, "10G does not support flow control "
+ "autonegotiation\n");
+ return -EINVAL;
+ }
+
+ if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX))
+ return -EINVAL;
+
+ /* TX flow control may automatically turn itself off if the
+ * link partner (intermittently) stops responding to pause
+ * frames. There isn't any indication that this has happened,
+ * so the best we do is leave it up to the user to spot this
+ * and fix it be cycling transmit flow control on this end. */
+ reset = ((flow_control & EFX_FC_TX) &&
+ !(efx->flow_control & EFX_FC_TX));
+ if (EFX_WORKAROUND_11482(efx) && reset) {
+ if (FALCON_REV(efx) >= FALCON_REV_B0) {
+ /* Recover by resetting the EM block */
+ if (efx->link_up)
+ falcon_drain_tx_fifo(efx);
+ } else {
+ /* Schedule a reset to recover */
+ efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
+ }
+ }
+
+ efx->flow_control = flow_control;
+
+ return 0;
+}
diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h
new file mode 100644
index 0000000..d25bbd1
--- /dev/null
+++ b/drivers/net/sfc/gmii.h
@@ -0,0 +1,195 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_GMII_H
+#define EFX_GMII_H
+
+/*
+ * GMII interface
+ */
+
+#include <linux/mii.h>
+
+/* GMII registers, excluding registers already defined as MII
+ * registers in mii.h
+ */
+#define GMII_IER 0x12 /* Interrupt enable register */
+#define GMII_ISR 0x13 /* Interrupt status register */
+
+/* Interrupt enable register */
+#define IER_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
+#define IER_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
+#define IER_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
+#define IER_PAGE_RCVD 0x1000 /* Bit 12 - page received */
+#define IER_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
+#define IER_LINK_CHG 0x0400 /* Bit 10 - link status changed */
+#define IER_SYM_ERR 0x0200 /* Bit 9 - symbol error */
+#define IER_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
+#define IER_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
+#define IER_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
+#define IER_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
+#define IER_ENERGY 0x0010 /* Bit 4 - energy detect */
+#define IER_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
+#define IER_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
+#define IER_JABBER 0x0001 /* Bit 0 - jabber */
+
+/* Interrupt status register */
+#define ISR_ANEG_ERR 0x8000 /* Bit 15 - autonegotiation error */
+#define ISR_SPEED_CHG 0x4000 /* Bit 14 - speed changed */
+#define ISR_DUPLEX_CHG 0x2000 /* Bit 13 - duplex changed */
+#define ISR_PAGE_RCVD 0x1000 /* Bit 12 - page received */
+#define ISR_ANEG_DONE 0x0800 /* Bit 11 - autonegotiation complete */
+#define ISR_LINK_CHG 0x0400 /* Bit 10 - link status changed */
+#define ISR_SYM_ERR 0x0200 /* Bit 9 - symbol error */
+#define ISR_FALSE_CARRIER 0x0100 /* Bit 8 - false carrier */
+#define ISR_FIFO_ERR 0x0080 /* Bit 7 - FIFO over/underflow */
+#define ISR_MDIX_CHG 0x0040 /* Bit 6 - MDI crossover changed */
+#define ISR_DOWNSHIFT 0x0020 /* Bit 5 - downshift */
+#define ISR_ENERGY 0x0010 /* Bit 4 - energy detect */
+#define ISR_DTE_POWER 0x0004 /* Bit 2 - DTE power detect */
+#define ISR_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */
+#define ISR_JABBER 0x0001 /* Bit 0 - jabber */
+
+/* Logically extended advertisement register */
+#define GM_ADVERTISE_SLCT ADVERTISE_SLCT
+#define GM_ADVERTISE_CSMA ADVERTISE_CSMA
+#define GM_ADVERTISE_10HALF ADVERTISE_10HALF
+#define GM_ADVERTISE_1000XFULL ADVERTISE_1000XFULL
+#define GM_ADVERTISE_10FULL ADVERTISE_10FULL
+#define GM_ADVERTISE_1000XHALF ADVERTISE_1000XHALF
+#define GM_ADVERTISE_100HALF ADVERTISE_100HALF
+#define GM_ADVERTISE_1000XPAUSE ADVERTISE_1000XPAUSE
+#define GM_ADVERTISE_100FULL ADVERTISE_100FULL
+#define GM_ADVERTISE_1000XPSE_ASYM ADVERTISE_1000XPSE_ASYM
+#define GM_ADVERTISE_100BASE4 ADVERTISE_100BASE4
+#define GM_ADVERTISE_PAUSE_CAP ADVERTISE_PAUSE_CAP
+#define GM_ADVERTISE_PAUSE_ASYM ADVERTISE_PAUSE_ASYM
+#define GM_ADVERTISE_RESV ADVERTISE_RESV
+#define GM_ADVERTISE_RFAULT ADVERTISE_RFAULT
+#define GM_ADVERTISE_LPACK ADVERTISE_LPACK
+#define GM_ADVERTISE_NPAGE ADVERTISE_NPAGE
+#define GM_ADVERTISE_1000FULL (ADVERTISE_1000FULL << 8)
+#define GM_ADVERTISE_1000HALF (ADVERTISE_1000HALF << 8)
+#define GM_ADVERTISE_1000 (GM_ADVERTISE_1000FULL | \
+ GM_ADVERTISE_1000HALF)
+#define GM_ADVERTISE_FULL (GM_ADVERTISE_1000FULL | \
+ ADVERTISE_FULL)
+#define GM_ADVERTISE_ALL (GM_ADVERTISE_1000FULL | \
+ GM_ADVERTISE_1000HALF | \
+ ADVERTISE_ALL)
+
+/* Logically extended link partner ability register */
+#define GM_LPA_SLCT LPA_SLCT
+#define GM_LPA_10HALF LPA_10HALF
+#define GM_LPA_1000XFULL LPA_1000XFULL
+#define GM_LPA_10FULL LPA_10FULL
+#define GM_LPA_1000XHALF LPA_1000XHALF
+#define GM_LPA_100HALF LPA_100HALF
+#define GM_LPA_1000XPAUSE LPA_1000XPAUSE
+#define GM_LPA_100FULL LPA_100FULL
+#define GM_LPA_1000XPAUSE_ASYM LPA_1000XPAUSE_ASYM
+#define GM_LPA_100BASE4 LPA_100BASE4
+#define GM_LPA_PAUSE_CAP LPA_PAUSE_CAP
+#define GM_LPA_PAUSE_ASYM LPA_PAUSE_ASYM
+#define GM_LPA_RESV LPA_RESV
+#define GM_LPA_RFAULT LPA_RFAULT
+#define GM_LPA_LPACK LPA_LPACK
+#define GM_LPA_NPAGE LPA_NPAGE
+#define GM_LPA_1000FULL (LPA_1000FULL << 6)
+#define GM_LPA_1000HALF (LPA_1000HALF << 6)
+#define GM_LPA_10000FULL 0x00040000
+#define GM_LPA_10000HALF 0x00080000
+#define GM_LPA_DUPLEX (GM_LPA_1000FULL | GM_LPA_10000FULL \
+ | LPA_DUPLEX)
+#define GM_LPA_10 (LPA_10FULL | LPA_10HALF)
+#define GM_LPA_100 LPA_100
+#define GM_LPA_1000 (GM_LPA_1000FULL | GM_LPA_1000HALF)
+#define GM_LPA_10000 (GM_LPA_10000FULL | GM_LPA_10000HALF)
+
+/* Retrieve GMII autonegotiation advertised abilities
+ *
+ * The MII advertisment register (MII_ADVERTISE) is logically extended
+ * to include advertisement bits ADVERTISE_1000FULL and
+ * ADVERTISE_1000HALF from MII_CTRL1000. The result can be tested
+ * against the GM_ADVERTISE_xxx constants.
+ */
+static inline unsigned int gmii_advertised(struct mii_if_info *gmii)
+{
+ unsigned int advertise;
+ unsigned int ctrl1000;
+
+ advertise = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE);
+ ctrl1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000);
+ return (((ctrl1000 << 8) & GM_ADVERTISE_1000) | advertise);
+}
+
+/* Retrieve GMII autonegotiation link partner abilities
+ *
+ * The MII link partner ability register (MII_LPA) is logically
+ * extended by adding bits LPA_1000HALF and LPA_1000FULL from
+ * MII_STAT1000. The result can be tested against the GM_LPA_xxx
+ * constants.
+ */
+static inline unsigned int gmii_lpa(struct mii_if_info *gmii)
+{
+ unsigned int lpa;
+ unsigned int stat1000;
+
+ lpa = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_LPA);
+ stat1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_STAT1000);
+ return (((stat1000 << 6) & GM_LPA_1000) | lpa);
+}
+
+/* Calculate GMII autonegotiated link technology
+ *
+ * "negotiated" should be the result of gmii_advertised() logically
+ * ANDed with the result of gmii_lpa().
+ *
+ * "tech" will be negotiated with the unused bits masked out. For
+ * example, if both ends of the link are capable of both
+ * GM_LPA_1000FULL and GM_LPA_100FULL, GM_LPA_100FULL will be masked
+ * out.
+ */
+static inline unsigned int gmii_nway_result(unsigned int negotiated)
+{
+ unsigned int other_bits;
+
+ /* Mask out the speed and duplexity bits */
+ other_bits = negotiated & ~(GM_LPA_10 | GM_LPA_100 | GM_LPA_1000);
+
+ if (negotiated & GM_LPA_1000FULL)
+ return (other_bits | GM_LPA_1000FULL);
+ else if (negotiated & GM_LPA_1000HALF)
+ return (other_bits | GM_LPA_1000HALF);
+ else
+ return (other_bits | mii_nway_result(negotiated));
+}
+
+/* Calculate GMII non-autonegotiated link technology
+ *
+ * This provides an equivalent to gmii_nway_result for the case when
+ * autonegotiation is disabled.
+ */
+static inline unsigned int gmii_forced_result(unsigned int bmcr)
+{
+ unsigned int result;
+ int full_duplex;
+
+ full_duplex = bmcr & BMCR_FULLDPLX;
+ if (bmcr & BMCR_SPEED1000)
+ result = full_duplex ? GM_LPA_1000FULL : GM_LPA_1000HALF;
+ else if (bmcr & BMCR_SPEED100)
+ result = full_duplex ? GM_LPA_100FULL : GM_LPA_100HALF;
+ else
+ result = full_duplex ? GM_LPA_10FULL : GM_LPA_10HALF;
+ return result;
+}
+
+#endif /* EFX_GMII_H */
diff --git a/drivers/net/sfc/i2c-direct.c b/drivers/net/sfc/i2c-direct.c
new file mode 100644
index 0000000..b6c62d0e
--- /dev/null
+++ b/drivers/net/sfc/i2c-direct.c
@@ -0,0 +1,381 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "i2c-direct.h"
+
+/*
+ * I2C data (SDA) and clock (SCL) line read/writes with appropriate
+ * delays.
+ */
+
+static inline void setsda(struct efx_i2c_interface *i2c, int state)
+{
+ udelay(i2c->op->udelay);
+ i2c->sda = state;
+ i2c->op->setsda(i2c);
+ udelay(i2c->op->udelay);
+}
+
+static inline void setscl(struct efx_i2c_interface *i2c, int state)
+{
+ udelay(i2c->op->udelay);
+ i2c->scl = state;
+ i2c->op->setscl(i2c);
+ udelay(i2c->op->udelay);
+}
+
+static inline int getsda(struct efx_i2c_interface *i2c)
+{
+ int sda;
+
+ udelay(i2c->op->udelay);
+ sda = i2c->op->getsda(i2c);
+ udelay(i2c->op->udelay);
+ return sda;
+}
+
+static inline int getscl(struct efx_i2c_interface *i2c)
+{
+ int scl;
+
+ udelay(i2c->op->udelay);
+ scl = i2c->op->getscl(i2c);
+ udelay(i2c->op->udelay);
+ return scl;
+}
+
+/*
+ * I2C low-level protocol operations
+ *
+ */
+
+static inline void i2c_release(struct efx_i2c_interface *i2c)
+{
+ EFX_WARN_ON_PARANOID(!i2c->scl);
+ EFX_WARN_ON_PARANOID(!i2c->sda);
+ /* Devices may time out if operations do not end */
+ setscl(i2c, 1);
+ setsda(i2c, 1);
+ EFX_BUG_ON_PARANOID(getsda(i2c) != 1);
+ EFX_BUG_ON_PARANOID(getscl(i2c) != 1);
+}
+
+static inline void i2c_start(struct efx_i2c_interface *i2c)
+{
+ /* We may be restarting immediately after a {send,recv}_bit,
+ * so SCL will not necessarily already be high.
+ */
+ EFX_WARN_ON_PARANOID(!i2c->sda);
+ setscl(i2c, 1);
+ setsda(i2c, 0);
+ setscl(i2c, 0);
+ setsda(i2c, 1);
+}
+
+static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit)
+{
+ EFX_WARN_ON_PARANOID(i2c->scl != 0);
+ setsda(i2c, bit);
+ setscl(i2c, 1);
+ setscl(i2c, 0);
+ setsda(i2c, 1);
+}
+
+static inline int i2c_recv_bit(struct efx_i2c_interface *i2c)
+{
+ int bit;
+
+ EFX_WARN_ON_PARANOID(i2c->scl != 0);
+ EFX_WARN_ON_PARANOID(!i2c->sda);
+ setscl(i2c, 1);
+ bit = getsda(i2c);
+ setscl(i2c, 0);
+ return bit;
+}
+
+static inline void i2c_stop(struct efx_i2c_interface *i2c)
+{
+ EFX_WARN_ON_PARANOID(i2c->scl != 0);
+ setsda(i2c, 0);
+ setscl(i2c, 1);
+ setsda(i2c, 1);
+}
+
+/*
+ * I2C mid-level protocol operations
+ *
+ */
+
+/* Sends a byte via the I2C bus and checks for an acknowledgement from
+ * the slave device.
+ */
+static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte)
+{
+ int i;
+
+ /* Send byte */
+ for (i = 0; i < 8; i++) {
+ i2c_send_bit(i2c, !!(byte & 0x80));
+ byte <<= 1;
+ }
+
+ /* Check for acknowledgement from slave */
+ return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO);
+}
+
+/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */
+static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack)
+{
+ u8 value = 0;
+ int i;
+
+ /* Receive byte */
+ for (i = 0; i < 8; i++)
+ value = (value << 1) | i2c_recv_bit(i2c);
+
+ /* Send ACK/NACK */
+ i2c_send_bit(i2c, (ack ? 0 : 1));
+
+ return value;
+}
+
+/* Calculate command byte for a read operation */
+static inline u8 i2c_read_cmd(u8 device_id)
+{
+ return ((device_id << 1) | 1);
+}
+
+/* Calculate command byte for a write operation */
+static inline u8 i2c_write_cmd(u8 device_id)
+{
+ return ((device_id << 1) | 0);
+}
+
+int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id)
+{
+ int rc;
+
+ /* If someone is driving the bus low we just give up. */
+ if (getsda(i2c) == 0 || getscl(i2c) == 0) {
+ EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low."
+ " Giving up.\n", __func__);
+ return -EFAULT;
+ }
+
+ /* Pretend to initiate a device write */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
+ if (rc)
+ goto out;
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* This performs a fast read of one or more consecutive bytes from an
+ * I2C device. Not all devices support consecutive reads of more than
+ * one byte; for these devices use efx_i2c_read() instead.
+ */
+int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len)
+{
+ int i;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
+ EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
+ EFX_WARN_ON_PARANOID(data == NULL);
+ EFX_WARN_ON_PARANOID(len < 1);
+
+ /* Select device and starting offset */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
+ if (rc)
+ goto out;
+ rc = i2c_send_byte(i2c, offset);
+ if (rc)
+ goto out;
+
+ /* Read data from device */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
+ if (rc)
+ goto out;
+ for (i = 0; i < (len - 1); i++)
+ /* Read and acknowledge all but the last byte */
+ data[i] = i2c_recv_byte(i2c, 1);
+ /* Read last byte with no acknowledgement */
+ data[i] = i2c_recv_byte(i2c, 0);
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* This performs a fast write of one or more consecutive bytes to an
+ * I2C device. Not all devices support consecutive writes of more
+ * than one byte; for these devices use efx_i2c_write() instead.
+ */
+int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len)
+{
+ int i;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
+ EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
+ EFX_WARN_ON_PARANOID(len < 1);
+
+ /* Select device and starting offset */
+ i2c_start(i2c);
+ rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
+ if (rc)
+ goto out;
+ rc = i2c_send_byte(i2c, offset);
+ if (rc)
+ goto out;
+
+ /* Write data to device */
+ for (i = 0; i < len; i++) {
+ rc = i2c_send_byte(i2c, data[i]);
+ if (rc)
+ goto out;
+ }
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* I2C byte-by-byte read */
+int efx_i2c_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len)
+{
+ int rc;
+
+ /* i2c_fast_read with length 1 is a single byte read */
+ for (; len > 0; offset++, data++, len--) {
+ rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1);
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+
+/* I2C byte-by-byte write */
+int efx_i2c_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, const u8 *data, unsigned int len)
+{
+ int rc;
+
+ /* i2c_fast_write with length 1 is a single byte write */
+ for (; len > 0; offset++, data++, len--) {
+ rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1);
+ if (rc)
+ return rc;
+ mdelay(i2c->op->mdelay);
+ }
+
+ return 0;
+}
+
+
+/* This is just a slightly neater wrapper round efx_i2c_fast_write
+ * in the case where the target doesn't take an offset
+ */
+int efx_i2c_send_bytes(struct efx_i2c_interface *i2c,
+ u8 device_id, const u8 *data, unsigned int len)
+{
+ return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1);
+}
+
+/* I2C receiving of bytes - does not send an offset byte */
+int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
+ u8 *bytes, unsigned int len)
+{
+ int i;
+ int rc;
+
+ EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
+ EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
+ EFX_WARN_ON_PARANOID(len < 1);
+
+ /* Select device */
+ i2c_start(i2c);
+
+ /* Read data from device */
+ rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
+ if (rc)
+ goto out;
+
+ for (i = 0; i < (len - 1); i++)
+ /* Read and acknowledge all but the last byte */
+ bytes[i] = i2c_recv_byte(i2c, 1);
+ /* Read last byte with no acknowledgement */
+ bytes[i] = i2c_recv_byte(i2c, 0);
+
+ out:
+ i2c_stop(i2c);
+ i2c_release(i2c);
+
+ return rc;
+}
+
+/* SMBus and some I2C devices will time out if the I2C clock is
+ * held low for too long. This is most likely to happen in virtualised
+ * systems (when the entire domain is descheduled) but could in
+ * principle happen due to preemption on any busy system (and given the
+ * potential length of an I2C operation turning preemption off is not
+ * a sensible option). The following functions deal with the failure by
+ * retrying up to a fixed number of times.
+ */
+
+#define I2C_MAX_RETRIES (10)
+
+/* The timeout problem will result in -EIO. If the wrapped function
+ * returns any other error, pass this up and do not retry. */
+#define RETRY_WRAPPER(_f) \
+ int retries = I2C_MAX_RETRIES; \
+ int rc; \
+ while (retries) { \
+ rc = _f; \
+ if (rc != -EIO) \
+ return rc; \
+ retries--; \
+ } \
+ return rc; \
+
+int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id)
+{
+ RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id))
+}
+
+int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len)
+{
+ RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len))
+}
+
+int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, const u8 *data, unsigned int len)
+{
+ RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len))
+}
diff --git a/drivers/net/sfc/i2c-direct.h b/drivers/net/sfc/i2c-direct.h
new file mode 100644
index 0000000..291e561
--- /dev/null
+++ b/drivers/net/sfc/i2c-direct.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_I2C_DIRECT_H
+#define EFX_I2C_DIRECT_H
+
+#include "net_driver.h"
+
+/*
+ * Direct control of an I2C bus
+ */
+
+struct efx_i2c_interface;
+
+/**
+ * struct efx_i2c_bit_operations - I2C bus direct control methods
+ *
+ * I2C bus direct control methods.
+ *
+ * @setsda: Set state of SDA line
+ * @setscl: Set state of SCL line
+ * @getsda: Get state of SDA line
+ * @getscl: Get state of SCL line
+ * @udelay: Delay between each bit operation
+ * @mdelay: Delay between each byte write
+ */
+struct efx_i2c_bit_operations {
+ void (*setsda) (struct efx_i2c_interface *i2c);
+ void (*setscl) (struct efx_i2c_interface *i2c);
+ int (*getsda) (struct efx_i2c_interface *i2c);
+ int (*getscl) (struct efx_i2c_interface *i2c);
+ unsigned int udelay;
+ unsigned int mdelay;
+};
+
+/**
+ * struct efx_i2c_interface - an I2C interface
+ *
+ * An I2C interface.
+ *
+ * @efx: Attached Efx NIC
+ * @op: I2C bus control methods
+ * @sda: Current output state of SDA line
+ * @scl: Current output state of SCL line
+ */
+struct efx_i2c_interface {
+ struct efx_nic *efx;
+ struct efx_i2c_bit_operations *op;
+ unsigned int sda:1;
+ unsigned int scl:1;
+};
+
+extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id);
+extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ u8 *data, unsigned int len);
+extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len);
+extern int efx_i2c_read(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len);
+extern int efx_i2c_write(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len);
+
+extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id,
+ const u8 *bytes, unsigned int len);
+
+extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
+ u8 *bytes, unsigned int len);
+
+
+/* Versions of the API that retry on failure. */
+extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c,
+ u8 device_id);
+
+extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset, u8 *data, unsigned int len);
+
+extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
+ u8 device_id, u8 offset,
+ const u8 *data, unsigned int len);
+
+#endif /* EFX_I2C_DIRECT_H */
diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h
new file mode 100644
index 0000000..edd07d4
--- /dev/null
+++ b/drivers/net/sfc/mac.h
@@ -0,0 +1,33 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2006-2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_MAC_H
+#define EFX_MAC_H
+
+#include "net_driver.h"
+
+extern void falcon_xmac_writel(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg);
+extern void falcon_xmac_readl(struct efx_nic *efx,
+ efx_dword_t *value, unsigned int mac_reg);
+extern int falcon_init_xmac(struct efx_nic *efx);
+extern void falcon_reconfigure_xmac(struct efx_nic *efx);
+extern void falcon_update_stats_xmac(struct efx_nic *efx);
+extern void falcon_fini_xmac(struct efx_nic *efx);
+extern int falcon_check_xmac(struct efx_nic *efx);
+extern void falcon_xmac_sim_phy_event(struct efx_nic *efx);
+extern int falcon_xmac_get_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+extern int falcon_xmac_set_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+extern int falcon_xmac_set_pause(struct efx_nic *efx,
+ enum efx_fc_type pause_params);
+
+#endif
diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c
new file mode 100644
index 0000000..dc06bb0
--- /dev/null
+++ b/drivers/net/sfc/mdio_10g.c
@@ -0,0 +1,282 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+/*
+ * Useful functions for working with MDIO clause 45 PHYs
+ */
+#include <linux/types.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+#include "net_driver.h"
+#include "mdio_10g.h"
+#include "boards.h"
+
+int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd,
+ int spins, int spintime)
+{
+ u32 ctrl;
+ int phy_id = port->mii.phy_id;
+
+ /* Catch callers passing values in the wrong units (or just silly) */
+ EFX_BUG_ON_PARANOID(spins * spintime >= 5000);
+
+ mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1,
+ (1 << MDIO_MMDREG_CTRL1_RESET_LBN));
+ /* Wait for the reset bit to clear. */
+ do {
+ msleep(spintime);
+ ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1);
+ spins--;
+
+ } while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)));
+
+ return spins ? spins : -ETIMEDOUT;
+}
+
+static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd,
+ int fault_fatal)
+{
+ int status;
+ int phy_id = efx->mii.phy_id;
+
+ /* Read MMD STATUS2 to check it is responding. */
+ status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2);
+ if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
+ ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
+ MDIO_MMDREG_STAT2_PRESENT_VAL) {
+ EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd);
+ return -EIO;
+ }
+
+ /* Read MMD STATUS 1 to check for fault. */
+ status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1);
+ if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) {
+ if (fault_fatal) {
+ EFX_ERR(efx, "PHY MMD %d reporting fatal"
+ " fault: status %x\n", mmd, status);
+ return -EIO;
+ } else {
+ EFX_LOG(efx, "PHY MMD %d reporting status"
+ " %x (expected)\n", mmd, status);
+ }
+ }
+ return 0;
+}
+
+/* This ought to be ridiculous overkill. We expect it to fail rarely */
+#define MDIO45_RESET_TIME 1000 /* ms */
+#define MDIO45_RESET_ITERS 100
+
+int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask)
+{
+ const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS;
+ int tries = MDIO45_RESET_ITERS;
+ int rc = 0;
+ int in_reset;
+
+ while (tries) {
+ int mask = mmd_mask;
+ int mmd = 0;
+ int stat;
+ in_reset = 0;
+ while (mask) {
+ if (mask & 1) {
+ stat = mdio_clause45_read(efx,
+ efx->mii.phy_id,
+ mmd,
+ MDIO_MMDREG_CTRL1);
+ if (stat < 0) {
+ EFX_ERR(efx, "failed to read status of"
+ " MMD %d\n", mmd);
+ return -EIO;
+ }
+ if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
+ in_reset |= (1 << mmd);
+ }
+ mask = mask >> 1;
+ mmd++;
+ }
+ if (!in_reset)
+ break;
+ tries--;
+ msleep(spintime);
+ }
+ if (in_reset != 0) {
+ EFX_ERR(efx, "not all MMDs came out of reset in time."
+ " MMDs still in reset: %x\n", in_reset);
+ rc = -ETIMEDOUT;
+ }
+ return rc;
+}
+
+int mdio_clause45_check_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask, unsigned int fatal_mask)
+{
+ int devices, mmd = 0;
+ int probe_mmd;
+
+ /* Historically we have probed the PHYXS to find out what devices are
+ * present,but that doesn't work so well if the PHYXS isn't expected
+ * to exist, if so just find the first item in the list supplied. */
+ probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS :
+ __ffs(mmd_mask);
+ devices = mdio_clause45_read(efx, efx->mii.phy_id,
+ probe_mmd, MDIO_MMDREG_DEVS0);
+
+ /* Check all the expected MMDs are present */
+ if (devices < 0) {
+ EFX_ERR(efx, "failed to read devices present\n");
+ return -EIO;
+ }
+ if ((devices & mmd_mask) != mmd_mask) {
+ EFX_ERR(efx, "required MMDs not present: got %x, "
+ "wanted %x\n", devices, mmd_mask);
+ return -ENODEV;
+ }
+ EFX_TRACE(efx, "Devices present: %x\n", devices);
+
+ /* Check all required MMDs are responding and happy. */
+ while (mmd_mask) {
+ if (mmd_mask & 1) {
+ int fault_fatal = fatal_mask & 1;
+ if (mdio_clause45_check_mmd(efx, mmd, fault_fatal))
+ return -EIO;
+ }
+ mmd_mask = mmd_mask >> 1;
+ fatal_mask = fatal_mask >> 1;
+ mmd++;
+ }
+
+ return 0;
+}
+
+int mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
+{
+ int phy_id = efx->mii.phy_id;
+ int status;
+ int ok = 1;
+ int mmd = 0;
+ int good;
+
+ while (mmd_mask) {
+ if (mmd_mask & 1) {
+ /* Double reads because link state is latched, and a
+ * read moves the current state into the register */
+ status = mdio_clause45_read(efx, phy_id,
+ mmd, MDIO_MMDREG_STAT1);
+ status = mdio_clause45_read(efx, phy_id,
+ mmd, MDIO_MMDREG_STAT1);
+
+ good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
+ ok = ok && good;
+ }
+ mmd_mask = (mmd_mask >> 1);
+ mmd++;
+ }
+ return ok;
+}
+
+/**
+ * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
+ * @efx: Efx NIC
+ * @ecmd: Buffer for settings
+ *
+ * On return the 'port', 'speed', 'supported' and 'advertising' fields of
+ * ecmd have been filled out based on the PMA type.
+ */
+void mdio_clause45_get_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd)
+{
+ int pma_type;
+
+ /* If no PMA is present we are presumably talking something XAUI-ish
+ * like CX4. Which we report as FIBRE (see below) */
+ if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) {
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_FIBRE;
+ ecmd->advertising = ADVERTISED_FIBRE;
+ return;
+ }
+
+ pma_type = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2);
+ pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK;
+
+ switch (pma_type) {
+ /* We represent CX4 as fibre in the absence of anything
+ better. */
+ case MDIO_PMAPMD_CTRL2_10G_CX4:
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_FIBRE;
+ ecmd->advertising = ADVERTISED_FIBRE;
+ break;
+ /* 10G Base-T */
+ case MDIO_PMAPMD_CTRL2_10G_BT:
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full;
+ ecmd->advertising = (ADVERTISED_FIBRE
+ | ADVERTISED_10000baseT_Full);
+ break;
+ case MDIO_PMAPMD_CTRL2_1G_BT:
+ ecmd->speed = SPEED_1000;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full;
+ ecmd->advertising = (ADVERTISED_FIBRE
+ | ADVERTISED_1000baseT_Full);
+ break;
+ case MDIO_PMAPMD_CTRL2_100_BT:
+ ecmd->speed = SPEED_100;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full;
+ ecmd->advertising = (ADVERTISED_FIBRE
+ | ADVERTISED_100baseT_Full);
+ break;
+ case MDIO_PMAPMD_CTRL2_10_BT:
+ ecmd->speed = SPEED_10;
+ ecmd->port = PORT_TP;
+ ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full;
+ ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full;
+ break;
+ /* All the other defined modes are flavours of
+ * 10G optical */
+ default:
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ ecmd->supported = SUPPORTED_FIBRE;
+ ecmd->advertising = ADVERTISED_FIBRE;
+ break;
+ }
+}
+
+/**
+ * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO.
+ * @efx: Efx NIC
+ * @ecmd: New settings
+ *
+ * Currently this just enforces that we are _not_ changing the
+ * 'port', 'speed', 'supported' or 'advertising' settings as these
+ * cannot be changed on any currently supported PHY.
+ */
+int mdio_clause45_set_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd)
+{
+ struct ethtool_cmd tmpcmd;
+ mdio_clause45_get_settings(efx, &tmpcmd);
+ /* None of the current PHYs support more than one mode
+ * of operation (and only 10GBT ever will), so keep things
+ * simple for now */
+ if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) &&
+ (ecmd->supported == tmpcmd.supported) &&
+ (ecmd->advertising == tmpcmd.advertising))
+ return 0;
+ return -EOPNOTSUPP;
+}
diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h
new file mode 100644
index 0000000..2214b6d
--- /dev/null
+++ b/drivers/net/sfc/mdio_10g.h
@@ -0,0 +1,232 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_MDIO_10G_H
+#define EFX_MDIO_10G_H
+
+/*
+ * Definitions needed for doing 10G MDIO as specified in clause 45
+ * MDIO, which do not appear in Linux yet. Also some helper functions.
+ */
+
+#include "efx.h"
+#include "boards.h"
+
+/* Numbering of the MDIO Manageable Devices (MMDs) */
+/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
+#define MDIO_MMD_PMAPMD (1)
+/* WAN Interface Sublayer */
+#define MDIO_MMD_WIS (2)
+/* Physical Coding Sublayer */
+#define MDIO_MMD_PCS (3)
+/* PHY Extender Sublayer */
+#define MDIO_MMD_PHYXS (4)
+/* Extender Sublayer */
+#define MDIO_MMD_DTEXS (5)
+/* Transmission convergence */
+#define MDIO_MMD_TC (6)
+/* Auto negotiation */
+#define MDIO_MMD_AN (7)
+
+/* Generic register locations */
+#define MDIO_MMDREG_CTRL1 (0)
+#define MDIO_MMDREG_STAT1 (1)
+#define MDIO_MMDREG_IDHI (2)
+#define MDIO_MMDREG_IDLOW (3)
+#define MDIO_MMDREG_SPEED (4)
+#define MDIO_MMDREG_DEVS0 (5)
+#define MDIO_MMDREG_DEVS1 (6)
+#define MDIO_MMDREG_CTRL2 (7)
+#define MDIO_MMDREG_STAT2 (8)
+
+/* Bits in MMDREG_CTRL1 */
+/* Reset */
+#define MDIO_MMDREG_CTRL1_RESET_LBN (15)
+#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1)
+
+/* Bits in MMDREG_STAT1 */
+#define MDIO_MMDREG_STAT1_FAULT_LBN (7)
+#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1)
+/* Link state */
+#define MDIO_MMDREG_STAT1_LINK_LBN (2)
+#define MDIO_MMDREG_STAT1_LINK_WIDTH (1)
+
+/* Bits in ID reg */
+#define MDIO_ID_REV(_id32) (_id32 & 0xf)
+#define MDIO_ID_MODEL(_id32) ((_id32 >> 4) & 0x3f)
+#define MDIO_ID_OUI(_id32) (_id32 >> 10)
+
+/* Bits in MMDREG_DEVS0. Someone thoughtfully layed things out
+ * so the 'bit present' bit number of an MMD is the number of
+ * that MMD */
+#define DEV_PRESENT_BIT(_b) (1 << _b)
+
+#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
+#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS)
+#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
+
+/* Bits in MMDREG_STAT2 */
+#define MDIO_MMDREG_STAT2_PRESENT_VAL (2)
+#define MDIO_MMDREG_STAT2_PRESENT_LBN (14)
+#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
+
+/* PMA type (4 bits) */
+#define MDIO_PMAPMD_CTRL2_10G_CX4 (0x0)
+#define MDIO_PMAPMD_CTRL2_10G_EW (0x1)
+#define MDIO_PMAPMD_CTRL2_10G_LW (0x2)
+#define MDIO_PMAPMD_CTRL2_10G_SW (0x3)
+#define MDIO_PMAPMD_CTRL2_10G_LX4 (0x4)
+#define MDIO_PMAPMD_CTRL2_10G_ER (0x5)
+#define MDIO_PMAPMD_CTRL2_10G_LR (0x6)
+#define MDIO_PMAPMD_CTRL2_10G_SR (0x7)
+/* Reserved */
+#define MDIO_PMAPMD_CTRL2_10G_BT (0x9)
+/* Reserved */
+/* Reserved */
+#define MDIO_PMAPMD_CTRL2_1G_BT (0xc)
+/* Reserved */
+#define MDIO_PMAPMD_CTRL2_100_BT (0xe)
+#define MDIO_PMAPMD_CTRL2_10_BT (0xf)
+#define MDIO_PMAPMD_CTRL2_TYPE_MASK (0xf)
+
+/* /\* PHY XGXS lane state *\/ */
+#define MDIO_PHYXS_LANE_STATE (0x18)
+#define MDIO_PHYXS_LANE_ALIGNED_LBN (12)
+
+/* AN registers */
+#define MDIO_AN_STATUS (1)
+#define MDIO_AN_STATUS_XNP_LBN (7)
+#define MDIO_AN_STATUS_PAGE_LBN (6)
+#define MDIO_AN_STATUS_AN_DONE_LBN (5)
+#define MDIO_AN_STATUS_LP_AN_CAP_LBN (0)
+
+#define MDIO_AN_10GBT_STATUS (33)
+#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */
+#define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */
+#define MDIO_AN_10GBT_STATUS_LOC_OK_LBN (13) /* Local OK */
+#define MDIO_AN_10GBT_STATUS_REM_OK_LBN (12) /* Remote OK */
+#define MDIO_AN_10GBT_STATUS_LP_10G_LBN (11) /* Link partner is 10GBT capable */
+#define MDIO_AN_10GBT_STATUS_LP_LTA_LBN (10) /* LP loop timing ability */
+#define MDIO_AN_10GBT_STATUS_LP_TRR_LBN (9) /* LP Training Reset Request */
+
+
+/* Packing of the prt and dev arguments of clause 45 style MDIO into a
+ * single int so they can be passed into the mdio_read/write functions
+ * that currently exist. Note that as Falcon is the only current user,
+ * the packed form is chosen to match what Falcon needs to write into
+ * a register. This is checked at compile-time so do not change it. If
+ * your target chip needs things layed out differently you will need
+ * to unpack the arguments in your chip-specific mdio functions.
+ */
+ /* These are defined by the standard. */
+#define MDIO45_PRT_ID_WIDTH (5)
+#define MDIO45_DEV_ID_WIDTH (5)
+
+/* The prt ID is just packed in immediately to the left of the dev ID */
+#define MDIO45_PRT_DEV_WIDTH (MDIO45_PRT_ID_WIDTH + MDIO45_DEV_ID_WIDTH)
+
+#define MDIO45_PRT_ID_MASK ((1 << MDIO45_PRT_DEV_WIDTH) - 1)
+/* This is the prt + dev extended by 1 bit to hold the 'is clause 45' flag. */
+#define MDIO45_XPRT_ID_WIDTH (MDIO45_PRT_DEV_WIDTH + 1)
+#define MDIO45_XPRT_ID_MASK ((1 << MDIO45_XPRT_ID_WIDTH) - 1)
+#define MDIO45_XPRT_ID_IS10G (1 << (MDIO45_XPRT_ID_WIDTH - 1))
+
+
+#define MDIO45_PRT_ID_COMP_LBN MDIO45_DEV_ID_WIDTH
+#define MDIO45_PRT_ID_COMP_WIDTH MDIO45_PRT_ID_WIDTH
+#define MDIO45_DEV_ID_COMP_LBN 0
+#define MDIO45_DEV_ID_COMP_WIDTH MDIO45_DEV_ID_WIDTH
+
+/* Compose port and device into a phy_id */
+static inline int mdio_clause45_pack(u8 prt, u8 dev)
+{
+ efx_dword_t phy_id;
+ EFX_POPULATE_DWORD_2(phy_id, MDIO45_PRT_ID_COMP, prt,
+ MDIO45_DEV_ID_COMP, dev);
+ return MDIO45_XPRT_ID_IS10G | EFX_DWORD_VAL(phy_id);
+}
+
+static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev)
+{
+ efx_dword_t phy_id;
+ EFX_POPULATE_DWORD_1(phy_id, EFX_DWORD_0, val);
+ *prt = EFX_DWORD_FIELD(phy_id, MDIO45_PRT_ID_COMP);
+ *dev = EFX_DWORD_FIELD(phy_id, MDIO45_DEV_ID_COMP);
+}
+
+static inline int mdio_clause45_read(struct efx_nic *efx,
+ u8 prt, u8 dev, u16 addr)
+{
+ return efx->mii.mdio_read(efx->net_dev,
+ mdio_clause45_pack(prt, dev), addr);
+}
+
+static inline void mdio_clause45_write(struct efx_nic *efx,
+ u8 prt, u8 dev, u16 addr, int value)
+{
+ efx->mii.mdio_write(efx->net_dev,
+ mdio_clause45_pack(prt, dev), addr, value);
+}
+
+
+static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd)
+{
+ int phy_id = efx->mii.phy_id;
+ u16 id_low = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW);
+ u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI);
+ return (id_hi << 16) | (id_low);
+}
+
+static inline int mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx)
+{
+ int i, sync, lane_status;
+
+ for (i = 0; i < 2; ++i)
+ lane_status = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PHYXS,
+ MDIO_PHYXS_LANE_STATE);
+
+ sync = (lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)) != 0;
+ if (!sync)
+ EFX_INFO(efx, "XGXS lane status: %x\n", lane_status);
+ return sync;
+}
+
+extern const char *mdio_clause45_mmd_name(int mmd);
+
+/*
+ * Reset a specific MMD and wait for reset to clear.
+ * Return number of spins left (>0) on success, -%ETIMEDOUT on failure.
+ *
+ * This function will sleep
+ */
+extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd,
+ int spins, int spintime);
+
+/* As mdio_clause45_check_mmd but for multiple MMDs */
+int mdio_clause45_check_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask, unsigned int fatal_mask);
+
+/* Check the link status of specified mmds in bit mask */
+extern int mdio_clause45_links_ok(struct efx_nic *efx,
+ unsigned int mmd_mask);
+
+/* Read (some of) the PHY settings over MDIO */
+extern void mdio_clause45_get_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+
+/* Set (some of) the PHY settings over MDIO */
+extern int mdio_clause45_set_settings(struct efx_nic *efx,
+ struct ethtool_cmd *ecmd);
+
+/* Wait for specified MMDs to exit reset within a timeout */
+extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
+ unsigned int mmd_mask);
+
+#endif /* EFX_MDIO_10G_H */
diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h
new file mode 100644
index 0000000..c505482
--- /dev/null
+++ b/drivers/net/sfc/net_driver.h
@@ -0,0 +1,883 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+/* Common definitions for all Efx net driver code */
+
+#ifndef EFX_NET_DRIVER_H
+#define EFX_NET_DRIVER_H
+
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/timer.h>
+#include <linux/mii.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/highmem.h>
+#include <linux/workqueue.h>
+#include <linux/inet_lro.h>
+
+#include "enum.h"
+#include "bitfield.h"
+#include "i2c-direct.h"
+
+#define EFX_MAX_LRO_DESCRIPTORS 8
+#define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS
+
+/**************************************************************************
+ *
+ * Build definitions
+ *
+ **************************************************************************/
+#ifndef EFX_DRIVER_NAME
+#define EFX_DRIVER_NAME "sfc"
+#endif
+#define EFX_DRIVER_VERSION "2.2.0136"
+
+#ifdef EFX_ENABLE_DEBUG
+#define EFX_BUG_ON_PARANOID(x) BUG_ON(x)
+#define EFX_WARN_ON_PARANOID(x) WARN_ON(x)
+#else
+#define EFX_BUG_ON_PARANOID(x) do {} while (0)
+#define EFX_WARN_ON_PARANOID(x) do {} while (0)
+#endif
+
+#define NET_DEV_REGISTERED(efx) \
+ ((efx)->net_dev->reg_state == NETREG_REGISTERED)
+
+/* Include net device name in log messages if it has been registered.
+ * Use efx->name not efx->net_dev->name so that races with (un)registration
+ * are harmless.
+ */
+#define NET_DEV_NAME(efx) (NET_DEV_REGISTERED(efx) ? (efx)->name : "")
+
+/* Un-rate-limited logging */
+#define EFX_ERR(efx, fmt, args...) \
+dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, NET_DEV_NAME(efx), ##args)
+
+#define EFX_INFO(efx, fmt, args...) \
+dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, NET_DEV_NAME(efx), ##args)
+
+#ifdef EFX_ENABLE_DEBUG
+#define EFX_LOG(efx, fmt, args...) \
+dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+#else
+#define EFX_LOG(efx, fmt, args...) \
+dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
+#endif
+
+#define EFX_TRACE(efx, fmt, args...) do {} while (0)
+
+#define EFX_REGDUMP(efx, fmt, args...) do {} while (0)
+
+/* Rate-limited logging */
+#define EFX_ERR_RL(efx, fmt, args...) \
+do {if (net_ratelimit()) EFX_ERR(efx, fmt, ##args); } while (0)
+
+#define EFX_INFO_RL(efx, fmt, args...) \
+do {if (net_ratelimit()) EFX_INFO(efx, fmt, ##args); } while (0)
+
+#define EFX_LOG_RL(efx, fmt, args...) \
+do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
+
+/* Kernel headers may redefine inline anyway */
+#ifndef inline
+#define inline inline __attribute__ ((always_inline))
+#endif
+
+/**************************************************************************
+ *
+ * Efx data structures
+ *
+ **************************************************************************/
+
+#define EFX_MAX_CHANNELS 32
+#define EFX_MAX_TX_QUEUES 1
+#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
+
+/**
+ * struct efx_special_buffer - An Efx special buffer
+ * @addr: CPU base address of the buffer
+ * @dma_addr: DMA base address of the buffer
+ * @len: Buffer length, in bytes
+ * @index: Buffer index within controller;s buffer table
+ * @entries: Number of buffer table entries
+ *
+ * Special buffers are used for the event queues and the TX and RX
+ * descriptor queues for each channel. They are *not* used for the
+ * actual transmit and receive buffers.
+ *
+ * Note that for Falcon, TX and RX descriptor queues live in host memory.
+ * Allocation and freeing procedures must take this into account.
+ */
+struct efx_special_buffer {
+ void *addr;
+ dma_addr_t dma_addr;
+ unsigned int len;
+ int index;
+ int entries;
+};
+
+/**
+ * struct efx_tx_buffer - An Efx TX buffer
+ * @skb: The associated socket buffer.
+ * Set only on the final fragment of a packet; %NULL for all other
+ * fragments. When this fragment completes, then we can free this
+ * skb.
+ * @dma_addr: DMA address of the fragment.
+ * @len: Length of this fragment.
+ * This field is zero when the queue slot is empty.
+ * @continuation: True if this fragment is not the end of a packet.
+ * @unmap_single: True if pci_unmap_single should be used.
+ * @unmap_addr: DMA address to unmap
+ * @unmap_len: Length of this fragment to unmap
+ */
+struct efx_tx_buffer {
+ const struct sk_buff *skb;
+ dma_addr_t dma_addr;
+ unsigned short len;
+ unsigned char continuation;
+ unsigned char unmap_single;
+ dma_addr_t unmap_addr;
+ unsigned short unmap_len;
+};
+
+/**
+ * struct efx_tx_queue - An Efx TX queue
+ *
+ * This is a ring buffer of TX fragments.
+ * Since the TX completion path always executes on the same
+ * CPU and the xmit path can operate on different CPUs,
+ * performance is increased by ensuring that the completion
+ * path and the xmit path operate on different cache lines.
+ * This is particularly important if the xmit path is always
+ * executing on one CPU which is different from the completion
+ * path. There is also a cache line for members which are
+ * read but not written on the fast path.
+ *
+ * @efx: The associated Efx NIC
+ * @queue: DMA queue number
+ * @used: Queue is used by net driver
+ * @channel: The associated channel
+ * @buffer: The software buffer ring
+ * @txd: The hardware descriptor ring
+ * @read_count: Current read pointer.
+ * This is the number of buffers that have been removed from both rings.
+ * @stopped: Stopped flag.
+ * Set if this TX queue is currently stopping its port.
+ * @insert_count: Current insert pointer
+ * This is the number of buffers that have been added to the
+ * software ring.
+ * @write_count: Current write pointer
+ * This is the number of buffers that have been added to the
+ * hardware ring.
+ * @old_read_count: The value of read_count when last checked.
+ * This is here for performance reasons. The xmit path will
+ * only get the up-to-date value of read_count if this
+ * variable indicates that the queue is full. This is to
+ * avoid cache-line ping-pong between the xmit path and the
+ * completion path.
+ */
+struct efx_tx_queue {
+ /* Members which don't change on the fast path */
+ struct efx_nic *efx ____cacheline_aligned_in_smp;
+ int queue;
+ int used;
+ struct efx_channel *channel;
+ struct efx_nic *nic;
+ struct efx_tx_buffer *buffer;
+ struct efx_special_buffer txd;
+
+ /* Members used mainly on the completion path */
+ unsigned int read_count ____cacheline_aligned_in_smp;
+ int stopped;
+
+ /* Members used only on the xmit path */
+ unsigned int insert_count ____cacheline_aligned_in_smp;
+ unsigned int write_count;
+ unsigned int old_read_count;
+};
+
+/**
+ * struct efx_rx_buffer - An Efx RX data buffer
+ * @dma_addr: DMA base address of the buffer
+ * @skb: The associated socket buffer, if any.
+ * If both this and page are %NULL, the buffer slot is currently free.
+ * @page: The associated page buffer, if any.
+ * If both this and skb are %NULL, the buffer slot is currently free.
+ * @data: Pointer to ethernet header
+ * @len: Buffer length, in bytes.
+ * @unmap_addr: DMA address to unmap
+ */
+struct efx_rx_buffer {
+ dma_addr_t dma_addr;
+ struct sk_buff *skb;
+ struct page *page;
+ char *data;
+ unsigned int len;
+ dma_addr_t unmap_addr;
+};
+
+/**
+ * struct efx_rx_queue - An Efx RX queue
+ * @efx: The associated Efx NIC
+ * @queue: DMA queue number
+ * @used: Queue is used by net driver
+ * @channel: The associated channel
+ * @buffer: The software buffer ring
+ * @rxd: The hardware descriptor ring
+ * @added_count: Number of buffers added to the receive queue.
+ * @notified_count: Number of buffers given to NIC (<= @added_count).
+ * @removed_count: Number of buffers removed from the receive queue.
+ * @add_lock: Receive queue descriptor add spin lock.
+ * This lock must be held in order to add buffers to the RX
+ * descriptor ring (rxd and buffer) and to update added_count (but
+ * not removed_count).
+ * @max_fill: RX descriptor maximum fill level (<= ring size)
+ * @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
+ * (<= @max_fill)
+ * @fast_fill_limit: The level to which a fast fill will fill
+ * (@fast_fill_trigger <= @fast_fill_limit <= @max_fill)
+ * @min_fill: RX descriptor minimum non-zero fill level.
+ * This records the minimum fill level observed when a ring
+ * refill was triggered.
+ * @min_overfill: RX descriptor minimum overflow fill level.
+ * This records the minimum fill level at which RX queue
+ * overflow was observed. It should never be set.
+ * @alloc_page_count: RX allocation strategy counter.
+ * @alloc_skb_count: RX allocation strategy counter.
+ * @work: Descriptor push work thread
+ * @buf_page: Page for next RX buffer.
+ * We can use a single page for multiple RX buffers. This tracks
+ * the remaining space in the allocation.
+ * @buf_dma_addr: Page's DMA address.
+ * @buf_data: Page's host address.
+ */
+struct efx_rx_queue {
+ struct efx_nic *efx;
+ int queue;
+ int used;
+ struct efx_channel *channel;
+ struct efx_rx_buffer *buffer;
+ struct efx_special_buffer rxd;
+
+ int added_count;
+ int notified_count;
+ int removed_count;
+ spinlock_t add_lock;
+ unsigned int max_fill;
+ unsigned int fast_fill_trigger;
+ unsigned int fast_fill_limit;
+ unsigned int min_fill;
+ unsigned int min_overfill;
+ unsigned int alloc_page_count;
+ unsigned int alloc_skb_count;
+ struct delayed_work work;
+ unsigned int slow_fill_count;
+
+ struct page *buf_page;
+ dma_addr_t buf_dma_addr;
+ char *buf_data;
+};
+
+/**
+ * struct efx_buffer - An Efx general-purpose buffer
+ * @addr: host base address of the buffer
+ * @dma_addr: DMA base address of the buffer
+ * @len: Buffer length, in bytes
+ *
+ * Falcon uses these buffers for its interrupt status registers and
+ * MAC stats dumps.
+ */
+struct efx_buffer {
+ void *addr;
+ dma_addr_t dma_addr;
+ unsigned int len;
+};
+
+
+/* Flags for channel->used_flags */
+#define EFX_USED_BY_RX 1
+#define EFX_USED_BY_TX 2
+#define EFX_USED_BY_RX_TX (EFX_USED_BY_RX | EFX_USED_BY_TX)
+
+enum efx_rx_alloc_method {
+ RX_ALLOC_METHOD_AUTO = 0,
+ RX_ALLOC_METHOD_SKB = 1,
+ RX_ALLOC_METHOD_PAGE = 2,
+};
+
+/**
+ * struct efx_channel - An Efx channel
+ *
+ * A channel comprises an event queue, at least one TX queue, at least
+ * one RX queue, and an associated tasklet for processing the event
+ * queue.
+ *
+ * @efx: Associated Efx NIC
+ * @evqnum: Event queue number
+ * @channel: Channel instance number
+ * @used_flags: Channel is used by net driver
+ * @enabled: Channel enabled indicator
+ * @irq: IRQ number (MSI and MSI-X only)
+ * @has_interrupt: Channel has an interrupt
+ * @irq_moderation: IRQ moderation value (in us)
+ * @napi_dev: Net device used with NAPI
+ * @napi_str: NAPI control structure
+ * @reset_work: Scheduled reset work thread
+ * @work_pending: Is work pending via NAPI?
+ * @eventq: Event queue buffer
+ * @eventq_read_ptr: Event queue read pointer
+ * @last_eventq_read_ptr: Last event queue read pointer value.
+ * @eventq_magic: Event queue magic value for driver-generated test events
+ * @lro_mgr: LRO state
+ * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
+ * and diagnostic counters
+ * @rx_alloc_push_pages: RX allocation method currently in use for pushing
+ * descriptors
+ * @rx_alloc_pop_pages: RX allocation method currently in use for popping
+ * descriptors
+ * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors
+ * @n_rx_ip_frag_err: Count of RX IP fragment errors
+ * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors
+ * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors
+ * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
+ * @n_rx_overlength: Count of RX_OVERLENGTH errors
+ * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
+ */
+struct efx_channel {
+ struct efx_nic *efx;
+ int evqnum;
+ int channel;
+ int used_flags;
+ int enabled;
+ int irq;
+ unsigned int has_interrupt;
+ unsigned int irq_moderation;
+ struct net_device *napi_dev;
+ struct napi_struct napi_str;
+ struct work_struct reset_work;
+ int work_pending;
+ struct efx_special_buffer eventq;
+ unsigned int eventq_read_ptr;
+ unsigned int last_eventq_read_ptr;
+ unsigned int eventq_magic;
+
+ struct net_lro_mgr lro_mgr;
+ int rx_alloc_level;
+ int rx_alloc_push_pages;
+ int rx_alloc_pop_pages;
+
+ unsigned n_rx_tobe_disc;
+ unsigned n_rx_ip_frag_err;
+ unsigned n_rx_ip_hdr_chksum_err;
+ unsigned n_rx_tcp_udp_chksum_err;
+ unsigned n_rx_frm_trunc;
+ unsigned n_rx_overlength;
+ unsigned n_skbuff_leaks;
+
+ /* Used to pipeline received packets in order to optimise memory
+ * access with prefetches.
+ */
+ struct efx_rx_buffer *rx_pkt;
+ int rx_pkt_csummed;
+
+};
+
+/**
+ * struct efx_blinker - S/W LED blinking context
+ * @led_num: LED ID (board-specific meaning)
+ * @state: Current state - on or off
+ * @resubmit: Timer resubmission flag
+ * @timer: Control timer for blinking
+ */
+struct efx_blinker {
+ int led_num;
+ int state;
+ int resubmit;
+ struct timer_list timer;
+};
+
+
+/**
+ * struct efx_board - board information
+ * @type: Board model type
+ * @major: Major rev. ('A', 'B' ...)
+ * @minor: Minor rev. (0, 1, ...)
+ * @init: Initialisation function
+ * @init_leds: Sets up board LEDs
+ * @set_fault_led: Turns the fault LED on or off
+ * @blink: Starts/stops blinking
+ * @blinker: used to blink LEDs in software
+ */
+struct efx_board {
+ int type;
+ int major;
+ int minor;
+ int (*init) (struct efx_nic *nic);
+ /* As the LEDs are typically attached to the PHY, LEDs
+ * have a separate init callback that happens later than
+ * board init. */
+ int (*init_leds)(struct efx_nic *efx);
+ void (*set_fault_led) (struct efx_nic *efx, int state);
+ void (*blink) (struct efx_nic *efx, int start);
+ struct efx_blinker blinker;
+};
+
+enum efx_int_mode {
+ /* Be careful if altering to correct macro below */
+ EFX_INT_MODE_MSIX = 0,
+ EFX_INT_MODE_MSI = 1,
+ EFX_INT_MODE_LEGACY = 2,
+ EFX_INT_MODE_MAX /* Insert any new items before this */
+};
+#define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI)
+
+enum phy_type {
+ PHY_TYPE_NONE = 0,
+ PHY_TYPE_CX4_RTMR = 1,
+ PHY_TYPE_1G_ALASKA = 2,
+ PHY_TYPE_10XPRESS = 3,
+ PHY_TYPE_XFP = 4,
+ PHY_TYPE_PM8358 = 6,
+ PHY_TYPE_MAX /* Insert any new items before this */
+};
+
+#define PHY_ADDR_INVALID 0xff
+
+enum nic_state {
+ STATE_INIT = 0,
+ STATE_RUNNING = 1,
+ STATE_FINI = 2,
+ STATE_RESETTING = 3, /* rtnl_lock always held */
+ STATE_DISABLED = 4,
+ STATE_MAX,
+};
+
+/*
+ * Alignment of page-allocated RX buffers
+ *
+ * Controls the number of bytes inserted at the start of an RX buffer.
+ * This is the equivalent of NET_IP_ALIGN [which controls the alignment
+ * of the skb->head for hardware DMA].
+ */
+#if defined(__i386__) || defined(__x86_64__)
+#define EFX_PAGE_IP_ALIGN 0
+#else
+#define EFX_PAGE_IP_ALIGN NET_IP_ALIGN
+#endif
+
+/*
+ * Alignment of the skb->head which wraps a page-allocated RX buffer
+ *
+ * The skb allocated to wrap an rx_buffer can have this alignment. Since
+ * the data is memcpy'd from the rx_buf, it does not need to be equal to
+ * EFX_PAGE_IP_ALIGN.
+ */
+#define EFX_PAGE_SKB_ALIGN 2
+
+/* Forward declaration */
+struct efx_nic;
+
+/* Pseudo bit-mask flow control field */
+enum efx_fc_type {
+ EFX_FC_RX = 1,
+ EFX_FC_TX = 2,
+ EFX_FC_AUTO = 4,
+};
+
+/**
+ * struct efx_phy_operations - Efx PHY operations table
+ * @init: Initialise PHY
+ * @fini: Shut down PHY
+ * @reconfigure: Reconfigure PHY (e.g. for new link parameters)
+ * @clear_interrupt: Clear down interrupt
+ * @blink: Blink LEDs
+ * @check_hw: Check hardware
+ * @reset_xaui: Reset XAUI side of PHY for (software sequenced reset)
+ * @mmds: MMD presence mask
+ */
+struct efx_phy_operations {
+ int (*init) (struct efx_nic *efx);
+ void (*fini) (struct efx_nic *efx);
+ void (*reconfigure) (struct efx_nic *efx);
+ void (*clear_interrupt) (struct efx_nic *efx);
+ int (*check_hw) (struct efx_nic *efx);
+ void (*reset_xaui) (struct efx_nic *efx);
+ int mmds;
+};
+
+/*
+ * Efx extended statistics
+ *
+ * Not all statistics are provided by all supported MACs. The purpose
+ * is this structure is to contain the raw statistics provided by each
+ * MAC.
+ */
+struct efx_mac_stats {
+ u64 tx_bytes;
+ u64 tx_good_bytes;
+ u64 tx_bad_bytes;
+ unsigned long tx_packets;
+ unsigned long tx_bad;
+ unsigned long tx_pause;
+ unsigned long tx_control;
+ unsigned long tx_unicast;
+ unsigned long tx_multicast;
+ unsigned long tx_broadcast;
+ unsigned long tx_lt64;
+ unsigned long tx_64;
+ unsigned long tx_65_to_127;
+ unsigned long tx_128_to_255;
+ unsigned long tx_256_to_511;
+ unsigned long tx_512_to_1023;
+ unsigned long tx_1024_to_15xx;
+ unsigned long tx_15xx_to_jumbo;
+ unsigned long tx_gtjumbo;
+ unsigned long tx_collision;
+ unsigned long tx_single_collision;
+ unsigned long tx_multiple_collision;
+ unsigned long tx_excessive_collision;
+ unsigned long tx_deferred;
+ unsigned long tx_late_collision;
+ unsigned long tx_excessive_deferred;
+ unsigned long tx_non_tcpudp;
+ unsigned long tx_mac_src_error;
+ unsigned long tx_ip_src_error;
+ u64 rx_bytes;
+ u64 rx_good_bytes;
+ u64 rx_bad_bytes;
+ unsigned long rx_packets;
+ unsigned long rx_good;
+ unsigned long rx_bad;
+ unsigned long rx_pause;
+ unsigned long rx_control;
+ unsigned long rx_unicast;
+ unsigned long rx_multicast;
+ unsigned long rx_broadcast;
+ unsigned long rx_lt64;
+ unsigned long rx_64;
+ unsigned long rx_65_to_127;
+ unsigned long rx_128_to_255;
+ unsigned long rx_256_to_511;
+ unsigned long rx_512_to_1023;
+ unsigned long rx_1024_to_15xx;
+ unsigned long rx_15xx_to_jumbo;
+ unsigned long rx_gtjumbo;
+ unsigned long rx_bad_lt64;
+ unsigned long rx_bad_64_to_15xx;
+ unsigned long rx_bad_15xx_to_jumbo;
+ unsigned long rx_bad_gtjumbo;
+ unsigned long rx_overflow;
+ unsigned long rx_missed;
+ unsigned long rx_false_carrier;
+ unsigned long rx_symbol_error;
+ unsigned long rx_align_error;
+ unsigned long rx_length_error;
+ unsigned long rx_internal_error;
+ unsigned long rx_good_lt64;
+};
+
+/* Number of bits used in a multicast filter hash address */
+#define EFX_MCAST_HASH_BITS 8
+
+/* Number of (single-bit) entries in a multicast filter hash */
+#define EFX_MCAST_HASH_ENTRIES (1 << EFX_MCAST_HASH_BITS)
+
+/* An Efx multicast filter hash */
+union efx_multicast_hash {
+ u8 byte[EFX_MCAST_HASH_ENTRIES / 8];
+ efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t) / 8];
+};
+
+/**
+ * struct efx_nic - an Efx NIC
+ * @name: Device name (net device name or bus id before net device registered)
+ * @pci_dev: The PCI device
+ * @type: Controller type attributes
+ * @legacy_irq: IRQ number
+ * @workqueue: Workqueue for resets, port reconfigures and the HW monitor
+ * @reset_work: Scheduled reset workitem
+ * @monitor_work: Hardware monitor workitem
+ * @membase_phys: Memory BAR value as physical address
+ * @membase: Memory BAR value
+ * @biu_lock: BIU (bus interface unit) lock
+ * @interrupt_mode: Interrupt mode
+ * @i2c: I2C interface
+ * @board_info: Board-level information
+ * @state: Device state flag. Serialised by the rtnl_lock.
+ * @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
+ * @tx_queue: TX DMA queues
+ * @rx_queue: RX DMA queues
+ * @channel: Channels
+ * @rss_queues: Number of RSS queues
+ * @rx_buffer_len: RX buffer length
+ * @rx_buffer_order: Order (log2) of number of pages for each RX buffer
+ * @irq_status: Interrupt status buffer
+ * @last_irq_cpu: Last CPU to handle interrupt.
+ * This register is written with the SMP processor ID whenever an
+ * interrupt is handled. It is used by falcon_test_interrupt()
+ * to verify that an interrupt has occurred.
+ * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
+ * @nic_data: Hardware dependant state
+ * @mac_lock: MAC access lock. Protects @port_enabled, efx_monitor() and
+ * efx_reconfigure_port()
+ * @port_enabled: Port enabled indicator.
+ * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and
+ * efx_reconfigure_work with kernel interfaces. Safe to read under any
+ * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must
+ * be held to modify it.
+ * @port_initialized: Port initialized?
+ * @net_dev: Operating system network device. Consider holding the rtnl lock
+ * @rx_checksum_enabled: RX checksumming enabled
+ * @netif_stop_count: Port stop count
+ * @netif_stop_lock: Port stop lock
+ * @mac_stats: MAC statistics. These include all statistics the MACs
+ * can provide. Generic code converts these into a standard
+ * &struct net_device_stats.
+ * @stats_buffer: DMA buffer for statistics
+ * @stats_lock: Statistics update lock
+ * @mac_address: Permanent MAC address
+ * @phy_type: PHY type
+ * @phy_lock: PHY access lock
+ * @phy_op: PHY interface
+ * @phy_data: PHY private data (including PHY-specific stats)
+ * @mii: PHY interface
+ * @phy_powered: PHY power state
+ * @tx_disabled: PHY transmitter turned off
+ * @link_up: Link status
+ * @link_options: Link options (MII/GMII format)
+ * @n_link_state_changes: Number of times the link has changed state
+ * @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
+ * @multicast_hash: Multicast hash table
+ * @flow_control: Flow control flags - separate RX/TX so can't use link_options
+ * @reconfigure_work: work item for dealing with PHY events
+ *
+ * The @priv field of the corresponding &struct net_device points to
+ * this.
+ */
+struct efx_nic {
+ char name[IFNAMSIZ];
+ struct pci_dev *pci_dev;
+ const struct efx_nic_type *type;
+ int legacy_irq;
+ struct workqueue_struct *workqueue;
+ struct work_struct reset_work;
+ struct delayed_work monitor_work;
+ unsigned long membase_phys;
+ void __iomem *membase;
+ spinlock_t biu_lock;
+ enum efx_int_mode interrupt_mode;
+
+ struct efx_i2c_interface i2c;
+ struct efx_board board_info;
+
+ enum nic_state state;
+ enum reset_type reset_pending;
+
+ struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
+ struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
+ struct efx_channel channel[EFX_MAX_CHANNELS];
+
+ int rss_queues;
+ unsigned int rx_buffer_len;
+ unsigned int rx_buffer_order;
+
+ struct efx_buffer irq_status;
+ volatile signed int last_irq_cpu;
+
+ unsigned n_rx_nodesc_drop_cnt;
+
+ void *nic_data;
+
+ struct mutex mac_lock;
+ int port_enabled;
+
+ int port_initialized;
+ struct net_device *net_dev;
+ int rx_checksum_enabled;
+
+ atomic_t netif_stop_count;
+ spinlock_t netif_stop_lock;
+
+ struct efx_mac_stats mac_stats;
+ struct efx_buffer stats_buffer;
+ spinlock_t stats_lock;
+
+ unsigned char mac_address[ETH_ALEN];
+
+ enum phy_type phy_type;
+ spinlock_t phy_lock;
+ struct efx_phy_operations *phy_op;
+ void *phy_data;
+ struct mii_if_info mii;
+
+ int link_up;
+ unsigned int link_options;
+ unsigned int n_link_state_changes;
+
+ int promiscuous;
+ union efx_multicast_hash multicast_hash;
+ enum efx_fc_type flow_control;
+ struct work_struct reconfigure_work;
+
+ atomic_t rx_reset;
+};
+
+/**
+ * struct efx_nic_type - Efx device type definition
+ * @mem_bar: Memory BAR number
+ * @mem_map_size: Memory BAR mapped size
+ * @txd_ptr_tbl_base: TX descriptor ring base address
+ * @rxd_ptr_tbl_base: RX descriptor ring base address
+ * @buf_tbl_base: Buffer table base address
+ * @evq_ptr_tbl_base: Event queue pointer table base address
+ * @evq_rptr_tbl_base: Event queue read-pointer table base address
+ * @txd_ring_mask: TX descriptor ring size - 1 (must be a power of two - 1)
+ * @rxd_ring_mask: RX descriptor ring size - 1 (must be a power of two - 1)
+ * @evq_size: Event queue size (must be a power of two)
+ * @max_dma_mask: Maximum possible DMA mask
+ * @tx_dma_mask: TX DMA mask
+ * @bug5391_mask: Address mask for bug 5391 workaround
+ * @rx_xoff_thresh: RX FIFO XOFF watermark (bytes)
+ * @rx_xon_thresh: RX FIFO XON watermark (bytes)
+ * @rx_buffer_padding: Padding added to each RX buffer
+ * @max_interrupt_mode: Highest capability interrupt mode supported
+ * from &enum efx_init_mode.
+ * @phys_addr_channels: Number of channels with physically addressed
+ * descriptors
+ */
+struct efx_nic_type {
+ unsigned int mem_bar;
+ unsigned int mem_map_size;
+ unsigned int txd_ptr_tbl_base;
+ unsigned int rxd_ptr_tbl_base;
+ unsigned int buf_tbl_base;
+ unsigned int evq_ptr_tbl_base;
+ unsigned int evq_rptr_tbl_base;
+
+ unsigned int txd_ring_mask;
+ unsigned int rxd_ring_mask;
+ unsigned int evq_size;
+ dma_addr_t max_dma_mask;
+ unsigned int tx_dma_mask;
+ unsigned bug5391_mask;
+
+ int rx_xoff_thresh;
+ int rx_xon_thresh;
+ unsigned int rx_buffer_padding;
+ unsigned int max_interrupt_mode;
+ unsigned int phys_addr_channels;
+};
+
+/**************************************************************************
+ *
+ * Prototypes and inline functions
+ *
+ *************************************************************************/
+
+/* Iterate over all used channels */
+#define efx_for_each_channel(_channel, _efx) \
+ for (_channel = &_efx->channel[0]; \
+ _channel < &_efx->channel[EFX_MAX_CHANNELS]; \
+ _channel++) \
+ if (!_channel->used_flags) \
+ continue; \
+ else
+
+/* Iterate over all used channels with interrupts */
+#define efx_for_each_channel_with_interrupt(_channel, _efx) \
+ for (_channel = &_efx->channel[0]; \
+ _channel < &_efx->channel[EFX_MAX_CHANNELS]; \
+ _channel++) \
+ if (!(_channel->used_flags && _channel->has_interrupt)) \
+ continue; \
+ else
+
+/* Iterate over all used TX queues */
+#define efx_for_each_tx_queue(_tx_queue, _efx) \
+ for (_tx_queue = &_efx->tx_queue[0]; \
+ _tx_queue < &_efx->tx_queue[EFX_MAX_TX_QUEUES]; \
+ _tx_queue++) \
+ if (!_tx_queue->used) \
+ continue; \
+ else
+
+/* Iterate over all TX queues belonging to a channel */
+#define efx_for_each_channel_tx_queue(_tx_queue, _channel) \
+ for (_tx_queue = &_channel->efx->tx_queue[0]; \
+ _tx_queue < &_channel->efx->tx_queue[EFX_MAX_TX_QUEUES]; \
+ _tx_queue++) \
+ if ((!_tx_queue->used) || \
+ (_tx_queue->channel != _channel)) \
+ continue; \
+ else
+
+/* Iterate over all used RX queues */
+#define efx_for_each_rx_queue(_rx_queue, _efx) \
+ for (_rx_queue = &_efx->rx_queue[0]; \
+ _rx_queue < &_efx->rx_queue[EFX_MAX_RX_QUEUES]; \
+ _rx_queue++) \
+ if (!_rx_queue->used) \
+ continue; \
+ else
+
+/* Iterate over all RX queues belonging to a channel */
+#define efx_for_each_channel_rx_queue(_rx_queue, _channel) \
+ for (_rx_queue = &_channel->efx->rx_queue[0]; \
+ _rx_queue < &_channel->efx->rx_queue[EFX_MAX_RX_QUEUES]; \
+ _rx_queue++) \
+ if ((!_rx_queue->used) || \
+ (_rx_queue->channel != _channel)) \
+ continue; \
+ else
+
+/* Returns a pointer to the specified receive buffer in the RX
+ * descriptor queue.
+ */
+static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue,
+ unsigned int index)
+{
+ return (&rx_queue->buffer[index]);
+}
+
+/* Set bit in a little-endian bitfield */
+static inline void set_bit_le(int nr, unsigned char *addr)
+{
+ addr[nr / 8] |= (1 << (nr % 8));
+}
+
+/* Clear bit in a little-endian bitfield */
+static inline void clear_bit_le(int nr, unsigned char *addr)
+{
+ addr[nr / 8] &= ~(1 << (nr % 8));
+}
+
+
+/**
+ * EFX_MAX_FRAME_LEN - calculate maximum frame length
+ *
+ * This calculates the maximum frame length that will be used for a
+ * given MTU. The frame length will be equal to the MTU plus a
+ * constant amount of header space and padding. This is the quantity
+ * that the net driver will program into the MAC as the maximum frame
+ * length.
+ *
+ * The 10G MAC used in Falcon requires 8-byte alignment on the frame
+ * length, so we round up to the nearest 8.
+ */
+#define EFX_MAX_FRAME_LEN(mtu) \
+ ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */) + 7) & ~7)
+
+
+#endif /* EFX_NET_DRIVER_H */
diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h
new file mode 100644
index 0000000..9d02c84
--- /dev/null
+++ b/drivers/net/sfc/phy.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_PHY_H
+#define EFX_PHY_H
+
+/****************************************************************************
+ * 10Xpress (SFX7101) PHY
+ */
+extern struct efx_phy_operations falcon_tenxpress_phy_ops;
+
+enum tenxpress_state {
+ TENXPRESS_STATUS_OFF = 0,
+ TENXPRESS_STATUS_OTEMP = 1,
+ TENXPRESS_STATUS_NORMAL = 2,
+};
+
+extern void tenxpress_set_state(struct efx_nic *efx,
+ enum tenxpress_state state);
+extern void tenxpress_phy_blink(struct efx_nic *efx, int blink);
+extern void tenxpress_crc_err(struct efx_nic *efx);
+
+/****************************************************************************
+ * Exported functions from the driver for XFP optical PHYs
+ */
+extern struct efx_phy_operations falcon_xfp_phy_ops;
+
+/* The QUAKE XFP PHY provides various H/W control states for LEDs */
+#define QUAKE_LED_LINK_INVAL (0)
+#define QUAKE_LED_LINK_STAT (1)
+#define QUAKE_LED_LINK_ACT (2)
+#define QUAKE_LED_LINK_ACTSTAT (3)
+#define QUAKE_LED_OFF (4)
+#define QUAKE_LED_ON (5)
+#define QUAKE_LED_LINK_INPUT (6) /* Pin is an input. */
+/* What link the LED tracks */
+#define QUAKE_LED_TXLINK (0)
+#define QUAKE_LED_RXLINK (8)
+
+extern void xfp_set_led(struct efx_nic *p, int led, int state);
+
+#endif
diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c
new file mode 100644
index 0000000..551299b
--- /dev/null
+++ b/drivers/net/sfc/rx.c
@@ -0,0 +1,875 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <net/ip.h>
+#include <net/checksum.h>
+#include "net_driver.h"
+#include "rx.h"
+#include "efx.h"
+#include "falcon.h"
+#include "workarounds.h"
+
+/* Number of RX descriptors pushed at once. */
+#define EFX_RX_BATCH 8
+
+/* Size of buffer allocated for skb header area. */
+#define EFX_SKB_HEADERS 64u
+
+/*
+ * rx_alloc_method - RX buffer allocation method
+ *
+ * This driver supports two methods for allocating and using RX buffers:
+ * each RX buffer may be backed by an skb or by an order-n page.
+ *
+ * When LRO is in use then the second method has a lower overhead,
+ * since we don't have to allocate then free skbs on reassembled frames.
+ *
+ * Values:
+ * - RX_ALLOC_METHOD_AUTO = 0
+ * - RX_ALLOC_METHOD_SKB = 1
+ * - RX_ALLOC_METHOD_PAGE = 2
+ *
+ * The heuristic for %RX_ALLOC_METHOD_AUTO is a simple hysteresis count
+ * controlled by the parameters below.
+ *
+ * - Since pushing and popping descriptors are separated by the rx_queue
+ * size, so the watermarks should be ~rxd_size.
+ * - The performance win by using page-based allocation for LRO is less
+ * than the performance hit of using page-based allocation of non-LRO,
+ * so the watermarks should reflect this.
+ *
+ * Per channel we maintain a single variable, updated by each channel:
+ *
+ * rx_alloc_level += (lro_performed ? RX_ALLOC_FACTOR_LRO :
+ * RX_ALLOC_FACTOR_SKB)
+ * Per NAPI poll interval, we constrain rx_alloc_level to 0..MAX (which
+ * limits the hysteresis), and update the allocation strategy:
+ *
+ * rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_LRO ?
+ * RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB)
+ */
+static int rx_alloc_method = RX_ALLOC_METHOD_PAGE;
+
+#define RX_ALLOC_LEVEL_LRO 0x2000
+#define RX_ALLOC_LEVEL_MAX 0x3000
+#define RX_ALLOC_FACTOR_LRO 1
+#define RX_ALLOC_FACTOR_SKB (-2)
+
+/* This is the percentage fill level below which new RX descriptors
+ * will be added to the RX descriptor ring.
+ */
+static unsigned int rx_refill_threshold = 90;
+
+/* This is the percentage fill level to which an RX queue will be refilled
+ * when the "RX refill threshold" is reached.
+ */
+static unsigned int rx_refill_limit = 95;
+
+/*
+ * RX maximum head room required.
+ *
+ * This must be at least 1 to prevent overflow and at least 2 to allow
+ * pipelined receives.
+ */
+#define EFX_RXD_HEAD_ROOM 2
+
+/* Macros for zero-order pages (potentially) containing multiple RX buffers */
+#define RX_DATA_OFFSET(_data) \
+ (((unsigned long) (_data)) & (PAGE_SIZE-1))
+#define RX_BUF_OFFSET(_rx_buf) \
+ RX_DATA_OFFSET((_rx_buf)->data)
+
+#define RX_PAGE_SIZE(_efx) \
+ (PAGE_SIZE * (1u << (_efx)->rx_buffer_order))
+
+
+/**************************************************************************
+ *
+ * Linux generic LRO handling
+ *
+ **************************************************************************
+ */
+
+static int efx_lro_get_skb_hdr(struct sk_buff *skb, void **ip_hdr,
+ void **tcpudp_hdr, u64 *hdr_flags, void *priv)
+{
+ struct efx_channel *channel = (struct efx_channel *)priv;
+ struct iphdr *iph;
+ struct tcphdr *th;
+
+ iph = (struct iphdr *)skb->data;
+ if (skb->protocol != htons(ETH_P_IP) || iph->protocol != IPPROTO_TCP)
+ goto fail;
+
+ th = (struct tcphdr *)(skb->data + iph->ihl * 4);
+
+ *tcpudp_hdr = th;
+ *ip_hdr = iph;
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
+ return 0;
+fail:
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+ return -1;
+}
+
+static int efx_get_frag_hdr(struct skb_frag_struct *frag, void **mac_hdr,
+ void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags,
+ void *priv)
+{
+ struct efx_channel *channel = (struct efx_channel *)priv;
+ struct ethhdr *eh;
+ struct iphdr *iph;
+
+ /* We support EtherII and VLAN encapsulated IPv4 */
+ eh = (struct ethhdr *)(page_address(frag->page) + frag->page_offset);
+ *mac_hdr = eh;
+
+ if (eh->h_proto == htons(ETH_P_IP)) {
+ iph = (struct iphdr *)(eh + 1);
+ } else {
+ struct vlan_ethhdr *veh = (struct vlan_ethhdr *)eh;
+ if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
+ goto fail;
+
+ iph = (struct iphdr *)(veh + 1);
+ }
+ *ip_hdr = iph;
+
+ /* We can only do LRO over TCP */
+ if (iph->protocol != IPPROTO_TCP)
+ goto fail;
+
+ *hdr_flags = LRO_IPV4 | LRO_TCP;
+ *tcpudp_hdr = (struct tcphdr *)((u8 *) iph + iph->ihl * 4);
+
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
+ return 0;
+ fail:
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+ return -1;
+}
+
+int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx)
+{
+ size_t s = sizeof(struct net_lro_desc) * EFX_MAX_LRO_DESCRIPTORS;
+ struct net_lro_desc *lro_arr;
+
+ /* Allocate the LRO descriptors structure */
+ lro_arr = kzalloc(s, GFP_KERNEL);
+ if (lro_arr == NULL)
+ return -ENOMEM;
+
+ lro_mgr->lro_arr = lro_arr;
+ lro_mgr->max_desc = EFX_MAX_LRO_DESCRIPTORS;
+ lro_mgr->max_aggr = EFX_MAX_LRO_AGGR;
+ lro_mgr->frag_align_pad = EFX_PAGE_SKB_ALIGN;
+
+ lro_mgr->get_skb_header = efx_lro_get_skb_hdr;
+ lro_mgr->get_frag_header = efx_get_frag_hdr;
+ lro_mgr->dev = efx->net_dev;
+
+ lro_mgr->features = LRO_F_NAPI;
+
+ /* We can pass packets up with the checksum intact */
+ lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
+
+ lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+
+ return 0;
+}
+
+void efx_lro_fini(struct net_lro_mgr *lro_mgr)
+{
+ kfree(lro_mgr->lro_arr);
+ lro_mgr->lro_arr = NULL;
+}
+
+/**
+ * efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
+ *
+ * @rx_queue: Efx RX queue
+ * @rx_buf: RX buffer structure to populate
+ *
+ * This allocates memory for a new receive buffer, maps it for DMA,
+ * and populates a struct efx_rx_buffer with the relevant
+ * information. Return a negative error code or 0 on success.
+ */
+static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ struct net_device *net_dev = efx->net_dev;
+ int skb_len = efx->rx_buffer_len;
+
+ rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
+ if (unlikely(!rx_buf->skb))
+ return -ENOMEM;
+
+ /* Adjust the SKB for padding and checksum */
+ skb_reserve(rx_buf->skb, NET_IP_ALIGN);
+ rx_buf->len = skb_len - NET_IP_ALIGN;
+ rx_buf->data = (char *)rx_buf->skb->data;
+ rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+ rx_buf->dma_addr = pci_map_single(efx->pci_dev,
+ rx_buf->data, rx_buf->len,
+ PCI_DMA_FROMDEVICE);
+
+ if (unlikely(pci_dma_mapping_error(rx_buf->dma_addr))) {
+ dev_kfree_skb_any(rx_buf->skb);
+ rx_buf->skb = NULL;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * efx_init_rx_buffer_page - create new RX buffer using page-based allocation
+ *
+ * @rx_queue: Efx RX queue
+ * @rx_buf: RX buffer structure to populate
+ *
+ * This allocates memory for a new receive buffer, maps it for DMA,
+ * and populates a struct efx_rx_buffer with the relevant
+ * information. Return a negative error code or 0 on success.
+ */
+static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ int bytes, space, offset;
+
+ bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
+
+ /* If there is space left in the previously allocated page,
+ * then use it. Otherwise allocate a new one */
+ rx_buf->page = rx_queue->buf_page;
+ if (rx_buf->page == NULL) {
+ dma_addr_t dma_addr;
+
+ rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
+ efx->rx_buffer_order);
+ if (unlikely(rx_buf->page == NULL))
+ return -ENOMEM;
+
+ dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
+ 0, RX_PAGE_SIZE(efx),
+ PCI_DMA_FROMDEVICE);
+
+ if (unlikely(pci_dma_mapping_error(dma_addr))) {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ rx_buf->page = NULL;
+ return -EIO;
+ }
+
+ rx_queue->buf_page = rx_buf->page;
+ rx_queue->buf_dma_addr = dma_addr;
+ rx_queue->buf_data = ((char *) page_address(rx_buf->page) +
+ EFX_PAGE_IP_ALIGN);
+ }
+
+ offset = RX_DATA_OFFSET(rx_queue->buf_data);
+ rx_buf->len = bytes;
+ rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
+ rx_buf->data = rx_queue->buf_data;
+
+ /* Try to pack multiple buffers per page */
+ if (efx->rx_buffer_order == 0) {
+ /* The next buffer starts on the next 512 byte boundary */
+ rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
+ offset += ((bytes + 0x1ff) & ~0x1ff);
+
+ space = RX_PAGE_SIZE(efx) - offset;
+ if (space >= bytes) {
+ /* Refs dropped on kernel releasing each skb */
+ get_page(rx_queue->buf_page);
+ goto out;
+ }
+ }
+
+ /* This is the final RX buffer for this page, so mark it for
+ * unmapping */
+ rx_queue->buf_page = NULL;
+ rx_buf->unmap_addr = rx_queue->buf_dma_addr;
+
+ out:
+ return 0;
+}
+
+/* This allocates memory for a new receive buffer, maps it for DMA,
+ * and populates a struct efx_rx_buffer with the relevant
+ * information.
+ */
+static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *new_rx_buf)
+{
+ int rc = 0;
+
+ if (rx_queue->channel->rx_alloc_push_pages) {
+ new_rx_buf->skb = NULL;
+ rc = efx_init_rx_buffer_page(rx_queue, new_rx_buf);
+ rx_queue->alloc_page_count++;
+ } else {
+ new_rx_buf->page = NULL;
+ rc = efx_init_rx_buffer_skb(rx_queue, new_rx_buf);
+ rx_queue->alloc_skb_count++;
+ }
+
+ if (unlikely(rc < 0))
+ EFX_LOG_RL(rx_queue->efx, "%s RXQ[%d] =%d\n", __func__,
+ rx_queue->queue, rc);
+ return rc;
+}
+
+static inline void efx_unmap_rx_buffer(struct efx_nic *efx,
+ struct efx_rx_buffer *rx_buf)
+{
+ if (rx_buf->page) {
+ EFX_BUG_ON_PARANOID(rx_buf->skb);
+ if (rx_buf->unmap_addr) {
+ pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
+ RX_PAGE_SIZE(efx), PCI_DMA_FROMDEVICE);
+ rx_buf->unmap_addr = 0;
+ }
+ } else if (likely(rx_buf->skb)) {
+ pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
+ rx_buf->len, PCI_DMA_FROMDEVICE);
+ }
+}
+
+static inline void efx_free_rx_buffer(struct efx_nic *efx,
+ struct efx_rx_buffer *rx_buf)
+{
+ if (rx_buf->page) {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ rx_buf->page = NULL;
+ } else if (likely(rx_buf->skb)) {
+ dev_kfree_skb_any(rx_buf->skb);
+ rx_buf->skb = NULL;
+ }
+}
+
+static inline void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf)
+{
+ efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
+ efx_free_rx_buffer(rx_queue->efx, rx_buf);
+}
+
+/**
+ * efx_fast_push_rx_descriptors - push new RX descriptors quickly
+ * @rx_queue: RX descriptor queue
+ * @retry: Recheck the fill level
+ * This will aim to fill the RX descriptor queue up to
+ * @rx_queue->@fast_fill_limit. If there is insufficient atomic
+ * memory to do so, the caller should retry.
+ */
+static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
+ int retry)
+{
+ struct efx_rx_buffer *rx_buf;
+ unsigned fill_level, index;
+ int i, space, rc = 0;
+
+ /* Calculate current fill level. Do this outside the lock,
+ * because most of the time we'll end up not wanting to do the
+ * fill anyway.
+ */
+ fill_level = (rx_queue->added_count - rx_queue->removed_count);
+ EFX_BUG_ON_PARANOID(fill_level >
+ rx_queue->efx->type->rxd_ring_mask + 1);
+
+ /* Don't fill if we don't need to */
+ if (fill_level >= rx_queue->fast_fill_trigger)
+ return 0;
+
+ /* Record minimum fill level */
+ if (unlikely(fill_level < rx_queue->min_fill))
+ if (fill_level)
+ rx_queue->min_fill = fill_level;
+
+ /* Acquire RX add lock. If this lock is contended, then a fast
+ * fill must already be in progress (e.g. in the refill
+ * tasklet), so we don't need to do anything
+ */
+ if (!spin_trylock_bh(&rx_queue->add_lock))
+ return -1;
+
+ retry:
+ /* Recalculate current fill level now that we have the lock */
+ fill_level = (rx_queue->added_count - rx_queue->removed_count);
+ EFX_BUG_ON_PARANOID(fill_level >
+ rx_queue->efx->type->rxd_ring_mask + 1);
+ space = rx_queue->fast_fill_limit - fill_level;
+ if (space < EFX_RX_BATCH)
+ goto out_unlock;
+
+ EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
+ " level %d to level %d using %s allocation\n",
+ rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
+ rx_queue->channel->rx_alloc_push_pages ? "page" : "skb");
+
+ do {
+ for (i = 0; i < EFX_RX_BATCH; ++i) {
+ index = (rx_queue->added_count &
+ rx_queue->efx->type->rxd_ring_mask);
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ rc = efx_init_rx_buffer(rx_queue, rx_buf);
+ if (unlikely(rc))
+ goto out;
+ ++rx_queue->added_count;
+ }
+ } while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
+
+ EFX_TRACE(rx_queue->efx, "RX queue %d fast-filled descriptor ring "
+ "to level %d\n", rx_queue->queue,
+ rx_queue->added_count - rx_queue->removed_count);
+
+ out:
+ /* Send write pointer to card. */
+ falcon_notify_rx_desc(rx_queue);
+
+ /* If the fast fill is running inside from the refill tasklet, then
+ * for SMP systems it may be running on a different CPU to
+ * RX event processing, which means that the fill level may now be
+ * out of date. */
+ if (unlikely(retry && (rc == 0)))
+ goto retry;
+
+ out_unlock:
+ spin_unlock_bh(&rx_queue->add_lock);
+
+ return rc;
+}
+
+/**
+ * efx_fast_push_rx_descriptors - push new RX descriptors quickly
+ * @rx_queue: RX descriptor queue
+ *
+ * This will aim to fill the RX descriptor queue up to
+ * @rx_queue->@fast_fill_limit. If there is insufficient memory to do so,
+ * it will schedule a work item to immediately continue the fast fill
+ */
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
+{
+ int rc;
+
+ rc = __efx_fast_push_rx_descriptors(rx_queue, 0);
+ if (unlikely(rc)) {
+ /* Schedule the work item to run immediately. The hope is
+ * that work is immediately pending to free some memory
+ * (e.g. an RX event or TX completion)
+ */
+ efx_schedule_slow_fill(rx_queue, 0);
+ }
+}
+
+void efx_rx_work(struct work_struct *data)
+{
+ struct efx_rx_queue *rx_queue;
+ int rc;
+
+ rx_queue = container_of(data, struct efx_rx_queue, work.work);
+
+ if (unlikely(!rx_queue->channel->enabled))
+ return;
+
+ EFX_TRACE(rx_queue->efx, "RX queue %d worker thread executing on CPU "
+ "%d\n", rx_queue->queue, raw_smp_processor_id());
+
+ ++rx_queue->slow_fill_count;
+ /* Push new RX descriptors, allowing at least 1 jiffy for
+ * the kernel to free some more memory. */
+ rc = __efx_fast_push_rx_descriptors(rx_queue, 1);
+ if (rc)
+ efx_schedule_slow_fill(rx_queue, 1);
+}
+
+static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
+ struct efx_rx_buffer *rx_buf,
+ int len, int *discard,
+ int *leak_packet)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned max_len = rx_buf->len - efx->type->rx_buffer_padding;
+
+ if (likely(len <= max_len))
+ return;
+
+ /* The packet must be discarded, but this is only a fatal error
+ * if the caller indicated it was
+ */
+ *discard = 1;
+
+ if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) {
+ EFX_ERR_RL(efx, " RX queue %d seriously overlength "
+ "RX event (0x%x > 0x%x+0x%x). Leaking\n",
+ rx_queue->queue, len, max_len,
+ efx->type->rx_buffer_padding);
+ /* If this buffer was skb-allocated, then the meta
+ * data at the end of the skb will be trashed. So
+ * we have no choice but to leak the fragment.
+ */
+ *leak_packet = (rx_buf->skb != NULL);
+ efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY);
+ } else {
+ EFX_ERR_RL(efx, " RX queue %d overlength RX event "
+ "(0x%x > 0x%x)\n", rx_queue->queue, len, max_len);
+ }
+
+ rx_queue->channel->n_rx_overlength++;
+}
+
+/* Pass a received packet up through the generic LRO stack
+ *
+ * Handles driverlink veto, and passes the fragment up via
+ * the appropriate LRO method
+ */
+static inline void efx_rx_packet_lro(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf)
+{
+ struct net_lro_mgr *lro_mgr = &channel->lro_mgr;
+ void *priv = channel;
+
+ /* Pass the skb/page into the LRO engine */
+ if (rx_buf->page) {
+ struct skb_frag_struct frags;
+
+ frags.page = rx_buf->page;
+ frags.page_offset = RX_BUF_OFFSET(rx_buf);
+ frags.size = rx_buf->len;
+
+ lro_receive_frags(lro_mgr, &frags, rx_buf->len,
+ rx_buf->len, priv, 0);
+
+ EFX_BUG_ON_PARANOID(rx_buf->skb);
+ rx_buf->page = NULL;
+ } else {
+ EFX_BUG_ON_PARANOID(!rx_buf->skb);
+
+ lro_receive_skb(lro_mgr, rx_buf->skb, priv);
+ rx_buf->skb = NULL;
+ }
+}
+
+/* Allocate and construct an SKB around a struct page.*/
+static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
+ struct efx_nic *efx,
+ int hdr_len)
+{
+ struct sk_buff *skb;
+
+ /* Allocate an SKB to store the headers */
+ skb = netdev_alloc_skb(efx->net_dev, hdr_len + EFX_PAGE_SKB_ALIGN);
+ if (unlikely(skb == NULL)) {
+ EFX_ERR_RL(efx, "RX out of memory for skb\n");
+ return NULL;
+ }
+
+ EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags);
+ EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len);
+
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ skb_reserve(skb, EFX_PAGE_SKB_ALIGN);
+
+ skb->len = rx_buf->len;
+ skb->truesize = rx_buf->len + sizeof(struct sk_buff);
+ memcpy(skb->data, rx_buf->data, hdr_len);
+ skb->tail += hdr_len;
+
+ /* Append the remaining page onto the frag list */
+ if (unlikely(rx_buf->len > hdr_len)) {
+ struct skb_frag_struct *frag = skb_shinfo(skb)->frags;
+ frag->page = rx_buf->page;
+ frag->page_offset = RX_BUF_OFFSET(rx_buf) + hdr_len;
+ frag->size = skb->len - hdr_len;
+ skb_shinfo(skb)->nr_frags = 1;
+ skb->data_len = frag->size;
+ } else {
+ __free_pages(rx_buf->page, efx->rx_buffer_order);
+ skb->data_len = 0;
+ }
+
+ /* Ownership has transferred from the rx_buf to skb */
+ rx_buf->page = NULL;
+
+ /* Move past the ethernet header */
+ skb->protocol = eth_type_trans(skb, efx->net_dev);
+
+ return skb;
+}
+
+void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
+ unsigned int len, int checksummed, int discard)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ struct efx_rx_buffer *rx_buf;
+ int leak_packet = 0;
+
+ rx_buf = efx_rx_buffer(rx_queue, index);
+ EFX_BUG_ON_PARANOID(!rx_buf->data);
+ EFX_BUG_ON_PARANOID(rx_buf->skb && rx_buf->page);
+ EFX_BUG_ON_PARANOID(!(rx_buf->skb || rx_buf->page));
+
+ /* This allows the refill path to post another buffer.
+ * EFX_RXD_HEAD_ROOM ensures that the slot we are using
+ * isn't overwritten yet.
+ */
+ rx_queue->removed_count++;
+
+ /* Validate the length encoded in the event vs the descriptor pushed */
+ efx_rx_packet__check_len(rx_queue, rx_buf, len,
+ &discard, &leak_packet);
+
+ EFX_TRACE(efx, "RX queue %d received id %x at %llx+%x %s%s\n",
+ rx_queue->queue, index,
+ (unsigned long long)rx_buf->dma_addr, len,
+ (checksummed ? " [SUMMED]" : ""),
+ (discard ? " [DISCARD]" : ""));
+
+ /* Discard packet, if instructed to do so */
+ if (unlikely(discard)) {
+ if (unlikely(leak_packet))
+ rx_queue->channel->n_skbuff_leaks++;
+ else
+ /* We haven't called efx_unmap_rx_buffer yet,
+ * so fini the entire rx_buffer here */
+ efx_fini_rx_buffer(rx_queue, rx_buf);
+ return;
+ }
+
+ /* Release card resources - assumes all RX buffers consumed in-order
+ * per RX queue
+ */
+ efx_unmap_rx_buffer(efx, rx_buf);
+
+ /* Prefetch nice and early so data will (hopefully) be in cache by
+ * the time we look at it.
+ */
+ prefetch(rx_buf->data);
+
+ /* Pipeline receives so that we give time for packet headers to be
+ * prefetched into cache.
+ */
+ rx_buf->len = len;
+ if (rx_queue->channel->rx_pkt)
+ __efx_rx_packet(rx_queue->channel,
+ rx_queue->channel->rx_pkt,
+ rx_queue->channel->rx_pkt_csummed);
+ rx_queue->channel->rx_pkt = rx_buf;
+ rx_queue->channel->rx_pkt_csummed = checksummed;
+}
+
+/* Handle a received packet. Second half: Touches packet payload. */
+void __efx_rx_packet(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf, int checksummed)
+{
+ struct efx_nic *efx = channel->efx;
+ struct sk_buff *skb;
+ int lro = efx->net_dev->features & NETIF_F_LRO;
+
+ if (rx_buf->skb) {
+ prefetch(skb_shinfo(rx_buf->skb));
+
+ skb_put(rx_buf->skb, rx_buf->len);
+
+ /* Move past the ethernet header. rx_buf->data still points
+ * at the ethernet header */
+ rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
+ efx->net_dev);
+ }
+
+ /* Both our generic-LRO and SFC-SSR support skb and page based
+ * allocation, but neither support switching from one to the
+ * other on the fly. If we spot that the allocation mode has
+ * changed, then flush the LRO state.
+ */
+ if (unlikely(channel->rx_alloc_pop_pages != (rx_buf->page != NULL))) {
+ efx_flush_lro(channel);
+ channel->rx_alloc_pop_pages = (rx_buf->page != NULL);
+ }
+ if (likely(checksummed && lro)) {
+ efx_rx_packet_lro(channel, rx_buf);
+ goto done;
+ }
+
+ /* Form an skb if required */
+ if (rx_buf->page) {
+ int hdr_len = min(rx_buf->len, EFX_SKB_HEADERS);
+ skb = efx_rx_mk_skb(rx_buf, efx, hdr_len);
+ if (unlikely(skb == NULL)) {
+ efx_free_rx_buffer(efx, rx_buf);
+ goto done;
+ }
+ } else {
+ /* We now own the SKB */
+ skb = rx_buf->skb;
+ rx_buf->skb = NULL;
+ }
+
+ EFX_BUG_ON_PARANOID(rx_buf->page);
+ EFX_BUG_ON_PARANOID(rx_buf->skb);
+ EFX_BUG_ON_PARANOID(!skb);
+
+ /* Set the SKB flags */
+ if (unlikely(!checksummed || !efx->rx_checksum_enabled))
+ skb->ip_summed = CHECKSUM_NONE;
+
+ /* Pass the packet up */
+ netif_receive_skb(skb);
+
+ /* Update allocation strategy method */
+ channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
+
+ /* fall-thru */
+done:
+ efx->net_dev->last_rx = jiffies;
+}
+
+void efx_rx_strategy(struct efx_channel *channel)
+{
+ enum efx_rx_alloc_method method = rx_alloc_method;
+
+ /* Only makes sense to use page based allocation if LRO is enabled */
+ if (!(channel->efx->net_dev->features & NETIF_F_LRO)) {
+ method = RX_ALLOC_METHOD_SKB;
+ } else if (method == RX_ALLOC_METHOD_AUTO) {
+ /* Constrain the rx_alloc_level */
+ if (channel->rx_alloc_level < 0)
+ channel->rx_alloc_level = 0;
+ else if (channel->rx_alloc_level > RX_ALLOC_LEVEL_MAX)
+ channel->rx_alloc_level = RX_ALLOC_LEVEL_MAX;
+
+ /* Decide on the allocation method */
+ method = ((channel->rx_alloc_level > RX_ALLOC_LEVEL_LRO) ?
+ RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB);
+ }
+
+ /* Push the option */
+ channel->rx_alloc_push_pages = (method == RX_ALLOC_METHOD_PAGE);
+}
+
+int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned int rxq_size;
+ int rc;
+
+ EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue);
+
+ /* Allocate RX buffers */
+ rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer);
+ rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL);
+ if (!rx_queue->buffer) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+
+ rc = falcon_probe_rx(rx_queue);
+ if (rc)
+ goto fail2;
+
+ return 0;
+
+ fail2:
+ kfree(rx_queue->buffer);
+ rx_queue->buffer = NULL;
+ fail1:
+ rx_queue->used = 0;
+
+ return rc;
+}
+
+int efx_init_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ struct efx_nic *efx = rx_queue->efx;
+ unsigned int max_fill, trigger, limit;
+
+ EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue);
+
+ /* Initialise ptr fields */
+ rx_queue->added_count = 0;
+ rx_queue->notified_count = 0;
+ rx_queue->removed_count = 0;
+ rx_queue->min_fill = -1U;
+ rx_queue->min_overfill = -1U;
+
+ /* Initialise limit fields */
+ max_fill = efx->type->rxd_ring_mask + 1 - EFX_RXD_HEAD_ROOM;
+ trigger = max_fill * min(rx_refill_threshold, 100U) / 100U;
+ limit = max_fill * min(rx_refill_limit, 100U) / 100U;
+
+ rx_queue->max_fill = max_fill;
+ rx_queue->fast_fill_trigger = trigger;
+ rx_queue->fast_fill_limit = limit;
+
+ /* Set up RX descriptor ring */
+ return falcon_init_rx(rx_queue);
+}
+
+void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ int i;
+ struct efx_rx_buffer *rx_buf;
+
+ EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
+
+ falcon_fini_rx(rx_queue);
+
+ /* Release RX buffers NB start at index 0 not current HW ptr */
+ if (rx_queue->buffer) {
+ for (i = 0; i <= rx_queue->efx->type->rxd_ring_mask; i++) {
+ rx_buf = efx_rx_buffer(rx_queue, i);
+ efx_fini_rx_buffer(rx_queue, rx_buf);
+ }
+ }
+
+ /* For a page that is part-way through splitting into RX buffers */
+ if (rx_queue->buf_page != NULL) {
+ pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
+ RX_PAGE_SIZE(rx_queue->efx), PCI_DMA_FROMDEVICE);
+ __free_pages(rx_queue->buf_page,
+ rx_queue->efx->rx_buffer_order);
+ rx_queue->buf_page = NULL;
+ }
+}
+
+void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
+{
+ EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue);
+
+ falcon_remove_rx(rx_queue);
+
+ kfree(rx_queue->buffer);
+ rx_queue->buffer = NULL;
+ rx_queue->used = 0;
+}
+
+void efx_flush_lro(struct efx_channel *channel)
+{
+ lro_flush_all(&channel->lro_mgr);
+}
+
+
+module_param(rx_alloc_method, int, 0644);
+MODULE_PARM_DESC(rx_alloc_method, "Allocation method used for RX buffers");
+
+module_param(rx_refill_threshold, uint, 0444);
+MODULE_PARM_DESC(rx_refill_threshold,
+ "RX descriptor ring fast/slow fill threshold (%)");
+
diff --git a/drivers/net/sfc/rx.h b/drivers/net/sfc/rx.h
new file mode 100644
index 0000000..f35e377
--- /dev/null
+++ b/drivers/net/sfc/rx.h
@@ -0,0 +1,29 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_RX_H
+#define EFX_RX_H
+
+#include "net_driver.h"
+
+int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
+void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
+int efx_init_rx_queue(struct efx_rx_queue *rx_queue);
+void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
+
+int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx);
+void efx_lro_fini(struct net_lro_mgr *lro_mgr);
+void efx_flush_lro(struct efx_channel *channel);
+void efx_rx_strategy(struct efx_channel *channel);
+void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
+void efx_rx_work(struct work_struct *data);
+void __efx_rx_packet(struct efx_channel *channel,
+ struct efx_rx_buffer *rx_buf, int checksummed);
+
+#endif /* EFX_RX_H */
diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c
new file mode 100644
index 0000000..11fa9fb
--- /dev/null
+++ b/drivers/net/sfc/sfe4001.c
@@ -0,0 +1,252 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+/*****************************************************************************
+ * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that
+ * controls the PHY power rails, and for the MAX6647 temp. sensor used to check
+ * the PHY
+ */
+#include <linux/delay.h>
+#include "efx.h"
+#include "phy.h"
+#include "boards.h"
+#include "falcon.h"
+#include "falcon_hwdefs.h"
+#include "mac.h"
+
+/**************************************************************************
+ *
+ * I2C IO Expander device
+ *
+ **************************************************************************/
+#define PCA9539 0x74
+
+#define P0_IN 0x00
+#define P0_OUT 0x02
+#define P0_INVERT 0x04
+#define P0_CONFIG 0x06
+
+#define P0_EN_1V0X_LBN 0
+#define P0_EN_1V0X_WIDTH 1
+#define P0_EN_1V2_LBN 1
+#define P0_EN_1V2_WIDTH 1
+#define P0_EN_2V5_LBN 2
+#define P0_EN_2V5_WIDTH 1
+#define P0_EN_3V3X_LBN 3
+#define P0_EN_3V3X_WIDTH 1
+#define P0_EN_5V_LBN 4
+#define P0_EN_5V_WIDTH 1
+#define P0_SHORTEN_JTAG_LBN 5
+#define P0_SHORTEN_JTAG_WIDTH 1
+#define P0_X_TRST_LBN 6
+#define P0_X_TRST_WIDTH 1
+#define P0_DSP_RESET_LBN 7
+#define P0_DSP_RESET_WIDTH 1
+
+#define P1_IN 0x01
+#define P1_OUT 0x03
+#define P1_INVERT 0x05
+#define P1_CONFIG 0x07
+
+#define P1_AFE_PWD_LBN 0
+#define P1_AFE_PWD_WIDTH 1
+#define P1_DSP_PWD25_LBN 1
+#define P1_DSP_PWD25_WIDTH 1
+#define P1_RESERVED_LBN 2
+#define P1_RESERVED_WIDTH 2
+#define P1_SPARE_LBN 4
+#define P1_SPARE_WIDTH 4
+
+
+/**************************************************************************
+ *
+ * Temperature Sensor
+ *
+ **************************************************************************/
+#define MAX6647 0x4e
+
+#define RLTS 0x00
+#define RLTE 0x01
+#define RSL 0x02
+#define RCL 0x03
+#define RCRA 0x04
+#define RLHN 0x05
+#define RLLI 0x06
+#define RRHI 0x07
+#define RRLS 0x08
+#define WCRW 0x0a
+#define WLHO 0x0b
+#define WRHA 0x0c
+#define WRLN 0x0e
+#define OSHT 0x0f
+#define REET 0x10
+#define RIET 0x11
+#define RWOE 0x19
+#define RWOI 0x20
+#define HYS 0x21
+#define QUEUE 0x22
+#define MFID 0xfe
+#define REVID 0xff
+
+/* Status bits */
+#define MAX6647_BUSY (1 << 7) /* ADC is converting */
+#define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */
+#define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */
+#define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */
+#define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */
+#define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */
+#define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */
+#define MAX6647_IOT (1 << 0) /* Local junction overtemp. */
+
+static const u8 xgphy_max_temperature = 90;
+
+void sfe4001_poweroff(struct efx_nic *efx)
+{
+ struct efx_i2c_interface *i2c = &efx->i2c;
+
+ u8 cfg, out, in;
+
+ EFX_INFO(efx, "%s\n", __func__);
+
+ /* Turn off all power rails */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+
+ /* Disable port 1 outputs on IO expander */
+ cfg = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+
+ /* Disable port 0 outputs on IO expander */
+ cfg = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+
+ /* Clear any over-temperature alert */
+ (void) efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
+}
+
+/* This board uses an I2C expander to provider power to the PHY, which needs to
+ * be turned on before the PHY can be used.
+ * Context: Process context, rtnl lock held
+ */
+int sfe4001_poweron(struct efx_nic *efx)
+{
+ struct efx_i2c_interface *i2c = &efx->i2c;
+ unsigned int count;
+ int rc;
+ u8 out, in, cfg;
+ efx_dword_t reg;
+
+ /* 10Xpress has fixed-function LED pins, so there is no board-specific
+ * blink code. */
+ efx->board_info.blink = tenxpress_phy_blink;
+
+ /* Ensure that XGXS and XAUI SerDes are held in reset */
+ EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1,
+ XX_PWRDNB_EN, 1,
+ XX_RSTPLLAB_EN, 1,
+ XX_RESETA_EN, 1,
+ XX_RESETB_EN, 1,
+ XX_RSTXGXSRX_EN, 1,
+ XX_RSTXGXSTX_EN, 1);
+ falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC);
+ udelay(10);
+
+ /* Set DSP over-temperature alert threshold */
+ EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
+ rc = efx_i2c_write(i2c, MAX6647, WLHO,
+ &xgphy_max_temperature, 1);
+ if (rc)
+ goto fail1;
+
+ /* Read it back and verify */
+ rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, 1);
+ if (rc)
+ goto fail1;
+ if (in != xgphy_max_temperature) {
+ rc = -EFAULT;
+ goto fail1;
+ }
+
+ /* Clear any previous over-temperature alert */
+ rc = efx_i2c_read(i2c, MAX6647, RSL, &in, 1);
+ if (rc)
+ goto fail1;
+
+ /* Enable port 0 and port 1 outputs on IO expander */
+ cfg = 0x00;
+ rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, 1);
+ if (rc)
+ goto fail1;
+ cfg = 0xff & ~(1 << P1_SPARE_LBN);
+ rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, 1);
+ if (rc)
+ goto fail2;
+
+ /* Turn all power off then wait 1 sec. This ensures PHY is reset */
+ out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
+ (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
+ (0 << P0_EN_1V0X_LBN));
+ rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ if (rc)
+ goto fail3;
+
+ schedule_timeout_uninterruptible(HZ);
+ count = 0;
+ do {
+ /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
+ out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
+ (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
+ (1 << P0_X_TRST_LBN));
+
+ rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ if (rc)
+ goto fail3;
+ msleep(10);
+
+ /* Turn on 1V power rail */
+ out &= ~(1 << P0_EN_1V0X_LBN);
+ rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ if (rc)
+ goto fail3;
+
+ EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
+
+ schedule_timeout_uninterruptible(HZ);
+
+ /* Check DSP is powered */
+ rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, 1);
+ if (rc)
+ goto fail3;
+ if (in & (1 << P1_AFE_PWD_LBN))
+ goto done;
+
+ } while (++count < 20);
+
+ EFX_INFO(efx, "timed out waiting for power\n");
+ rc = -ETIMEDOUT;
+ goto fail3;
+
+done:
+ EFX_INFO(efx, "PHY is powered on\n");
+ return 0;
+
+fail3:
+ /* Turn off all power rails */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, 1);
+ /* Disable port 1 outputs on IO expander */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, 1);
+fail2:
+ /* Disable port 0 outputs on IO expander */
+ out = 0xff;
+ (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &out, 1);
+fail1:
+ return rc;
+}
diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h
new file mode 100644
index 0000000..34412f3
--- /dev/null
+++ b/drivers/net/sfc/spi.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005 Fen Systems Ltd.
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_SPI_H
+#define EFX_SPI_H
+
+#include "net_driver.h"
+
+/**************************************************************************
+ *
+ * Basic SPI command set and bit definitions
+ *
+ *************************************************************************/
+
+/*
+ * Commands common to all known devices.
+ *
+ */
+
+/* Write status register */
+#define SPI_WRSR 0x01
+
+/* Write data to memory array */
+#define SPI_WRITE 0x02
+
+/* Read data from memory array */
+#define SPI_READ 0x03
+
+/* Reset write enable latch */
+#define SPI_WRDI 0x04
+
+/* Read status register */
+#define SPI_RDSR 0x05
+
+/* Set write enable latch */
+#define SPI_WREN 0x06
+
+/* SST: Enable write to status register */
+#define SPI_SST_EWSR 0x50
+
+/*
+ * Status register bits. Not all bits are supported on all devices.
+ *
+ */
+
+/* Write-protect pin enabled */
+#define SPI_STATUS_WPEN 0x80
+
+/* Block protection bit 2 */
+#define SPI_STATUS_BP2 0x10
+
+/* Block protection bit 1 */
+#define SPI_STATUS_BP1 0x08
+
+/* Block protection bit 0 */
+#define SPI_STATUS_BP0 0x04
+
+/* State of the write enable latch */
+#define SPI_STATUS_WEN 0x02
+
+/* Device busy flag */
+#define SPI_STATUS_NRDY 0x01
+
+#endif /* EFX_SPI_H */
diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c
new file mode 100644
index 0000000..a2e9f79
--- /dev/null
+++ b/drivers/net/sfc/tenxpress.c
@@ -0,0 +1,434 @@
+/****************************************************************************
+ * Driver for Solarflare 802.3an compliant PHY
+ * Copyright 2007 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include "efx.h"
+#include "gmii.h"
+#include "mdio_10g.h"
+#include "falcon.h"
+#include "phy.h"
+#include "falcon_hwdefs.h"
+#include "boards.h"
+#include "mac.h"
+
+/* We expect these MMDs to be in the package */
+/* AN not here as mdio_check_mmds() requires STAT2 support */
+#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PHYXS)
+
+/* We complain if we fail to see the link partner as 10G capable this many
+ * times in a row (must be > 1 as sampling the autoneg. registers is racy)
+ */
+#define MAX_BAD_LP_TRIES (5)
+
+/* Extended control register */
+#define PMA_PMD_XCONTROL_REG 0xc000
+#define PMA_PMD_LNPGA_POWERDOWN_LBN 8
+#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
+
+/* extended status register */
+#define PMA_PMD_XSTATUS_REG 0xc001
+#define PMA_PMD_XSTAT_FLP_LBN (12)
+
+/* LED control register */
+#define PMA_PMD_LED_CTRL_REG (0xc007)
+#define PMA_PMA_LED_ACTIVITY_LBN (3)
+
+/* LED function override register */
+#define PMA_PMD_LED_OVERR_REG (0xc009)
+/* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
+#define PMA_PMD_LED_LINK_LBN (0)
+#define PMA_PMD_LED_SPEED_LBN (2)
+#define PMA_PMD_LED_TX_LBN (4)
+#define PMA_PMD_LED_RX_LBN (6)
+/* Override settings */
+#define PMA_PMD_LED_AUTO (0) /* H/W control */
+#define PMA_PMD_LED_ON (1)
+#define PMA_PMD_LED_OFF (2)
+#define PMA_PMD_LED_FLASH (3)
+/* All LEDs under hardware control */
+#define PMA_PMD_LED_FULL_AUTO (0)
+/* Green and Amber under hardware control, Red off */
+#define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
+
+
+/* Self test (BIST) control register */
+#define PMA_PMD_BIST_CTRL_REG (0xc014)
+#define PMA_PMD_BIST_BER_LBN (2) /* Run BER test */
+#define PMA_PMD_BIST_CONT_LBN (1) /* Run continuous BIST until cleared */
+#define PMA_PMD_BIST_SINGLE_LBN (0) /* Run 1 BIST iteration (self clears) */
+/* Self test status register */
+#define PMA_PMD_BIST_STAT_REG (0xc015)
+#define PMA_PMD_BIST_ENX_LBN (3)
+#define PMA_PMD_BIST_PMA_LBN (2)
+#define PMA_PMD_BIST_RXD_LBN (1)
+#define PMA_PMD_BIST_AFE_LBN (0)
+
+#define BIST_MAX_DELAY (1000)
+#define BIST_POLL_DELAY (10)
+
+/* Misc register defines */
+#define PCS_CLOCK_CTRL_REG 0xd801
+#define PLL312_RST_N_LBN 2
+
+#define PCS_SOFT_RST2_REG 0xd806
+#define SERDES_RST_N_LBN 13
+#define XGXS_RST_N_LBN 12
+
+#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */
+#define CLK312_EN_LBN 3
+
+/* Boot status register */
+#define PCS_BOOT_STATUS_REG (0xd000)
+#define PCS_BOOT_FATAL_ERR_LBN (0)
+#define PCS_BOOT_PROGRESS_LBN (1)
+#define PCS_BOOT_PROGRESS_WIDTH (2)
+#define PCS_BOOT_COMPLETE_LBN (3)
+#define PCS_BOOT_MAX_DELAY (100)
+#define PCS_BOOT_POLL_DELAY (10)
+
+/* Time to wait between powering down the LNPGA and turning off the power
+ * rails */
+#define LNPGA_PDOWN_WAIT (HZ / 5)
+
+static int crc_error_reset_threshold = 100;
+module_param(crc_error_reset_threshold, int, 0644);
+MODULE_PARM_DESC(crc_error_reset_threshold,
+ "Max number of CRC errors before XAUI reset");
+
+struct tenxpress_phy_data {
+ enum tenxpress_state state;
+ atomic_t bad_crc_count;
+ int bad_lp_tries;
+};
+
+static int tenxpress_state_is(struct efx_nic *efx, int state)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ return (phy_data != NULL) && (state == phy_data->state);
+}
+
+void tenxpress_set_state(struct efx_nic *efx,
+ enum tenxpress_state state)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ if (phy_data != NULL)
+ phy_data->state = state;
+}
+
+void tenxpress_crc_err(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ if (phy_data != NULL)
+ atomic_inc(&phy_data->bad_crc_count);
+}
+
+/* Check that the C166 has booted successfully */
+static int tenxpress_phy_check(struct efx_nic *efx)
+{
+ int phy_id = efx->mii.phy_id;
+ int count = PCS_BOOT_MAX_DELAY / PCS_BOOT_POLL_DELAY;
+ int boot_stat;
+
+ /* Wait for the boot to complete (or not) */
+ while (count) {
+ boot_stat = mdio_clause45_read(efx, phy_id,
+ MDIO_MMD_PCS,
+ PCS_BOOT_STATUS_REG);
+ if (boot_stat & (1 << PCS_BOOT_COMPLETE_LBN))
+ break;
+ count--;
+ udelay(PCS_BOOT_POLL_DELAY);
+ }
+
+ if (!count) {
+ EFX_ERR(efx, "%s: PHY boot timed out. Last status "
+ "%x\n", __func__,
+ (boot_stat >> PCS_BOOT_PROGRESS_LBN) &
+ ((1 << PCS_BOOT_PROGRESS_WIDTH) - 1));
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void tenxpress_reset_xaui(struct efx_nic *efx);
+
+static int tenxpress_init(struct efx_nic *efx)
+{
+ int rc, reg;
+
+ /* Turn on the clock */
+ reg = (1 << CLK312_EN_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id,
+ MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
+
+ rc = tenxpress_phy_check(efx);
+ if (rc < 0)
+ return rc;
+
+ /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
+ reg = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG);
+ reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_CTRL_REG, reg);
+
+ reg = PMA_PMD_LED_DEFAULT;
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_OVERR_REG, reg);
+
+ return rc;
+}
+
+static int tenxpress_phy_init(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data;
+ int rc = 0;
+
+ phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
+ efx->phy_data = phy_data;
+
+ tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
+
+ rc = mdio_clause45_wait_reset_mmds(efx,
+ TENXPRESS_REQUIRED_DEVS);
+ if (rc < 0)
+ goto fail;
+
+ rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
+ if (rc < 0)
+ goto fail;
+
+ rc = tenxpress_init(efx);
+ if (rc < 0)
+ goto fail;
+
+ schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
+
+ /* Let XGXS and SerDes out of reset and resets 10XPress */
+ falcon_reset_xaui(efx);
+
+ return 0;
+
+ fail:
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+ return rc;
+}
+
+static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp)
+{
+ struct tenxpress_phy_data *pd = efx->phy_data;
+ int reg;
+
+ /* Nothing to do if all is well and was previously so. */
+ if (!(bad_lp || pd->bad_lp_tries))
+ return;
+
+ reg = mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG);
+
+ if (bad_lp)
+ pd->bad_lp_tries++;
+ else
+ pd->bad_lp_tries = 0;
+
+ if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
+ pd->bad_lp_tries = 0; /* Restart count */
+ reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
+ reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
+ EFX_ERR(efx, "This NIC appears to be plugged into"
+ " a port that is not 10GBASE-T capable.\n"
+ " This PHY is 10GBASE-T ONLY, so no link can"
+ " be established.\n");
+ } else {
+ reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN);
+ }
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_OVERR_REG, reg);
+}
+
+/* Check link status and return a boolean OK value. If the link is NOT
+ * OK we have a quick rummage round to see if we appear to be plugged
+ * into a non-10GBT port and if so warn the user that they won't get
+ * link any time soon as we are 10GBT only, unless caller specified
+ * not to do this check (it isn't useful in loopback) */
+static int tenxpress_link_ok(struct efx_nic *efx, int check_lp)
+{
+ int ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS);
+
+ if (ok) {
+ tenxpress_set_bad_lp(efx, 0);
+ } else if (check_lp) {
+ /* Are we plugged into the wrong sort of link? */
+ int bad_lp = 0;
+ int phy_id = efx->mii.phy_id;
+ int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
+ MDIO_AN_STATUS);
+ int xphy_stat = mdio_clause45_read(efx, phy_id,
+ MDIO_MMD_PMAPMD,
+ PMA_PMD_XSTATUS_REG);
+ /* Are we plugged into anything that sends FLPs? If
+ * not we can't distinguish between not being plugged
+ * in and being plugged into a non-AN antique. The FLP
+ * bit has the advantage of not clearing when autoneg
+ * restarts. */
+ if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) {
+ tenxpress_set_bad_lp(efx, 0);
+ return ok;
+ }
+
+ /* If it can do 10GBT it must be XNP capable */
+ bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN));
+ if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) {
+ bad_lp = !(mdio_clause45_read(efx, phy_id,
+ MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) &
+ (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN));
+ }
+ tenxpress_set_bad_lp(efx, bad_lp);
+ }
+ return ok;
+}
+
+static void tenxpress_phy_reconfigure(struct efx_nic *efx)
+{
+ if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL))
+ return;
+
+ efx->link_up = tenxpress_link_ok(efx, 0);
+ efx->link_options = GM_LPA_10000FULL;
+}
+
+static void tenxpress_phy_clear_interrupt(struct efx_nic *efx)
+{
+ /* Nothing done here - LASI interrupts aren't reliable so poll */
+}
+
+
+/* Poll PHY for interrupt */
+static int tenxpress_phy_check_hw(struct efx_nic *efx)
+{
+ struct tenxpress_phy_data *phy_data = efx->phy_data;
+ int phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL);
+ int link_ok;
+
+ link_ok = phy_up && tenxpress_link_ok(efx, 1);
+
+ if (link_ok != efx->link_up)
+ falcon_xmac_sim_phy_event(efx);
+
+ /* Nothing to check if we've already shut down the PHY */
+ if (!phy_up)
+ return 0;
+
+ if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {
+ EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n");
+ falcon_reset_xaui(efx);
+ atomic_set(&phy_data->bad_crc_count, 0);
+ }
+
+ return 0;
+}
+
+static void tenxpress_phy_fini(struct efx_nic *efx)
+{
+ int reg;
+
+ /* Power down the LNPGA */
+ reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_XCONTROL_REG, reg);
+
+ /* Waiting here ensures that the board fini, which can turn off the
+ * power to the PHY, won't get run until the LNPGA powerdown has been
+ * given long enough to complete. */
+ schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
+
+ kfree(efx->phy_data);
+ efx->phy_data = NULL;
+}
+
+
+/* Set the RX and TX LEDs and Link LED flashing. The other LEDs
+ * (which probably aren't wired anyway) are left in AUTO mode */
+void tenxpress_phy_blink(struct efx_nic *efx, int blink)
+{
+ int reg;
+
+ if (blink)
+ reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) |
+ (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) |
+ (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN);
+ else
+ reg = PMA_PMD_LED_DEFAULT;
+
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ PMA_PMD_LED_OVERR_REG, reg);
+}
+
+static void tenxpress_reset_xaui(struct efx_nic *efx)
+{
+ int phy = efx->mii.phy_id;
+ int clk_ctrl, test_select, soft_rst2;
+
+ /* Real work is done on clock_ctrl other resets are thought to be
+ * optional but make the reset more reliable
+ */
+
+ /* Read */
+ clk_ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
+ PCS_CLOCK_CTRL_REG);
+ test_select = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
+ PCS_TEST_SELECT_REG);
+ soft_rst2 = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
+ PCS_SOFT_RST2_REG);
+
+ /* Put in reset */
+ test_select &= ~(1 << CLK312_EN_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_TEST_SELECT_REG, test_select);
+
+ soft_rst2 &= ~((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_SOFT_RST2_REG, soft_rst2);
+
+ clk_ctrl &= ~(1 << PLL312_RST_N_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_CLOCK_CTRL_REG, clk_ctrl);
+ udelay(10);
+
+ /* Remove reset */
+ clk_ctrl |= (1 << PLL312_RST_N_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_CLOCK_CTRL_REG, clk_ctrl);
+ udelay(10);
+
+ soft_rst2 |= ((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_SOFT_RST2_REG, soft_rst2);
+ udelay(10);
+
+ test_select |= (1 << CLK312_EN_LBN);
+ mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
+ PCS_TEST_SELECT_REG, test_select);
+ udelay(10);
+}
+
+struct efx_phy_operations falcon_tenxpress_phy_ops = {
+ .init = tenxpress_phy_init,
+ .reconfigure = tenxpress_phy_reconfigure,
+ .check_hw = tenxpress_phy_check_hw,
+ .fini = tenxpress_phy_fini,
+ .clear_interrupt = tenxpress_phy_clear_interrupt,
+ .reset_xaui = tenxpress_reset_xaui,
+ .mmds = TENXPRESS_REQUIRED_DEVS,
+};
diff --git a/drivers/net/sfc/tx.c b/drivers/net/sfc/tx.c
new file mode 100644
index 0000000..fbb866b
--- /dev/null
+++ b/drivers/net/sfc/tx.c
@@ -0,0 +1,452 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2005-2006 Fen Systems Ltd.
+ * Copyright 2005-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#include <linux/pci.h>
+#include <linux/tcp.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/if_ether.h>
+#include <linux/highmem.h>
+#include "net_driver.h"
+#include "tx.h"
+#include "efx.h"
+#include "falcon.h"
+#include "workarounds.h"
+
+/*
+ * TX descriptor ring full threshold
+ *
+ * The tx_queue descriptor ring fill-level must fall below this value
+ * before we restart the netif queue
+ */
+#define EFX_NETDEV_TX_THRESHOLD(_tx_queue) \
+ (_tx_queue->efx->type->txd_ring_mask / 2u)
+
+/* We want to be able to nest calls to netif_stop_queue(), since each
+ * channel can have an individual stop on the queue.
+ */
+void efx_stop_queue(struct efx_nic *efx)
+{
+ spin_lock_bh(&efx->netif_stop_lock);
+ EFX_TRACE(efx, "stop TX queue\n");
+
+ atomic_inc(&efx->netif_stop_count);
+ netif_stop_queue(efx->net_dev);
+
+ spin_unlock_bh(&efx->netif_stop_lock);
+}
+
+/* Wake netif's TX queue
+ * We want to be able to nest calls to netif_stop_queue(), since each
+ * channel can have an individual stop on the queue.
+ */
+inline void efx_wake_queue(struct efx_nic *efx)
+{
+ local_bh_disable();
+ if (atomic_dec_and_lock(&efx->netif_stop_count,
+ &efx->netif_stop_lock)) {
+ EFX_TRACE(efx, "waking TX queue\n");
+ netif_wake_queue(efx->net_dev);
+ spin_unlock(&efx->netif_stop_lock);
+ }
+ local_bh_enable();
+}
+
+static inline void efx_dequeue_buffer(struct efx_tx_queue *tx_queue,
+ struct efx_tx_buffer *buffer)
+{
+ if (buffer->unmap_len) {
+ struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
+ if (buffer->unmap_single)
+ pci_unmap_single(pci_dev, buffer->unmap_addr,
+ buffer->unmap_len, PCI_DMA_TODEVICE);
+ else
+ pci_unmap_page(pci_dev, buffer->unmap_addr,
+ buffer->unmap_len, PCI_DMA_TODEVICE);
+ buffer->unmap_len = 0;
+ buffer->unmap_single = 0;
+ }
+
+ if (buffer->skb) {
+ dev_kfree_skb_any((struct sk_buff *) buffer->skb);
+ buffer->skb = NULL;
+ EFX_TRACE(tx_queue->efx, "TX queue %d transmission id %x "
+ "complete\n", tx_queue->queue, read_ptr);
+ }
+}
+
+
+/*
+ * Add a socket buffer to a TX queue
+ *
+ * This maps all fragments of a socket buffer for DMA and adds them to
+ * the TX queue. The queue's insert pointer will be incremented by
+ * the number of fragments in the socket buffer.
+ *
+ * If any DMA mapping fails, any mapped fragments will be unmapped,
+ * the queue's insert pointer will be restored to its original value.
+ *
+ * Returns NETDEV_TX_OK or NETDEV_TX_BUSY
+ * You must hold netif_tx_lock() to call this function.
+ */
+static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
+ const struct sk_buff *skb)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ struct pci_dev *pci_dev = efx->pci_dev;
+ struct efx_tx_buffer *buffer;
+ skb_frag_t *fragment;
+ struct page *page;
+ int page_offset;
+ unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign;
+ dma_addr_t dma_addr, unmap_addr = 0;
+ unsigned int dma_len;
+ unsigned unmap_single;
+ int q_space, i = 0;
+ int rc = NETDEV_TX_OK;
+
+ EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
+
+ /* Get size of the initial fragment */
+ len = skb_headlen(skb);
+
+ fill_level = tx_queue->insert_count - tx_queue->old_read_count;
+ q_space = efx->type->txd_ring_mask - 1 - fill_level;
+
+ /* Map for DMA. Use pci_map_single rather than pci_map_page
+ * since this is more efficient on machines with sparse
+ * memory.
+ */
+ unmap_single = 1;
+ dma_addr = pci_map_single(pci_dev, skb->data, len, PCI_DMA_TODEVICE);
+
+ /* Process all fragments */
+ while (1) {
+ if (unlikely(pci_dma_mapping_error(dma_addr)))
+ goto pci_err;
+
+ /* Store fields for marking in the per-fragment final
+ * descriptor */
+ unmap_len = len;
+ unmap_addr = dma_addr;
+
+ /* Add to TX queue, splitting across DMA boundaries */
+ do {
+ if (unlikely(q_space-- <= 0)) {
+ /* It might be that completions have
+ * happened since the xmit path last
+ * checked. Update the xmit path's
+ * copy of read_count.
+ */
+ ++tx_queue->stopped;
+ /* This memory barrier protects the
+ * change of stopped from the access
+ * of read_count. */
+ smp_mb();
+ tx_queue->old_read_count =
+ *(volatile unsigned *)
+ &tx_queue->read_count;
+ fill_level = (tx_queue->insert_count
+ - tx_queue->old_read_count);
+ q_space = (efx->type->txd_ring_mask - 1 -
+ fill_level);
+ if (unlikely(q_space-- <= 0))
+ goto stop;
+ smp_mb();
+ --tx_queue->stopped;
+ }
+
+ insert_ptr = (tx_queue->insert_count &
+ efx->type->txd_ring_mask);
+ buffer = &tx_queue->buffer[insert_ptr];
+ EFX_BUG_ON_PARANOID(buffer->skb);
+ EFX_BUG_ON_PARANOID(buffer->len);
+ EFX_BUG_ON_PARANOID(buffer->continuation != 1);
+ EFX_BUG_ON_PARANOID(buffer->unmap_len);
+
+ dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1);
+ if (likely(dma_len > len))
+ dma_len = len;
+
+ misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
+ if (misalign && dma_len + misalign > 512)
+ dma_len = 512 - misalign;
+
+ /* Fill out per descriptor fields */
+ buffer->len = dma_len;
+ buffer->dma_addr = dma_addr;
+ len -= dma_len;
+ dma_addr += dma_len;
+ ++tx_queue->insert_count;
+ } while (len);
+
+ /* Transfer ownership of the unmapping to the final buffer */
+ buffer->unmap_addr = unmap_addr;
+ buffer->unmap_single = unmap_single;
+ buffer->unmap_len = unmap_len;
+ unmap_len = 0;
+
+ /* Get address and size of next fragment */
+ if (i >= skb_shinfo(skb)->nr_frags)
+ break;
+ fragment = &skb_shinfo(skb)->frags[i];
+ len = fragment->size;
+ page = fragment->page;
+ page_offset = fragment->page_offset;
+ i++;
+ /* Map for DMA */
+ unmap_single = 0;
+ dma_addr = pci_map_page(pci_dev, page, page_offset, len,
+ PCI_DMA_TODEVICE);
+ }
+
+ /* Transfer ownership of the skb to the final buffer */
+ buffer->skb = skb;
+ buffer->continuation = 0;
+
+ /* Pass off to hardware */
+ falcon_push_buffers(tx_queue);
+
+ return NETDEV_TX_OK;
+
+ pci_err:
+ EFX_ERR_RL(efx, " TX queue %d could not map skb with %d bytes %d "
+ "fragments for DMA\n", tx_queue->queue, skb->len,
+ skb_shinfo(skb)->nr_frags + 1);
+
+ /* Mark the packet as transmitted, and free the SKB ourselves */
+ dev_kfree_skb_any((struct sk_buff *)skb);
+ goto unwind;
+
+ stop:
+ rc = NETDEV_TX_BUSY;
+
+ if (tx_queue->stopped == 1)
+ efx_stop_queue(efx);
+
+ unwind:
+ /* Work backwards until we hit the original insert pointer value */
+ while (tx_queue->insert_count != tx_queue->write_count) {
+ --tx_queue->insert_count;
+ insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask;
+ buffer = &tx_queue->buffer[insert_ptr];
+ efx_dequeue_buffer(tx_queue, buffer);
+ buffer->len = 0;
+ }
+
+ /* Free the fragment we were mid-way through pushing */
+ if (unmap_len)
+ pci_unmap_page(pci_dev, unmap_addr, unmap_len,
+ PCI_DMA_TODEVICE);
+
+ return rc;
+}
+
+/* Remove packets from the TX queue
+ *
+ * This removes packets from the TX queue, up to and including the
+ * specified index.
+ */
+static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
+ unsigned int index)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ unsigned int stop_index, read_ptr;
+ unsigned int mask = tx_queue->efx->type->txd_ring_mask;
+
+ stop_index = (index + 1) & mask;
+ read_ptr = tx_queue->read_count & mask;
+
+ while (read_ptr != stop_index) {
+ struct efx_tx_buffer *buffer = &tx_queue->buffer[read_ptr];
+ if (unlikely(buffer->len == 0)) {
+ EFX_ERR(tx_queue->efx, "TX queue %d spurious TX "
+ "completion id %x\n", tx_queue->queue,
+ read_ptr);
+ efx_schedule_reset(efx, RESET_TYPE_TX_SKIP);
+ return;
+ }
+
+ efx_dequeue_buffer(tx_queue, buffer);
+ buffer->continuation = 1;
+ buffer->len = 0;
+
+ ++tx_queue->read_count;
+ read_ptr = tx_queue->read_count & mask;
+ }
+}
+
+/* Initiate a packet transmission on the specified TX queue.
+ * Note that returning anything other than NETDEV_TX_OK will cause the
+ * OS to free the skb.
+ *
+ * This function is split out from efx_hard_start_xmit to allow the
+ * loopback test to direct packets via specific TX queues. It is
+ * therefore a non-static inline, so as not to penalise performance
+ * for non-loopback transmissions.
+ *
+ * Context: netif_tx_lock held
+ */
+inline int efx_xmit(struct efx_nic *efx,
+ struct efx_tx_queue *tx_queue, struct sk_buff *skb)
+{
+ int rc;
+
+ /* Map fragments for DMA and add to TX queue */
+ rc = efx_enqueue_skb(tx_queue, skb);
+ if (unlikely(rc != NETDEV_TX_OK))
+ goto out;
+
+ /* Update last TX timer */
+ efx->net_dev->trans_start = jiffies;
+
+ out:
+ return rc;
+}
+
+/* Initiate a packet transmission. We use one channel per CPU
+ * (sharing when we have more CPUs than channels). On Falcon, the TX
+ * completion events will be directed back to the CPU that transmitted
+ * the packet, which should be cache-efficient.
+ *
+ * Context: non-blocking.
+ * Note that returning anything other than NETDEV_TX_OK will cause the
+ * OS to free the skb.
+ */
+int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
+{
+ struct efx_nic *efx = net_dev->priv;
+ return efx_xmit(efx, &efx->tx_queue[0], skb);
+}
+
+void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
+{
+ unsigned fill_level;
+ struct efx_nic *efx = tx_queue->efx;
+
+ EFX_BUG_ON_PARANOID(index > efx->type->txd_ring_mask);
+
+ efx_dequeue_buffers(tx_queue, index);
+
+ /* See if we need to restart the netif queue. This barrier
+ * separates the update of read_count from the test of
+ * stopped. */
+ smp_mb();
+ if (unlikely(tx_queue->stopped)) {
+ fill_level = tx_queue->insert_count - tx_queue->read_count;
+ if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) {
+ EFX_BUG_ON_PARANOID(!NET_DEV_REGISTERED(efx));
+
+ /* Do this under netif_tx_lock(), to avoid racing
+ * with efx_xmit(). */
+ netif_tx_lock(efx->net_dev);
+ if (tx_queue->stopped) {
+ tx_queue->stopped = 0;
+ efx_wake_queue(efx);
+ }
+ netif_tx_unlock(efx->net_dev);
+ }
+ }
+}
+
+int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ struct efx_nic *efx = tx_queue->efx;
+ unsigned int txq_size;
+ int i, rc;
+
+ EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue);
+
+ /* Allocate software ring */
+ txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer);
+ tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
+ if (!tx_queue->buffer) {
+ rc = -ENOMEM;
+ goto fail1;
+ }
+ for (i = 0; i <= efx->type->txd_ring_mask; ++i)
+ tx_queue->buffer[i].continuation = 1;
+
+ /* Allocate hardware ring */
+ rc = falcon_probe_tx(tx_queue);
+ if (rc)
+ goto fail2;
+
+ return 0;
+
+ fail2:
+ kfree(tx_queue->buffer);
+ tx_queue->buffer = NULL;
+ fail1:
+ tx_queue->used = 0;
+
+ return rc;
+}
+
+int efx_init_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue);
+
+ tx_queue->insert_count = 0;
+ tx_queue->write_count = 0;
+ tx_queue->read_count = 0;
+ tx_queue->old_read_count = 0;
+ BUG_ON(tx_queue->stopped);
+
+ /* Set up TX descriptor ring */
+ return falcon_init_tx(tx_queue);
+}
+
+void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
+{
+ struct efx_tx_buffer *buffer;
+
+ if (!tx_queue->buffer)
+ return;
+
+ /* Free any buffers left in the ring */
+ while (tx_queue->read_count != tx_queue->write_count) {
+ buffer = &tx_queue->buffer[tx_queue->read_count &
+ tx_queue->efx->type->txd_ring_mask];
+ efx_dequeue_buffer(tx_queue, buffer);
+ buffer->continuation = 1;
+ buffer->len = 0;
+
+ ++tx_queue->read_count;
+ }
+}
+
+void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue);
+
+ /* Flush TX queue, remove descriptor ring */
+ falcon_fini_tx(tx_queue);
+
+ efx_release_tx_buffers(tx_queue);
+
+ /* Release queue's stop on port, if any */
+ if (tx_queue->stopped) {
+ tx_queue->stopped = 0;
+ efx_wake_queue(tx_queue->efx);
+ }
+}
+
+void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
+{
+ EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue);
+ falcon_remove_tx(tx_queue);
+
+ kfree(tx_queue->buffer);
+ tx_queue->buffer = NULL;
+ tx_queue->used = 0;
+}
+
+
diff --git a/drivers/net/sfc/tx.h b/drivers/net/sfc/tx.h
new file mode 100644
index 0000000..1526a73
--- /dev/null
+++ b/drivers/net/sfc/tx.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006 Fen Systems Ltd.
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_TX_H
+#define EFX_TX_H
+
+#include "net_driver.h"
+
+int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
+void efx_remove_tx_queue(struct efx_tx_queue *tx_queue);
+int efx_init_tx_queue(struct efx_tx_queue *tx_queue);
+void efx_fini_tx_queue(struct efx_tx_queue *tx_queue);
+
+int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
+void efx_release_tx_buffers(struct efx_tx_queue *tx_queue);
+
+#endif /* EFX_TX_H */
diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h
new file mode 100644
index 0000000..dca62f1
--- /dev/null
+++ b/drivers/net/sfc/workarounds.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_WORKAROUNDS_H
+#define EFX_WORKAROUNDS_H
+
+/*
+ * Hardware workarounds.
+ * Bug numbers are from Solarflare's Bugzilla.
+ */
+
+#define EFX_WORKAROUND_ALWAYS(efx) 1
+#define EFX_WORKAROUND_FALCON_A(efx) (FALCON_REV(efx) <= FALCON_REV_A1)
+
+/* XAUI resets if link not detected */
+#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
+/* SNAP frames have TOBE_DISC set */
+#define EFX_WORKAROUND_5475 EFX_WORKAROUND_ALWAYS
+/* RX PCIe double split performance issue */
+#define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
+/* TX pkt parser problem with <= 16 byte TXes */
+#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
+/* XGXS and XAUI reset sequencing in SW */
+#define EFX_WORKAROUND_9388 EFX_WORKAROUND_ALWAYS
+/* Low rate CRC errors require XAUI reset */
+#define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS
+/* TX_EV_PKT_ERR can be caused by a dangling TX descriptor
+ * or a PCIe error (bug 11028) */
+#define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS
+/* Transmit flow control may get disabled */
+#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS
+/* Flush events can take a very long time to appear */
+#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS
+
+/* Spurious parity errors in TSORT buffers */
+#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
+/* iSCSI parsing errors */
+#define EFX_WORKAROUND_5583 EFX_WORKAROUND_FALCON_A
+/* RX events go missing */
+#define EFX_WORKAROUND_5676 EFX_WORKAROUND_FALCON_A
+/* RX_RESET on A1 */
+#define EFX_WORKAROUND_6555 EFX_WORKAROUND_FALCON_A
+/* Increase filter depth to avoid RX_RESET */
+#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
+/* Flushes may never complete */
+#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
+/* Leak overlength packets rather than free */
+#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
+
+#endif /* EFX_WORKAROUNDS_H */
diff --git a/drivers/net/sfc/xenpack.h b/drivers/net/sfc/xenpack.h
new file mode 100644
index 0000000..b0d1f22
--- /dev/null
+++ b/drivers/net/sfc/xenpack.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+
+#ifndef EFX_XENPACK_H
+#define EFX_XENPACK_H
+
+/* Exported functions from Xenpack standard PHY control */
+
+#include "mdio_10g.h"
+
+/****************************************************************************/
+/* XENPACK MDIO register extensions */
+#define MDIO_XP_LASI_RX_CTRL (0x9000)
+#define MDIO_XP_LASI_TX_CTRL (0x9001)
+#define MDIO_XP_LASI_CTRL (0x9002)
+#define MDIO_XP_LASI_RX_STAT (0x9003)
+#define MDIO_XP_LASI_TX_STAT (0x9004)
+#define MDIO_XP_LASI_STAT (0x9005)
+
+/* Control/Status bits */
+#define XP_LASI_LS_ALARM (1 << 0)
+#define XP_LASI_TX_ALARM (1 << 1)
+#define XP_LASI_RX_ALARM (1 << 2)
+/* These two are Quake vendor extensions to the standard XENPACK defines */
+#define XP_LASI_LS_INTB (1 << 3)
+#define XP_LASI_TEST (1 << 7)
+
+/* Enable LASI interrupts for PHY */
+static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx)
+{
+ int reg;
+ int phy_id = efx->mii.phy_id;
+ /* Read to clear LASI status register */
+ reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_XP_LASI_STAT);
+
+ mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
+ MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM);
+}
+
+/* Read the LASI interrupt status to clear the interrupt. */
+static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx)
+{
+ /* Read to clear link status alarm */
+ return mdio_clause45_read(efx, efx->mii.phy_id,
+ MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
+}
+
+/* Turn off LASI interrupts */
+static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx)
+{
+ mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+ MDIO_XP_LASI_CTRL, 0);
+}
+
+#endif /* EFX_XENPACK_H */
diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c
new file mode 100644
index 0000000..66dd5bf
--- /dev/null
+++ b/drivers/net/sfc/xfp_phy.c
@@ -0,0 +1,132 @@
+/****************************************************************************
+ * Driver for Solarflare Solarstorm network controllers and boards
+ * Copyright 2006-2008 Solarflare Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, incorporated herein by reference.
+ */
+/*
+ * Driver for XFP optical PHYs (plus some support specific to the Quake 2032)
+ * See www.amcc.com for details (search for qt2032)
+ */
+
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include "efx.h"
+#include "gmii.h"
+#include "mdio_10g.h"
+#include "xenpack.h"
+#include "phy.h"
+#include "mac.h"
+
+#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS | \
+ MDIO_MMDREG_DEVS0_PMAPMD | \
+ MDIO_MMDREG_DEVS0_PHYXS)
+
+/****************************************************************************/
+/* Quake-specific MDIO registers */
+#define MDIO_QUAKE_LED0_REG (0xD006)
+
+void xfp_set_led(struct efx_nic *p, int led, int mode)
+{
+ int addr = MDIO_QUAKE_LED0_REG + led;
+ mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr,
+ mode);
+}
+
+#define XFP_MAX_RESET_TIME 500
+#define XFP_RESET_WAIT 10
+
+/* Reset the PHYXS MMD. This is documented (for the Quake PHY) as doing
+ * a complete soft reset.
+ */
+static int xfp_reset_phy(struct efx_nic *efx)
+{
+ int rc;
+
+ rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS,
+ XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
+ XFP_RESET_WAIT);
+ if (rc < 0)
+ goto fail;
+
+ /* Wait 250ms for the PHY to complete bootup */
+ msleep(250);
+
+ /* Check that all the MMDs we expect are present and responding. We
+ * expect faults on some if the link is down, but not on the PHY XS */
+ rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS,
+ MDIO_MMDREG_DEVS0_PHYXS);
+ if (rc < 0)
+ goto fail;
+
+ efx->board_info.init_leds(efx);
+
+ return rc;
+
+ fail:
+ EFX_ERR(efx, "XFP: reset timed out!\n");
+ return rc;
+}
+
+static int xfp_phy_init(struct efx_nic *efx)
+{
+ u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
+ int rc;
+
+ EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
+ " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
+ MDIO_ID_REV(devid));
+
+ rc = xfp_reset_phy(efx);
+
+ EFX_INFO(efx, "XFP: PHY init %s.\n",
+ rc ? "failed" : "successful");
+
+ return rc;
+}
+
+static void xfp_phy_clear_interrupt(struct efx_nic *efx)
+{
+ xenpack_clear_lasi_irqs(efx);
+}
+
+static int xfp_link_ok(struct efx_nic *efx)
+{
+ return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS);
+}
+
+static int xfp_phy_check_hw(struct efx_nic *efx)
+{
+ int rc = 0;
+ int link_up = xfp_link_ok(efx);
+ /* Simulate a PHY event if link state has changed */
+ if (link_up != efx->link_up)
+ falcon_xmac_sim_phy_event(efx);
+
+ return rc;
+}
+
+static void xfp_phy_reconfigure(struct efx_nic *efx)
+{
+ efx->link_up = xfp_link_ok(efx);
+ efx->link_options = GM_LPA_10000FULL;
+}
+
+
+static void xfp_phy_fini(struct efx_nic *efx)
+{
+ /* Clobber the LED if it was blinking */
+ efx->board_info.blink(efx, 0);
+}
+
+struct efx_phy_operations falcon_xfp_phy_ops = {
+ .init = xfp_phy_init,
+ .reconfigure = xfp_phy_reconfigure,
+ .check_hw = xfp_phy_check_hw,
+ .fini = xfp_phy_fini,
+ .clear_interrupt = xfp_phy_clear_interrupt,
+ .reset_xaui = efx_port_dummy_op_void,
+ .mmds = XFP_REQUIRED_DEVS,
+};
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index 20745fd..abc63b0 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -212,6 +212,12 @@
THOL2 = 0x20000000,
THOL1 = 0x10000000,
THOL0 = 0x00000000,
+
+ WND = 0x00080000,
+ TABRT = 0x00040000,
+ FIFO = 0x00020000,
+ LINK = 0x00010000,
+ ColCountMask = 0x0000ffff,
/* RxDesc.status */
IPON = 0x20000000,
TCPON = 0x10000000,
@@ -480,30 +486,23 @@
desc->status = 0x0;
}
-static int sis190_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
- struct RxDesc *desc, u32 rx_buf_sz)
+static struct sk_buff *sis190_alloc_rx_skb(struct sis190_private *tp,
+ struct RxDesc *desc)
{
+ u32 rx_buf_sz = tp->rx_buf_sz;
struct sk_buff *skb;
- dma_addr_t mapping;
- int ret = 0;
- skb = dev_alloc_skb(rx_buf_sz);
- if (!skb)
- goto err_out;
+ skb = netdev_alloc_skb(tp->dev, rx_buf_sz);
+ if (likely(skb)) {
+ dma_addr_t mapping;
- *sk_buff = skb;
+ mapping = pci_map_single(tp->pci_dev, skb->data, tp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
+ sis190_map_to_asic(desc, mapping, rx_buf_sz);
+ } else
+ sis190_make_unusable_by_asic(desc);
- mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
- PCI_DMA_FROMDEVICE);
-
- sis190_map_to_asic(desc, mapping, rx_buf_sz);
-out:
- return ret;
-
-err_out:
- ret = -ENOMEM;
- sis190_make_unusable_by_asic(desc);
- goto out;
+ return skb;
}
static u32 sis190_rx_fill(struct sis190_private *tp, struct net_device *dev,
@@ -512,37 +511,41 @@
u32 cur;
for (cur = start; cur < end; cur++) {
- int ret, i = cur % NUM_RX_DESC;
+ unsigned int i = cur % NUM_RX_DESC;
if (tp->Rx_skbuff[i])
continue;
- ret = sis190_alloc_rx_skb(tp->pci_dev, tp->Rx_skbuff + i,
- tp->RxDescRing + i, tp->rx_buf_sz);
- if (ret < 0)
+ tp->Rx_skbuff[i] = sis190_alloc_rx_skb(tp, tp->RxDescRing + i);
+
+ if (!tp->Rx_skbuff[i])
break;
}
return cur - start;
}
-static inline int sis190_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
- struct RxDesc *desc, int rx_buf_sz)
+static bool sis190_try_rx_copy(struct sis190_private *tp,
+ struct sk_buff **sk_buff, int pkt_size,
+ dma_addr_t addr)
{
- int ret = -1;
+ struct sk_buff *skb;
+ bool done = false;
- if (pkt_size < rx_copybreak) {
- struct sk_buff *skb;
+ if (pkt_size >= rx_copybreak)
+ goto out;
- skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
- if (skb) {
- skb_reserve(skb, NET_IP_ALIGN);
- skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
- *sk_buff = skb;
- sis190_give_to_asic(desc, rx_buf_sz);
- ret = 0;
- }
- }
- return ret;
+ skb = netdev_alloc_skb(tp->dev, pkt_size + 2);
+ if (!skb)
+ goto out;
+
+ pci_dma_sync_single_for_device(tp->pci_dev, addr, pkt_size,
+ PCI_DMA_FROMDEVICE);
+ skb_reserve(skb, 2);
+ skb_copy_to_linear_data(skb, sk_buff[0]->data, pkt_size);
+ *sk_buff = skb;
+ done = true;
+out:
+ return done;
}
static inline int sis190_rx_pkt_err(u32 status, struct net_device_stats *stats)
@@ -592,9 +595,9 @@
sis190_give_to_asic(desc, tp->rx_buf_sz);
else {
struct sk_buff *skb = tp->Rx_skbuff[entry];
+ dma_addr_t addr = le32_to_cpu(desc->addr);
int pkt_size = (status & RxSizeMask) - 4;
- void (*pci_action)(struct pci_dev *, dma_addr_t,
- size_t, int) = pci_dma_sync_single_for_device;
+ struct pci_dev *pdev = tp->pci_dev;
if (unlikely(pkt_size > tp->rx_buf_sz)) {
net_intr(tp, KERN_INFO
@@ -606,20 +609,18 @@
continue;
}
- pci_dma_sync_single_for_cpu(tp->pci_dev,
- le32_to_cpu(desc->addr), tp->rx_buf_sz,
- PCI_DMA_FROMDEVICE);
- if (sis190_try_rx_copy(&skb, pkt_size, desc,
- tp->rx_buf_sz)) {
- pci_action = pci_unmap_single;
+ if (sis190_try_rx_copy(tp, &skb, pkt_size, addr)) {
+ pci_dma_sync_single_for_device(pdev, addr,
+ tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ sis190_give_to_asic(desc, tp->rx_buf_sz);
+ } else {
+ pci_unmap_single(pdev, addr, tp->rx_buf_sz,
+ PCI_DMA_FROMDEVICE);
tp->Rx_skbuff[entry] = NULL;
sis190_make_unusable_by_asic(desc);
}
- pci_action(tp->pci_dev, le32_to_cpu(desc->addr),
- tp->rx_buf_sz, PCI_DMA_FROMDEVICE);
-
skb_put(skb, pkt_size);
skb->protocol = eth_type_trans(skb, dev);
@@ -658,9 +659,31 @@
memset(desc, 0x00, sizeof(*desc));
}
+static inline int sis190_tx_pkt_err(u32 status, struct net_device_stats *stats)
+{
+#define TxErrMask (WND | TABRT | FIFO | LINK)
+
+ if (!unlikely(status & TxErrMask))
+ return 0;
+
+ if (status & WND)
+ stats->tx_window_errors++;
+ if (status & TABRT)
+ stats->tx_aborted_errors++;
+ if (status & FIFO)
+ stats->tx_fifo_errors++;
+ if (status & LINK)
+ stats->tx_carrier_errors++;
+
+ stats->tx_errors++;
+
+ return -1;
+}
+
static void sis190_tx_interrupt(struct net_device *dev,
struct sis190_private *tp, void __iomem *ioaddr)
{
+ struct net_device_stats *stats = &dev->stats;
u32 pending, dirty_tx = tp->dirty_tx;
/*
* It would not be needed if queueing was allowed to be enabled
@@ -675,15 +698,19 @@
for (; pending; pending--, dirty_tx++) {
unsigned int entry = dirty_tx % NUM_TX_DESC;
struct TxDesc *txd = tp->TxDescRing + entry;
+ u32 status = le32_to_cpu(txd->status);
struct sk_buff *skb;
- if (le32_to_cpu(txd->status) & OWNbit)
+ if (status & OWNbit)
break;
skb = tp->Tx_skbuff[entry];
- dev->stats.tx_packets++;
- dev->stats.tx_bytes += skb->len;
+ if (likely(sis190_tx_pkt_err(status, stats) == 0)) {
+ stats->tx_packets++;
+ stats->tx_bytes += skb->len;
+ stats->collisions += ((status & ColCountMask) - 1);
+ }
sis190_unmap_tx_skb(tp->pci_dev, skb, txd);
tp->Tx_skbuff[entry] = NULL;
@@ -904,10 +931,9 @@
mod_timer(&tp->timer, jiffies + HZ/10);
} else if (!(mdio_read_latched(ioaddr, phy_id, MII_BMSR) &
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);
+ net_link(tp, KERN_WARNING "%s: auto-negotiating...\n",
+ dev->name);
mod_timer(&tp->timer, jiffies + SIS190_PHY_TIMEOUT);
} else {
/* Rejoice ! */
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 5a55ede..84af68f 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -396,14 +396,14 @@
/* Order of next two lines is *very* important.
* When we are sending a little amount of data,
- * the transfer may be completed inside driver.write()
+ * the transfer may be completed inside the ops->write()
* routine, because it's running with interrupts enabled.
* In this case we *never* got WRITE_WAKEUP event,
* if we did not request it before write operation.
* 14 Oct 1994 Dmitry Gorodchanin.
*/
sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- actual = sl->tty->driver->write(sl->tty, sl->xbuff, count);
+ actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
#ifdef SL_CHECK_TRANSMIT
sl->dev->trans_start = jiffies;
#endif
@@ -437,7 +437,7 @@
return;
}
- actual = tty->driver->write(tty, sl->xhead, sl->xleft);
+ actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual;
sl->xhead += actual;
}
@@ -462,7 +462,7 @@
}
printk(KERN_WARNING "%s: transmit timed out, %s?\n",
dev->name,
- (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ?
+ (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
"bad line quality" : "driver error");
sl->xleft = 0;
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
@@ -830,6 +830,9 @@
if (!capable(CAP_NET_ADMIN))
return -EPERM;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
/* RTnetlink lock is misused here to serialize concurrent
opens of slip channels. There are better ways, but it is
the simplest one.
@@ -1432,7 +1435,7 @@
/* put END into tty queue. Is it right ??? */
if (!netif_queue_stopped(sl->dev)) {
/* if device busy no outfill */
- sl->tty->driver->write(sl->tty, &s, 1);
+ sl->tty->ops->write(sl->tty, &s, 1);
}
} else
set_bit(SLF_OUTWAIT, &sl->flags);
diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c
index e83b166..432e837 100644
--- a/drivers/net/tehuti.c
+++ b/drivers/net/tehuti.c
@@ -649,7 +649,7 @@
DBG("%d 0x%x 0x%x\n", data[0], data[1], data[2]);
}
- if (!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_SYS_RAWIO))
return -EPERM;
switch (data[0]) {
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index e3f74c9..b66c75e 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -4361,7 +4361,7 @@
}
segs = skb_gso_segment(skb, tp->dev->features & ~NETIF_F_TSO);
- if (unlikely(IS_ERR(segs)))
+ if (IS_ERR(segs))
goto tg3_tso_bug_end;
do {
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index 6c6fc32..bc30c6e 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -482,7 +482,6 @@
static char version[] __devinitdata = "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n";
#define c_char const char
-#define TWIDDLE(a) (u_short)le16_to_cpu(get_unaligned((__le16 *)(a)))
/*
** MII Information
@@ -4405,7 +4404,7 @@
}
}
- lp->infoleaf_offset = TWIDDLE(p+1);
+ lp->infoleaf_offset = get_unaligned_le16(p + 1);
return 0;
}
@@ -4476,7 +4475,7 @@
while (count--) {
gep_wr(((lp->chipset==DC21140) && (lp->ibn!=5) ?
- *p++ : TWIDDLE(w++)), dev);
+ *p++ : get_unaligned_le16(w++)), dev);
mdelay(2); /* 2ms per action */
}
@@ -4711,10 +4710,10 @@
lp->active = *p++;
lp->phy[lp->active].gep = (*p ? p : NULL); p += (*p + 1);
lp->phy[lp->active].rst = (*p ? p : NULL); p += (*p + 1);
- lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
- lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
- lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
- lp->phy[lp->active].ttm = TWIDDLE(p);
+ lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].ttm = get_unaligned_le16(p);
return 0;
} else if ((lp->media == INIT) && (lp->timeout < 0)) {
lp->ibn = 1;
@@ -4751,16 +4750,16 @@
lp->infoblock_media = (*p) & MEDIA_CODE;
if ((*p++) & EXT_FIELD) {
- lp->cache.csr13 = TWIDDLE(p); p += 2;
- lp->cache.csr14 = TWIDDLE(p); p += 2;
- lp->cache.csr15 = TWIDDLE(p); p += 2;
+ lp->cache.csr13 = get_unaligned_le16(p); p += 2;
+ lp->cache.csr14 = get_unaligned_le16(p); p += 2;
+ lp->cache.csr15 = get_unaligned_le16(p); p += 2;
} else {
lp->cache.csr13 = CSR13;
lp->cache.csr14 = CSR14;
lp->cache.csr15 = CSR15;
}
- lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
- lp->cache.gep = ((s32)(TWIDDLE(p)) << 16);
+ lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2;
+ lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16);
lp->infoblock_csr6 = OMR_SIA;
lp->useMII = false;
@@ -4792,10 +4791,10 @@
if (MOTO_SROM_BUG) lp->active = 0;
lp->phy[lp->active].gep = (*p ? p : NULL); p += (2 * (*p) + 1);
lp->phy[lp->active].rst = (*p ? p : NULL); p += (2 * (*p) + 1);
- lp->phy[lp->active].mc = TWIDDLE(p); p += 2;
- lp->phy[lp->active].ana = TWIDDLE(p); p += 2;
- lp->phy[lp->active].fdx = TWIDDLE(p); p += 2;
- lp->phy[lp->active].ttm = TWIDDLE(p); p += 2;
+ lp->phy[lp->active].mc = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].ana = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].fdx = get_unaligned_le16(p); p += 2;
+ lp->phy[lp->active].ttm = get_unaligned_le16(p); p += 2;
lp->phy[lp->active].mci = *p;
return 0;
} else if ((lp->media == INIT) && (lp->timeout < 0)) {
@@ -4835,8 +4834,8 @@
lp->cache.csr13 = CSR13; /* Hard coded defaults */
lp->cache.csr14 = CSR14;
lp->cache.csr15 = CSR15;
- lp->cache.gepc = ((s32)(TWIDDLE(p)) << 16); p += 2;
- lp->cache.gep = ((s32)(TWIDDLE(p)) << 16); p += 2;
+ lp->cache.gepc = ((s32)(get_unaligned_le16(p)) << 16); p += 2;
+ lp->cache.gep = ((s32)(get_unaligned_le16(p)) << 16); p += 2;
csr6 = *p++;
flags = *p++;
diff --git a/drivers/net/tulip/de4x5.h b/drivers/net/tulip/de4x5.h
index 9fb8d7f..f5f33b3 100644
--- a/drivers/net/tulip/de4x5.h
+++ b/drivers/net/tulip/de4x5.h
@@ -1017,4 +1017,4 @@
#define DE4X5_SET_OMR 0x0d /* Set the OMR Register contents */
#define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */
-#define MOTO_SROM_BUG ((lp->active == 8) && (((le32_to_cpu(get_unaligned(((__le32 *)dev->dev_addr))))&0x00ffffff)==0x3e0008))
+#define MOTO_SROM_BUG (lp->active == 8 && (get_unaligned_le32(dev->dev_addr) & 0x00ffffff) == 0x3e0008)
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 908422f..92c68a2 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -25,6 +25,7 @@
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/unaligned.h>
@@ -304,11 +305,7 @@
#define RUN_AT(x) (jiffies + (x))
-#if defined(__i386__) /* AKA get_unaligned() */
-#define get_u16(ptr) (*(u16 *)(ptr))
-#else
-#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
-#endif
+#define get_u16(ptr) get_unaligned_le16((ptr))
struct medialeaf {
u8 type;
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index fa1c1c3..f9d13fa 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -327,8 +327,8 @@
tp->dirty_rx = tp->dirty_tx = 0;
if (tp->flags & MC_HASH_ONLY) {
- u32 addr_low = le32_to_cpu(get_unaligned((__le32 *)dev->dev_addr));
- u32 addr_high = le16_to_cpu(get_unaligned((__le16 *)(dev->dev_addr+4)));
+ u32 addr_low = get_unaligned_le32(dev->dev_addr);
+ u32 addr_high = get_unaligned_le16(dev->dev_addr + 4);
if (tp->chip_id == AX88140) {
iowrite32(0, ioaddr + CSR13);
iowrite32(addr_low, ioaddr + CSR14);
@@ -1437,13 +1437,13 @@
do
value = ioread32(ioaddr + CSR9);
while (value < 0 && --boguscnt > 0);
- put_unaligned(cpu_to_le16(value), ((__le16*)dev->dev_addr) + i);
+ put_unaligned_le16(value, ((__le16 *)dev->dev_addr) + i);
sum += value & 0xffff;
}
} else if (chip_idx == COMET) {
/* No need to read the EEPROM. */
- put_unaligned(cpu_to_le32(ioread32(ioaddr + 0xA4)), (__le32 *)dev->dev_addr);
- put_unaligned(cpu_to_le16(ioread32(ioaddr + 0xA8)), (__le16 *)(dev->dev_addr + 4));
+ put_unaligned_le32(ioread32(ioaddr + 0xA4), dev->dev_addr);
+ put_unaligned_le16(ioread32(ioaddr + 0xA8), dev->dev_addr + 4);
for (i = 0; i < 6; i ++)
sum += dev->dev_addr[i];
} else {
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 555b70c..f926b5a 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -41,6 +41,9 @@
struct net_device *dev;
struct napi_struct napi;
+ /* The skb we couldn't send because buffers were full. */
+ struct sk_buff *last_xmit_skb;
+
/* Number of input buffers, and max we've ever had. */
unsigned int num, max;
@@ -142,10 +145,10 @@
static void try_fill_recv(struct virtnet_info *vi)
{
struct sk_buff *skb;
- struct scatterlist sg[1+MAX_SKB_FRAGS];
+ struct scatterlist sg[2+MAX_SKB_FRAGS];
int num, err;
- sg_init_table(sg, 1+MAX_SKB_FRAGS);
+ sg_init_table(sg, 2+MAX_SKB_FRAGS);
for (;;) {
skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN);
if (unlikely(!skb))
@@ -221,23 +224,22 @@
while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
pr_debug("Sent skb %p\n", skb);
__skb_unlink(skb, &vi->send);
- vi->dev->stats.tx_bytes += len;
+ vi->dev->stats.tx_bytes += skb->len;
vi->dev->stats.tx_packets++;
kfree_skb(skb);
}
}
-static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb)
{
- struct virtnet_info *vi = netdev_priv(dev);
- int num, err;
- struct scatterlist sg[1+MAX_SKB_FRAGS];
+ int num;
+ struct scatterlist sg[2+MAX_SKB_FRAGS];
struct virtio_net_hdr *hdr;
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
- sg_init_table(sg, 1+MAX_SKB_FRAGS);
+ sg_init_table(sg, 2+MAX_SKB_FRAGS);
- pr_debug("%s: xmit %p " MAC_FMT "\n", dev->name, skb,
+ pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb,
dest[0], dest[1], dest[2],
dest[3], dest[4], dest[5]);
@@ -272,30 +274,51 @@
vnet_hdr_to_sg(sg, skb);
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
- __skb_queue_head(&vi->send, skb);
+
+ return vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
+}
+
+static int start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
again:
/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs(vi);
- err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
- if (err) {
- pr_debug("%s: virtio not prepared to send\n", dev->name);
- netif_stop_queue(dev);
- /* Activate callback for using skbs: if this returns false it
- * means some were used in the meantime. */
- if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
- vi->svq->vq_ops->disable_cb(vi->svq);
- netif_start_queue(dev);
- goto again;
+ /* If we has a buffer left over from last time, send it now. */
+ if (vi->last_xmit_skb) {
+ if (xmit_skb(vi, vi->last_xmit_skb) != 0) {
+ /* Drop this skb: we only queue one. */
+ vi->dev->stats.tx_dropped++;
+ kfree_skb(skb);
+ goto stop_queue;
}
- __skb_unlink(skb, &vi->send);
-
- return NETDEV_TX_BUSY;
+ vi->last_xmit_skb = NULL;
}
- vi->svq->vq_ops->kick(vi->svq);
- return 0;
+ /* Put new one in send queue and do transmit */
+ __skb_queue_head(&vi->send, skb);
+ if (xmit_skb(vi, skb) != 0) {
+ vi->last_xmit_skb = skb;
+ goto stop_queue;
+ }
+done:
+ vi->svq->vq_ops->kick(vi->svq);
+ return NETDEV_TX_OK;
+
+stop_queue:
+ pr_debug("%s: virtio not prepared to send\n", dev->name);
+ netif_stop_queue(dev);
+
+ /* Activate callback for using skbs: if this returns false it
+ * means some were used in the meantime. */
+ if (unlikely(!vi->svq->vq_ops->enable_cb(vi->svq))) {
+ vi->svq->vq_ops->disable_cb(vi->svq);
+ netif_start_queue(dev);
+ goto again;
+ }
+ goto done;
}
#ifdef CONFIG_NET_POLL_CONTROLLER
@@ -355,17 +378,26 @@
SET_NETDEV_DEV(dev, &vdev->dev);
/* Do we support "hardware" checksums? */
- if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) {
+ if (csum && virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) {
/* This opens up the world of extra features. */
dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
- if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) {
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
dev->features |= NETIF_F_TSO | NETIF_F_UFO
| NETIF_F_TSO_ECN | NETIF_F_TSO6;
}
+ /* Individual feature bits: what can host handle? */
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4))
+ dev->features |= NETIF_F_TSO;
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6))
+ dev->features |= NETIF_F_TSO6;
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
+ dev->features |= NETIF_F_TSO_ECN;
+ if (gso && virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
+ dev->features |= NETIF_F_UFO;
}
/* Configuration may specify what MAC to use. Otherwise random. */
- if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) {
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
vdev->config->get(vdev,
offsetof(struct virtio_net_config, mac),
dev->dev_addr, dev->addr_len);
@@ -454,7 +486,15 @@
{ 0 },
};
+static unsigned int features[] = {
+ VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
+ VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
+ VIRTIO_NET_F_HOST_ECN,
+};
+
static struct virtio_driver virtio_net = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
diff --git a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c
index 63abfd7..e03eef2 100644
--- a/drivers/net/wan/pc300_tty.c
+++ b/drivers/net/wan/pc300_tty.c
@@ -178,6 +178,20 @@
CPC_TTY_UNLOCK(card,flags);
}
+
+static const struct tty_operations pc300_ops = {
+ .open = cpc_tty_open,
+ .close = cpc_tty_close,
+ .write = cpc_tty_write,
+ .write_room = cpc_tty_write_room,
+ .chars_in_buffer = cpc_tty_chars_in_buffer,
+ .tiocmset = pc300_tiocmset,
+ .tiocmget = pc300_tiocmget,
+ .flush_buffer = cpc_tty_flush_buffer,
+ .hangup = cpc_tty_hangup,
+};
+
+
/*
* PC300 TTY initialization routine
*
@@ -225,15 +239,7 @@
serial_drv.flags = TTY_DRIVER_REAL_RAW;
/* interface routines from the upper tty layer to the tty driver */
- serial_drv.open = cpc_tty_open;
- serial_drv.close = cpc_tty_close;
- serial_drv.write = cpc_tty_write;
- serial_drv.write_room = cpc_tty_write_room;
- serial_drv.chars_in_buffer = cpc_tty_chars_in_buffer;
- serial_drv.tiocmset = pc300_tiocmset;
- serial_drv.tiocmget = pc300_tiocmget;
- serial_drv.flush_buffer = cpc_tty_flush_buffer;
- serial_drv.hangup = cpc_tty_hangup;
+ tty_set_operations(&serial_drv, &pc300_ops);
/* register the TTY driver */
if (tty_register_driver(&serial_drv)) {
diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
index 0f8aca8..249e180 100644
--- a/drivers/net/wan/x25_asy.c
+++ b/drivers/net/wan/x25_asy.c
@@ -17,7 +17,7 @@
#include <linux/module.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/string.h>
#include <linux/mm.h>
@@ -95,7 +95,7 @@
x25_asy_devs[i] = dev;
return sl;
} else {
- printk("x25_asy_alloc() - register_netdev() failure.\n");
+ printk(KERN_WARNING "x25_asy_alloc() - register_netdev() failure.\n");
free_netdev(dev);
}
}
@@ -112,23 +112,22 @@
kfree(sl->xbuff);
sl->xbuff = NULL;
- if (!test_and_clear_bit(SLF_INUSE, &sl->flags)) {
- printk("%s: x25_asy_free for already free unit.\n", sl->dev->name);
- }
+ if (!test_and_clear_bit(SLF_INUSE, &sl->flags))
+ printk(KERN_ERR "%s: x25_asy_free for already free unit.\n",
+ sl->dev->name);
}
static int x25_asy_change_mtu(struct net_device *dev, int newmtu)
{
struct x25_asy *sl = dev->priv;
unsigned char *xbuff, *rbuff;
- int len = 2* newmtu;
+ int len = 2 * newmtu;
xbuff = kmalloc(len + 4, GFP_ATOMIC);
rbuff = kmalloc(len + 4, GFP_ATOMIC);
- if (xbuff == NULL || rbuff == NULL)
- {
- printk("%s: unable to grow X.25 buffers, MTU change cancelled.\n",
+ if (xbuff == NULL || rbuff == NULL) {
+ printk(KERN_WARNING "%s: unable to grow X.25 buffers, MTU change cancelled.\n",
dev->name);
kfree(xbuff);
kfree(rbuff);
@@ -193,25 +192,23 @@
int err;
count = sl->rcount;
- sl->stats.rx_bytes+=count;
-
+ sl->stats.rx_bytes += count;
+
skb = dev_alloc_skb(count+1);
- if (skb == NULL)
- {
- printk("%s: memory squeeze, dropping packet.\n", sl->dev->name);
+ if (skb == NULL) {
+ printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n",
+ sl->dev->name);
sl->stats.rx_dropped++;
return;
}
- skb_push(skb,1); /* LAPB internal control */
- memcpy(skb_put(skb,count), sl->rbuff, count);
+ skb_push(skb, 1); /* LAPB internal control */
+ memcpy(skb_put(skb, count), sl->rbuff, count);
skb->protocol = x25_type_trans(skb, sl->dev);
- if((err=lapb_data_received(skb->dev, skb))!=LAPB_OK)
- {
+ err = lapb_data_received(skb->dev, skb);
+ if (err != LAPB_OK) {
kfree_skb(skb);
- printk(KERN_DEBUG "x25_asy: data received err - %d\n",err);
- }
- else
- {
+ printk(KERN_DEBUG "x25_asy: data received err - %d\n", err);
+ } else {
netif_rx(skb);
sl->dev->last_rx = jiffies;
sl->stats.rx_packets++;
@@ -224,10 +221,11 @@
unsigned char *p;
int actual, count, mtu = sl->dev->mtu;
- if (len > mtu)
- { /* Sigh, shouldn't occur BUT ... */
+ if (len > mtu) {
+ /* Sigh, shouldn't occur BUT ... */
len = mtu;
- printk ("%s: truncating oversized transmit packet!\n", sl->dev->name);
+ printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n",
+ sl->dev->name);
sl->stats.tx_dropped++;
x25_asy_unlock(sl);
return;
@@ -245,7 +243,7 @@
* 14 Oct 1994 Dmitry Gorodchanin.
*/
sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
- actual = sl->tty->driver->write(sl->tty, sl->xbuff, count);
+ actual = sl->tty->ops->write(sl->tty, sl->xbuff, count);
sl->xleft = count - actual;
sl->xhead = sl->xbuff + actual;
/* VSV */
@@ -265,8 +263,7 @@
if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
return;
- if (sl->xleft <= 0)
- {
+ if (sl->xleft <= 0) {
/* Now serial buffer is almost free & we can start
* transmission of another packet */
sl->stats.tx_packets++;
@@ -275,14 +272,14 @@
return;
}
- actual = tty->driver->write(tty, sl->xhead, sl->xleft);
+ actual = tty->ops->write(tty, sl->xhead, sl->xleft);
sl->xleft -= actual;
sl->xhead += actual;
}
static void x25_asy_timeout(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
spin_lock(&sl->lock);
if (netif_queue_stopped(dev)) {
@@ -290,7 +287,7 @@
* 14 Oct 1994 Dmitry Gorodchanin.
*/
printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
- (sl->tty->driver->chars_in_buffer(sl->tty) || sl->xleft) ?
+ (tty_chars_in_buffer(sl->tty) || sl->xleft) ?
"bad line quality" : "driver error");
sl->xleft = 0;
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
@@ -303,31 +300,34 @@
static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
int err;
if (!netif_running(sl->dev)) {
- printk("%s: xmit call when iface is down\n", dev->name);
+ printk(KERN_ERR "%s: xmit call when iface is down\n",
+ dev->name);
kfree_skb(skb);
return 0;
}
-
- switch(skb->data[0])
- {
- case 0x00:break;
- case 0x01: /* Connection request .. do nothing */
- if((err=lapb_connect_request(dev))!=LAPB_OK)
- printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
- kfree_skb(skb);
- return 0;
- case 0x02: /* Disconnect request .. do nothing - hang up ?? */
- if((err=lapb_disconnect_request(dev))!=LAPB_OK)
- printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
- default:
- kfree_skb(skb);
- return 0;
+
+ switch (skb->data[0]) {
+ case 0x00:
+ break;
+ case 0x01: /* Connection request .. do nothing */
+ err = lapb_connect_request(dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy: lapb_connect_request error - %d\n", err);
+ kfree_skb(skb);
+ return 0;
+ case 0x02: /* Disconnect request .. do nothing - hang up ?? */
+ err = lapb_disconnect_request(dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy: lapb_disconnect_request error - %d\n", err);
+ default:
+ kfree_skb(skb);
+ return 0;
}
- skb_pull(skb,1); /* Remove control byte */
+ skb_pull(skb, 1); /* Remove control byte */
/*
* If we are busy already- too bad. We ought to be able
* to queue things at this point, to allow for a little
@@ -338,10 +338,10 @@
* So, no queues !
* 14 Oct 1994 Dmitry Gorodchanin.
*/
-
- if((err=lapb_data_request(dev,skb))!=LAPB_OK)
- {
- printk(KERN_ERR "lapbeth: lapb_data_request error - %d\n", err);
+
+ err = lapb_data_request(dev, skb);
+ if (err != LAPB_OK) {
+ printk(KERN_ERR "x25_asy: lapb_data_request error - %d\n", err);
kfree_skb(skb);
return 0;
}
@@ -357,7 +357,7 @@
* Called when I frame data arrives. We did the work above - throw it
* at the net layer.
*/
-
+
static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb)
{
skb->dev->last_rx = jiffies;
@@ -369,24 +369,22 @@
* busy cases too well. Its tricky to see how to do this nicely -
* perhaps lapb should allow us to bounce this ?
*/
-
+
static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
{
- struct x25_asy *sl=dev->priv;
-
+ struct x25_asy *sl = dev->priv;
+
spin_lock(&sl->lock);
- if (netif_queue_stopped(sl->dev) || sl->tty == NULL)
- {
+ if (netif_queue_stopped(sl->dev) || sl->tty == NULL) {
spin_unlock(&sl->lock);
printk(KERN_ERR "x25_asy: tbusy drop\n");
kfree_skb(skb);
return;
}
/* We were not busy, so we are now... :-) */
- if (skb != NULL)
- {
+ if (skb != NULL) {
x25_asy_lock(sl);
- sl->stats.tx_bytes+=skb->len;
+ sl->stats.tx_bytes += skb->len;
x25_asy_encaps(sl, skb->data, skb->len);
dev_kfree_skb(skb);
}
@@ -396,15 +394,16 @@
/*
* LAPB connection establish/down information.
*/
-
+
static void x25_asy_connected(struct net_device *dev, int reason)
{
struct x25_asy *sl = dev->priv;
struct sk_buff *skb;
unsigned char *ptr;
- if ((skb = dev_alloc_skb(1)) == NULL) {
- printk(KERN_ERR "lapbeth: out of memory\n");
+ skb = dev_alloc_skb(1);
+ if (skb == NULL) {
+ printk(KERN_ERR "x25_asy: out of memory\n");
return;
}
@@ -422,7 +421,8 @@
struct sk_buff *skb;
unsigned char *ptr;
- if ((skb = dev_alloc_skb(1)) == NULL) {
+ skb = dev_alloc_skb(1);
+ if (skb == NULL) {
printk(KERN_ERR "x25_asy: out of memory\n");
return;
}
@@ -449,7 +449,7 @@
/* Open the low-level part of the X.25 channel. Easy! */
static int x25_asy_open(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
unsigned long len;
int err;
@@ -466,13 +466,11 @@
len = dev->mtu * 2;
sl->rbuff = kmalloc(len + 4, GFP_KERNEL);
- if (sl->rbuff == NULL) {
+ if (sl->rbuff == NULL)
goto norbuff;
- }
sl->xbuff = kmalloc(len + 4, GFP_KERNEL);
- if (sl->xbuff == NULL) {
+ if (sl->xbuff == NULL)
goto noxbuff;
- }
sl->buffsize = len;
sl->rcount = 0;
@@ -480,11 +478,12 @@
sl->flags &= (1 << SLF_INUSE); /* Clear ESCAPE & ERROR flags */
netif_start_queue(dev);
-
+
/*
* Now attach LAPB
*/
- if((err=lapb_register(dev, &x25_asy_callbacks))==LAPB_OK)
+ err = lapb_register(dev, &x25_asy_callbacks);
+ if (err == LAPB_OK)
return 0;
/* Cleanup */
@@ -499,18 +498,20 @@
/* Close the low-level part of the X.25 channel. Easy! */
static int x25_asy_close(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
+ struct x25_asy *sl = dev->priv;
int err;
spin_lock(&sl->lock);
- if (sl->tty)
+ if (sl->tty)
sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
netif_stop_queue(dev);
sl->rcount = 0;
sl->xleft = 0;
- if((err=lapb_unregister(dev))!=LAPB_OK)
- printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",err);
+ err = lapb_unregister(dev);
+ if (err != LAPB_OK)
+ printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
+ err);
spin_unlock(&sl->lock);
return 0;
}
@@ -521,8 +522,9 @@
* a block of X.25 data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing.
*/
-
-static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+
+static void x25_asy_receive_buf(struct tty_struct *tty,
+ const unsigned char *cp, char *fp, int count)
{
struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
@@ -533,9 +535,8 @@
/* Read the characters out of the buffer */
while (count--) {
if (fp && *fp++) {
- if (!test_and_set_bit(SLF_ERROR, &sl->flags)) {
+ if (!test_and_set_bit(SLF_ERROR, &sl->flags))
sl->stats.rx_errors++;
- }
cp++;
continue;
}
@@ -556,31 +557,31 @@
struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
int err;
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
/* First make sure we're not already connected. */
- if (sl && sl->magic == X25_ASY_MAGIC) {
+ if (sl && sl->magic == X25_ASY_MAGIC)
return -EEXIST;
- }
/* OK. Find a free X.25 channel to use. */
- if ((sl = x25_asy_alloc()) == NULL) {
+ sl = x25_asy_alloc();
+ if (sl == NULL)
return -ENFILE;
- }
sl->tty = tty;
tty->disc_data = sl;
tty->receive_room = 65536;
- if (tty->driver->flush_buffer) {
- tty->driver->flush_buffer(tty);
- }
+ tty_driver_flush_buffer(tty);
tty_ldisc_flush(tty);
/* Restore default settings */
sl->dev->type = ARPHRD_X25;
-
- /* Perform the low-level X.25 async init */
- if ((err = x25_asy_open(sl->dev)))
- return err;
+ /* Perform the low-level X.25 async init */
+ err = x25_asy_open(sl->dev);
+ if (err)
+ return err;
/* Done. We have linked the TTY line to a channel. */
return sl->dev->base_addr;
}
@@ -601,9 +602,7 @@
return;
if (sl->dev->flags & IFF_UP)
- {
- (void) dev_close(sl->dev);
- }
+ dev_close(sl->dev);
tty->disc_data = NULL;
sl->tty = NULL;
@@ -613,8 +612,7 @@
static struct net_device_stats *x25_asy_get_stats(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
-
+ struct x25_asy *sl = dev->priv;
return &sl->stats;
}
@@ -641,21 +639,19 @@
* character sequence, according to the X.25 protocol.
*/
- while (len-- > 0)
- {
- switch(c = *s++)
- {
- case X25_END:
- *ptr++ = X25_ESC;
- *ptr++ = X25_ESCAPE(X25_END);
- break;
- case X25_ESC:
- *ptr++ = X25_ESC;
- *ptr++ = X25_ESCAPE(X25_ESC);
- break;
- default:
- *ptr++ = c;
- break;
+ while (len-- > 0) {
+ switch (c = *s++) {
+ case X25_END:
+ *ptr++ = X25_ESC;
+ *ptr++ = X25_ESCAPE(X25_END);
+ break;
+ case X25_ESC:
+ *ptr++ = X25_ESC;
+ *ptr++ = X25_ESCAPE(X25_ESC);
+ break;
+ default:
+ *ptr++ = c;
+ break;
}
}
*ptr++ = X25_END;
@@ -665,31 +661,25 @@
static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
{
- switch(s)
- {
- case X25_END:
- if (!test_and_clear_bit(SLF_ERROR, &sl->flags) && (sl->rcount > 2))
- {
- x25_asy_bump(sl);
- }
- clear_bit(SLF_ESCAPE, &sl->flags);
- sl->rcount = 0;
- return;
-
- case X25_ESC:
- set_bit(SLF_ESCAPE, &sl->flags);
- return;
-
- case X25_ESCAPE(X25_ESC):
- case X25_ESCAPE(X25_END):
- if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
- s = X25_UNESCAPE(s);
- break;
+ switch (s) {
+ case X25_END:
+ if (!test_and_clear_bit(SLF_ERROR, &sl->flags)
+ && sl->rcount > 2)
+ x25_asy_bump(sl);
+ clear_bit(SLF_ESCAPE, &sl->flags);
+ sl->rcount = 0;
+ return;
+ case X25_ESC:
+ set_bit(SLF_ESCAPE, &sl->flags);
+ return;
+ case X25_ESCAPE(X25_ESC):
+ case X25_ESCAPE(X25_END):
+ if (test_and_clear_bit(SLF_ESCAPE, &sl->flags))
+ s = X25_UNESCAPE(s);
+ break;
}
- if (!test_bit(SLF_ERROR, &sl->flags))
- {
- if (sl->rcount < sl->buffsize)
- {
+ if (!test_bit(SLF_ERROR, &sl->flags)) {
+ if (sl->rcount < sl->buffsize) {
sl->rbuff[sl->rcount++] = s;
return;
}
@@ -709,7 +699,7 @@
if (!sl || sl->magic != X25_ASY_MAGIC)
return -EINVAL;
- switch(cmd) {
+ switch (cmd) {
case SIOCGIFNAME:
if (copy_to_user((void __user *)arg, sl->dev->name,
strlen(sl->dev->name) + 1))
@@ -724,8 +714,8 @@
static int x25_asy_open_dev(struct net_device *dev)
{
- struct x25_asy *sl = (struct x25_asy*)(dev->priv);
- if(sl->tty==NULL)
+ struct x25_asy *sl = dev->priv;
+ if (sl->tty == NULL)
return -ENODEV;
return 0;
}
@@ -741,9 +731,9 @@
set_bit(SLF_INUSE, &sl->flags);
/*
- * Finish setting up the DEVICE info.
+ * Finish setting up the DEVICE info.
*/
-
+
dev->mtu = SL_MTU;
dev->hard_start_xmit = x25_asy_xmit;
dev->tx_timeout = x25_asy_timeout;
@@ -778,9 +768,10 @@
x25_asy_maxdev = 4; /* Sanity */
printk(KERN_INFO "X.25 async: version 0.00 ALPHA "
- "(dynamic channels, max=%d).\n", x25_asy_maxdev );
+ "(dynamic channels, max=%d).\n", x25_asy_maxdev);
- x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device*), GFP_KERNEL);
+ x25_asy_devs = kcalloc(x25_asy_maxdev, sizeof(struct net_device *),
+ GFP_KERNEL);
if (!x25_asy_devs) {
printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] "
"array! Uaargh! (-> No X.25 available)\n");
@@ -802,7 +793,7 @@
struct x25_asy *sl = dev->priv;
spin_lock_bh(&sl->lock);
- if (sl->tty)
+ if (sl->tty)
tty_hangup(sl->tty);
spin_unlock_bh(&sl->lock);
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 932d6b1..45f47c1 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -3657,7 +3657,7 @@
ptr += hdrlen;
if (hdrlen == 24)
ptr += 6;
- gap = le16_to_cpu(get_unaligned((__le16 *)ptr));
+ gap = get_unaligned_le16(ptr);
ptr += sizeof(__le16);
if (gap) {
if (gap <= 8)
@@ -4347,24 +4347,28 @@
static int proc_wepkey_open( struct inode *inode, struct file *file );
static const struct file_operations proc_statsdelta_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.open = proc_statsdelta_open,
.release = proc_close
};
static const struct file_operations proc_stats_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.open = proc_stats_open,
.release = proc_close
};
static const struct file_operations proc_status_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.open = proc_status_open,
.release = proc_close
};
static const struct file_operations proc_SSID_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_SSID_open,
@@ -4372,6 +4376,7 @@
};
static const struct file_operations proc_BSSList_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_BSSList_open,
@@ -4379,6 +4384,7 @@
};
static const struct file_operations proc_APList_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_APList_open,
@@ -4386,6 +4392,7 @@
};
static const struct file_operations proc_config_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_config_open,
@@ -4393,6 +4400,7 @@
};
static const struct file_operations proc_wepkey_ops = {
+ .owner = THIS_MODULE,
.read = proc_read,
.write = proc_write,
.open = proc_wepkey_open,
@@ -4411,10 +4419,6 @@
void (*on_close) (struct inode *, struct file *);
};
-#ifndef SETPROC_OPS
-#define SETPROC_OPS(entry, ops) (entry)->proc_fops = &(ops)
-#endif
-
static int setup_proc_entry( struct net_device *dev,
struct airo_info *apriv ) {
struct proc_dir_entry *entry;
@@ -4430,100 +4434,76 @@
apriv->proc_entry->owner = THIS_MODULE;
/* Setup the StatsDelta */
- entry = create_proc_entry("StatsDelta",
- S_IFREG | (S_IRUGO&proc_perm),
- apriv->proc_entry);
+ entry = proc_create_data("StatsDelta",
+ S_IFREG | (S_IRUGO&proc_perm),
+ apriv->proc_entry, &proc_statsdelta_ops, dev);
if (!entry)
goto fail_stats_delta;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_statsdelta_ops);
/* Setup the Stats */
- entry = create_proc_entry("Stats",
- S_IFREG | (S_IRUGO&proc_perm),
- apriv->proc_entry);
+ entry = proc_create_data("Stats",
+ S_IFREG | (S_IRUGO&proc_perm),
+ apriv->proc_entry, &proc_stats_ops, dev);
if (!entry)
goto fail_stats;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_stats_ops);
/* Setup the Status */
- entry = create_proc_entry("Status",
- S_IFREG | (S_IRUGO&proc_perm),
- apriv->proc_entry);
+ entry = proc_create_data("Status",
+ S_IFREG | (S_IRUGO&proc_perm),
+ apriv->proc_entry, &proc_status_ops, dev);
if (!entry)
goto fail_status;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_status_ops);
/* Setup the Config */
- entry = create_proc_entry("Config",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("Config",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_config_ops, dev);
if (!entry)
goto fail_config;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_config_ops);
/* Setup the SSID */
- entry = create_proc_entry("SSID",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("SSID",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_SSID_ops, dev);
if (!entry)
goto fail_ssid;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_SSID_ops);
/* Setup the APList */
- entry = create_proc_entry("APList",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("APList",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_APList_ops, dev);
if (!entry)
goto fail_aplist;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_APList_ops);
/* Setup the BSSList */
- entry = create_proc_entry("BSSList",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("BSSList",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_BSSList_ops, dev);
if (!entry)
goto fail_bsslist;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_BSSList_ops);
/* Setup the WepKey */
- entry = create_proc_entry("WepKey",
- S_IFREG | proc_perm,
- apriv->proc_entry);
+ entry = proc_create_data("WepKey",
+ S_IFREG | proc_perm,
+ apriv->proc_entry, &proc_wepkey_ops, dev);
if (!entry)
goto fail_wepkey;
entry->uid = proc_uid;
entry->gid = proc_gid;
- entry->data = dev;
- entry->owner = THIS_MODULE;
- SETPROC_OPS(entry, proc_wepkey_ops);
return 0;
@@ -5625,9 +5605,9 @@
int have_isa_dev = 0;
#endif
- airo_entry = create_proc_entry("aironet",
+ airo_entry = create_proc_entry("driver/aironet",
S_IFDIR | airo_perm,
- proc_root_driver);
+ NULL);
if (airo_entry) {
airo_entry->uid = proc_uid;
@@ -5651,7 +5631,7 @@
airo_print_info("", "Finished probing for PCI adapters");
if (i) {
- remove_proc_entry("aironet", proc_root_driver);
+ remove_proc_entry("driver/aironet", NULL);
return i;
}
#endif
@@ -5673,7 +5653,7 @@
#ifdef CONFIG_PCI
pci_unregister_driver(&airo_driver);
#endif
- remove_proc_entry("aironet", proc_root_driver);
+ remove_proc_entry("driver/aironet", NULL);
}
/*
diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c
index e18305b..4e5c8fc 100644
--- a/drivers/net/wireless/ath5k/base.c
+++ b/drivers/net/wireless/ath5k/base.c
@@ -58,10 +58,6 @@
#include "reg.h"
#include "debug.h"
-/* unaligned little endian access */
-#define LE_READ_2(_p) (le16_to_cpu(get_unaligned((__le16 *)(_p))))
-#define LE_READ_4(_p) (le32_to_cpu(get_unaligned((__le32 *)(_p))))
-
enum {
ATH_LED_TX,
ATH_LED_RX,
@@ -2909,9 +2905,9 @@
if (!mclist)
break;
/* calculate XOR of eight 6-bit values */
- val = LE_READ_4(mclist->dmi_addr + 0);
+ val = get_unaligned_le32(mclist->dmi_addr + 0);
pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
- val = LE_READ_4(mclist->dmi_addr + 3);
+ val = get_unaligned_le32(mclist->dmi_addr + 3);
pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
pos &= 0x3f;
mfilt[pos / 32] |= (1 << (pos % 32));
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 4bf8a99..8c24cd7 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2171,7 +2171,7 @@
goto err_format;
array_size -= sizeof(iv->data.d32);
- value = be32_to_cpu(get_unaligned(&iv->data.d32));
+ value = get_unaligned_be32(&iv->data.d32);
b43_write32(dev, offset, value);
iv = (const struct b43_iv *)((const uint8_t *)iv +
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index ef829ee..14a5eea 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -1720,7 +1720,7 @@
goto err_format;
array_size -= sizeof(iv->data.d32);
- value = be32_to_cpu(get_unaligned(&iv->data.d32));
+ value = get_unaligned_be32(&iv->data.d32);
b43legacy_write32(dev, offset, value);
iv = (const struct b43legacy_iv *)((const uint8_t *)iv +
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 9a25f55..d5b7a76 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -6,6 +6,10 @@
tristate "Intel Wireless Wifi Core"
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select IWLWIFI
+ select MAC80211_LEDS if IWLWIFI_LEDS
+ select LEDS_CLASS if IWLWIFI_LEDS
+ select RFKILL if IWLWIFI_RFKILL
+ select RFKILL_INPUT if IWLWIFI_RFKILL
config IWLWIFI_LEDS
bool
@@ -14,8 +18,6 @@
config IWLWIFI_RFKILL
boolean "IWLWIFI RF kill support"
depends on IWLCORE
- select RFKILL
- select RFKILL_INPUT
config IWL4965
tristate "Intel Wireless WiFi 4965AGN"
@@ -55,8 +57,6 @@
config IWL4965_LEDS
bool "Enable LEDS features in iwl4965 driver"
depends on IWL4965
- select MAC80211_LEDS
- select LEDS_CLASS
select IWLWIFI_LEDS
---help---
This option enables LEDS for the iwlwifi drivers
@@ -112,6 +112,8 @@
depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
select FW_LOADER
select IWLWIFI
+ select MAC80211_LEDS if IWL3945_LEDS
+ select LEDS_CLASS if IWL3945_LEDS
---help---
Select to build the driver supporting the:
@@ -143,8 +145,6 @@
config IWL3945_LEDS
bool "Enable LEDS features in iwl3945 driver"
depends on IWL3945
- select MAC80211_LEDS
- select LEDS_CLASS
---help---
This option enables LEDS for the iwl3945 driver.
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index 598e4ee..d340683 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -554,40 +554,36 @@
iwl3945_rt->rt_hdr.it_pad = 0;
/* total header + data */
- put_unaligned(cpu_to_le16(sizeof(*iwl3945_rt)),
- &iwl3945_rt->rt_hdr.it_len);
+ put_unaligned_le16(sizeof(*iwl3945_rt), &iwl3945_rt->rt_hdr.it_len);
/* Indicate all the fields we add to the radiotap header */
- put_unaligned(cpu_to_le32((1 << IEEE80211_RADIOTAP_TSFT) |
- (1 << IEEE80211_RADIOTAP_FLAGS) |
- (1 << IEEE80211_RADIOTAP_RATE) |
- (1 << IEEE80211_RADIOTAP_CHANNEL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
- (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
- (1 << IEEE80211_RADIOTAP_ANTENNA)),
- &iwl3945_rt->rt_hdr.it_present);
+ put_unaligned_le32((1 << IEEE80211_RADIOTAP_TSFT) |
+ (1 << IEEE80211_RADIOTAP_FLAGS) |
+ (1 << IEEE80211_RADIOTAP_RATE) |
+ (1 << IEEE80211_RADIOTAP_CHANNEL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL) |
+ (1 << IEEE80211_RADIOTAP_DBM_ANTNOISE) |
+ (1 << IEEE80211_RADIOTAP_ANTENNA),
+ &iwl3945_rt->rt_hdr.it_present);
/* Zero the flags, we'll add to them as we go */
iwl3945_rt->rt_flags = 0;
- put_unaligned(cpu_to_le64(tsf), &iwl3945_rt->rt_tsf);
+ put_unaligned_le64(tsf, &iwl3945_rt->rt_tsf);
iwl3945_rt->rt_dbmsignal = signal;
iwl3945_rt->rt_dbmnoise = noise;
/* Convert the channel frequency and set the flags */
- put_unaligned(cpu_to_le16(stats->freq), &iwl3945_rt->rt_channelMHz);
+ put_unaligned_le16(stats->freq, &iwl3945_rt->rt_channelMHz);
if (!(phy_flags_hw & RX_RES_PHY_FLAGS_BAND_24_MSK))
- put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_5GHZ),
+ put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
&iwl3945_rt->rt_chbitmask);
else if (phy_flags_hw & RX_RES_PHY_FLAGS_MOD_CCK_MSK)
- put_unaligned(cpu_to_le16(IEEE80211_CHAN_CCK |
- IEEE80211_CHAN_2GHZ),
+ put_unaligned_le16(IEEE80211_CHAN_CCK | IEEE80211_CHAN_2GHZ,
&iwl3945_rt->rt_chbitmask);
else /* 802.11g */
- put_unaligned(cpu_to_le16(IEEE80211_CHAN_OFDM |
- IEEE80211_CHAN_2GHZ),
+ put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_2GHZ,
&iwl3945_rt->rt_chbitmask);
if (rate == -1)
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c
index e72c97a..1a409fc 100644
--- a/drivers/net/wireless/libertas/scan.c
+++ b/drivers/net/wireless/libertas/scan.c
@@ -522,7 +522,7 @@
if (*bytesleft >= sizeof(beaconsize)) {
/* Extract & convert beacon size from the command buffer */
- beaconsize = le16_to_cpu(get_unaligned((__le16 *)*pbeaconinfo));
+ beaconsize = get_unaligned_le16(*pbeaconinfo);
*bytesleft -= sizeof(beaconsize);
*pbeaconinfo += sizeof(beaconsize);
}
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index bced3fe..5dd23c9 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -768,41 +768,17 @@
/* General routines for STRIP */
/*
- * get_baud returns the current baud rate, as one of the constants defined in
- * termbits.h
- * If the user has issued a baud rate override using the 'setserial' command
- * and the logical current rate is set to 38.4, then the true baud rate
- * currently in effect (57.6 or 115.2) is returned.
- */
-static unsigned int get_baud(struct tty_struct *tty)
-{
- if (!tty || !tty->termios)
- return (0);
- if ((tty->termios->c_cflag & CBAUD) == B38400 && tty->driver_data) {
- struct async_struct *info =
- (struct async_struct *) tty->driver_data;
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- return (B57600);
- if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- return (B115200);
- }
- return (tty->termios->c_cflag & CBAUD);
-}
-
-/*
* set_baud sets the baud rate to the rate defined by baudcode
- * Note: The rate B38400 should be avoided, because the user may have
- * issued a 'setserial' speed override to map that to a different speed.
- * We could achieve a true rate of 38400 if we needed to by cancelling
- * any user speed override that is in place, but that might annoy the
- * user, so it is simplest to just avoid using 38400.
*/
-static void set_baud(struct tty_struct *tty, unsigned int baudcode)
+static void set_baud(struct tty_struct *tty, speed_t baudrate)
{
- struct ktermios old_termios = *(tty->termios);
- tty->termios->c_cflag &= ~CBAUD; /* Clear the old baud setting */
- tty->termios->c_cflag |= baudcode; /* Set the new baud setting */
- tty->driver->set_termios(tty, &old_termios);
+ struct ktermios old_termios;
+
+ mutex_lock(&tty->termios_mutex);
+ old_termios =*(tty->termios);
+ tty_encode_baud_rate(tty, baudrate, baudrate);
+ tty->ops->set_termios(tty, &old_termios);
+ mutex_unlock(&tty->termios_mutex);
}
/*
@@ -1217,7 +1193,7 @@
strip_info->watchdog_doreset = jiffies + 1 * HZ;
/* If the user has selected a baud rate above 38.4 see what magic we have to do */
- if (strip_info->user_baud > B38400) {
+ if (strip_info->user_baud > 38400) {
/*
* Subtle stuff: Pay attention :-)
* If the serial port is currently at the user's selected (>38.4) rate,
@@ -1227,17 +1203,17 @@
* issued the ATS304 command last time through, so this time we restore
* the user's selected rate and issue the normal starmode reset string.
*/
- if (strip_info->user_baud == get_baud(tty)) {
+ if (strip_info->user_baud == tty_get_baud_rate(tty)) {
static const char b0[] = "ate0q1s304=57600\r";
static const char b1[] = "ate0q1s304=115200\r";
static const StringDescriptor baudstring[2] =
{ {b0, sizeof(b0) - 1}
, {b1, sizeof(b1) - 1}
};
- set_baud(tty, B19200);
- if (strip_info->user_baud == B57600)
+ set_baud(tty, 19200);
+ if (strip_info->user_baud == 57600)
s = baudstring[0];
- else if (strip_info->user_baud == B115200)
+ else if (strip_info->user_baud == 115200)
s = baudstring[1];
else
s = baudstring[1]; /* For now */
@@ -1245,7 +1221,7 @@
set_baud(tty, strip_info->user_baud);
}
- tty->driver->write(tty, s.string, s.length);
+ tty->ops->write(tty, s.string, s.length);
#ifdef EXT_COUNTERS
strip_info->tx_ebytes += s.length;
#endif
@@ -1267,7 +1243,7 @@
if (strip_info->tx_left > 0) {
int num_written =
- tty->driver->write(tty, strip_info->tx_head,
+ tty->ops->write(tty, strip_info->tx_head,
strip_info->tx_left);
strip_info->tx_left -= num_written;
strip_info->tx_head += num_written;
@@ -2457,7 +2433,7 @@
strip_info->working = FALSE;
strip_info->firmware_level = NoStructure;
strip_info->next_command = CompatibilityCommand;
- strip_info->user_baud = get_baud(strip_info->tty);
+ strip_info->user_baud = tty_get_baud_rate(strip_info->tty);
printk(KERN_INFO "%s: Initializing Radio.\n",
strip_info->dev->name);
@@ -2632,6 +2608,13 @@
return -EEXIST;
/*
+ * We need a write method.
+ */
+
+ if (tty->ops->write == NULL)
+ return -EOPNOTSUPP;
+
+ /*
* OK. Find a free STRIP channel to use.
*/
if ((strip_info = strip_alloc()) == NULL)
@@ -2652,8 +2635,7 @@
tty->disc_data = strip_info;
tty->receive_room = 65536;
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
/*
* Restore default settings
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index e34675c..5316074 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -545,11 +545,11 @@
* be padded. Unaligned access might also happen if the length_info
* structure is not present.
*/
- if (get_unaligned(&length_info->tag) == cpu_to_le16(RX_LENGTH_INFO_TAG))
+ if (get_unaligned_le16(&length_info->tag) == RX_LENGTH_INFO_TAG)
{
unsigned int l, k, n;
for (i = 0, l = 0;; i++) {
- k = le16_to_cpu(get_unaligned(&length_info->length[i]));
+ k = get_unaligned_le16(&length_info->length[i]);
if (k == 0)
return;
n = l+k;
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 2464072..57e1f49 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -1062,7 +1062,7 @@
buf_addr = rx_skb->data;
data_size = (le32_to_cpu(desc->dbdma_cmd) -
le32_to_cpu(desc->result_status)) & 0xffff;
- frame_status = le16_to_cpu(get_unaligned((__le16*)&(buf_addr[data_size - 2])));
+ frame_status = get_unaligned_le16(&(buf_addr[data_size - 2]));
if (yellowfin_debug > 4)
printk(KERN_DEBUG " yellowfin_rx() status was %4.4x.\n",
frame_status);
diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c
index e07492b..208dd12 100644
--- a/drivers/nubus/proc.c
+++ b/drivers/nubus/proc.c
@@ -21,6 +21,7 @@
#include <linux/kernel.h>
#include <linux/nubus.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/module.h>
@@ -28,38 +29,36 @@
#include <asm/byteorder.h>
static int
-get_nubus_dev_info(char *buf, char **start, off_t pos, int count)
+nubus_devices_proc_show(struct seq_file *m, void *v)
{
struct nubus_dev *dev = nubus_devices;
- off_t at = 0;
- int len, cnt;
- cnt = 0;
- while (dev && count > cnt) {
- len = sprintf(buf, "%x\t%04x %04x %04x %04x",
+ while (dev) {
+ seq_printf(m, "%x\t%04x %04x %04x %04x",
dev->board->slot,
dev->category,
dev->type,
dev->dr_sw,
dev->dr_hw);
- len += sprintf(buf+len,
- "\t%08lx",
- dev->board->slot_addr);
- buf[len++] = '\n';
- at += len;
- if (at >= pos) {
- if (!*start) {
- *start = buf + (pos - (at - len));
- cnt = at - pos;
- } else
- cnt += len;
- buf += len;
- }
+ seq_printf(m, "\t%08lx\n", dev->board->slot_addr);
dev = dev->next;
}
- return (count > cnt) ? cnt : count;
+ return 0;
}
+static int nubus_devices_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, nubus_devices_proc_show, NULL);
+}
+
+static const struct file_operations nubus_devices_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = nubus_devices_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
static struct proc_dir_entry *proc_bus_nubus_dir;
static void nubus_proc_subdir(struct nubus_dev* dev,
@@ -171,8 +170,7 @@
{
if (!MACH_IS_MAC)
return;
- proc_bus_nubus_dir = proc_mkdir("nubus", proc_bus);
- create_proc_info_entry("devices", 0, proc_bus_nubus_dir,
- get_nubus_dev_info);
+ proc_bus_nubus_dir = proc_mkdir("bus/nubus", NULL);
+ proc_create("devices", 0, proc_bus_nubus_dir, &nubus_devices_proc_fops);
proc_bus_nubus_add_devices();
}
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 62db3c3..07d2a8d 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -1551,8 +1551,7 @@
{
int i;
struct ioc *ioc, **ioc_p = &ioc_list;
- struct proc_dir_entry *info_entry, *bitmap_entry;
-
+
ioc = kzalloc(sizeof(struct ioc), GFP_KERNEL);
if (ioc == NULL) {
printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
@@ -1580,13 +1579,10 @@
HBA_DATA(dev->dev.platform_data)->iommu = ioc;
if (ioc_count == 0) {
- info_entry = create_proc_entry(MODULE_NAME, 0, proc_runway_root);
- if (info_entry)
- info_entry->proc_fops = &ccio_proc_info_fops;
-
- bitmap_entry = create_proc_entry(MODULE_NAME"-bitmap", 0, proc_runway_root);
- if (bitmap_entry)
- bitmap_entry->proc_fops = &ccio_proc_bitmap_fops;
+ proc_create(MODULE_NAME, 0, proc_runway_root,
+ &ccio_proc_info_fops);
+ proc_create(MODULE_NAME"-bitmap", 0, proc_runway_root,
+ &ccio_proc_bitmap_fops);
}
ioc_count++;
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 8c4d2c1..afc849b 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -1895,7 +1895,9 @@
int i;
char *version;
void __iomem *sba_addr = ioremap_nocache(dev->hpa.start, SBA_FUNC_SIZE);
- struct proc_dir_entry *info_entry, *bitmap_entry, *root;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *root;
+#endif
sba_dump_ranges(sba_addr);
@@ -1973,14 +1975,8 @@
break;
}
- info_entry = create_proc_entry("sba_iommu", 0, root);
- bitmap_entry = create_proc_entry("sba_iommu-bitmap", 0, root);
-
- if (info_entry)
- info_entry->proc_fops = &sba_proc_fops;
-
- if (bitmap_entry)
- bitmap_entry->proc_fops = &sba_proc_bitmap_fops;
+ proc_create("sba_iommu", 0, root, &sba_proc_fops);
+ proc_create("sba_iommu-bitmap", 0, root, &sba_proc_bitmap_fops);
#endif
parisc_vmerge_boundary = IOVP_SIZE;
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 54a6ef7..0338b09 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -76,7 +76,7 @@
semaphore. */
return 1;
- init_timer (&timer);
+ init_timer_on_stack(&timer);
timer.expires = jiffies + timeout;
timer.function = timeout_waiting_on_port;
port_from_cookie[port->number % PARPORT_MAX] = port;
@@ -88,6 +88,8 @@
/* Timed out. */
ret = 1;
+ destroy_timer_on_stack(&timer);
+
return ret;
}
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 0e77ae2..e6a7e84 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -365,11 +365,11 @@
if (boot_cpu_data.cpu_type > pcxt && !pdc_add_valid(port+4)) {
/* Initialize bidirectional-mode (0x10) & data-tranfer-mode #1 (0x20) */
- printk("%s: initialize bidirectional-mode.\n", __FUNCTION__);
+ printk("%s: initialize bidirectional-mode.\n", __func__);
parport_writeb ( (0x10 + 0x20), port + 4);
} else {
- printk("%s: enhanced parport-modes not supported.\n", __FUNCTION__);
+ printk("%s: enhanced parport-modes not supported.\n", __func__);
}
p = parport_gsc_probe_port(port, 0, dev->irq,
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index a858089..e0c2a45 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -1415,7 +1415,7 @@
{
int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
- if (!request_region(io, 3, __FUNCTION__))
+ if (!request_region(io, 3, __func__))
return;
/* First probe without key */
@@ -1449,7 +1449,7 @@
{
int devid,devrev,oldid,x_devid,x_devrev,x_oldid;
- if (!request_region(io, 3, __FUNCTION__))
+ if (!request_region(io, 3, __func__))
return;
/* First probe without the key */
@@ -1482,7 +1482,7 @@
{
int id,rev,oldid,oldrev,x_id,x_rev,x_oldid,x_oldrev;
- if (!request_region(io, 3, __FUNCTION__))
+ if (!request_region(io, 3, __func__))
return;
/* First probe without the key */
@@ -1547,7 +1547,7 @@
u8 r;
if (verbose_probing)
printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n");
- if (!request_region(0x2e, 1, __FUNCTION__))
+ if (!request_region(0x2e, 1, __func__))
return;
outb(0x87, 0x2e);
outb(0x01, 0x2e);
@@ -3082,6 +3082,7 @@
static int __init parport_pc_init_superio(int autoirq, int autodma) {return 0;}
#endif /* CONFIG_PCI */
+#ifdef CONFIG_PNP
static const struct pnp_device_id parport_pc_pnp_tbl[] = {
/* Standard LPT Printer Port */
@@ -3148,6 +3149,9 @@
.remove = parport_pc_pnp_remove,
};
+#else
+static struct pnp_driver parport_pc_pnp_driver;
+#endif /* CONFIG_PNP */
static int __devinit parport_pc_platform_probe(struct platform_device *pdev)
{
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index f14267e1..8264a76 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -93,11 +93,10 @@
u8 slot_device_offset;
u32 first_slot; /* First physical slot number */ /* PCIE only has 1 slot */
u8 slot_bus; /* Bus where the slots handled by this controller sit */
- u8 ctrlcap;
+ u32 slot_cap;
u8 cap_base;
struct timer_list poll_timer;
volatile int cmd_busy;
- spinlock_t lock;
};
#define INT_BUTTON_IGNORE 0
@@ -137,13 +136,13 @@
#define HP_SUPR_RM_SUP 0x00000020
#define EMI_PRSN 0x00020000
-#define ATTN_BUTTN(cap) (cap & ATTN_BUTTN_PRSN)
-#define POWER_CTRL(cap) (cap & PWR_CTRL_PRSN)
-#define MRL_SENS(cap) (cap & MRL_SENS_PRSN)
-#define ATTN_LED(cap) (cap & ATTN_LED_PRSN)
-#define PWR_LED(cap) (cap & PWR_LED_PRSN)
-#define HP_SUPR_RM(cap) (cap & HP_SUPR_RM_SUP)
-#define EMI(cap) (cap & EMI_PRSN)
+#define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN)
+#define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN)
+#define MRL_SENS(ctrl) ((ctrl)->slot_cap & MRL_SENS_PRSN)
+#define ATTN_LED(ctrl) ((ctrl)->slot_cap & ATTN_LED_PRSN)
+#define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN)
+#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP)
+#define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN)
extern int pciehp_sysfs_enable_slot(struct slot *slot);
extern int pciehp_sysfs_disable_slot(struct slot *slot);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index aee19f0..43d8ddb 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -41,6 +41,7 @@
int pciehp_poll_mode;
int pciehp_poll_time;
int pciehp_force;
+int pciehp_slot_with_bus;
struct workqueue_struct *pciehp_wq;
#define DRIVER_VERSION "0.4"
@@ -55,10 +56,12 @@
module_param(pciehp_poll_mode, bool, 0644);
module_param(pciehp_poll_time, int, 0644);
module_param(pciehp_force, bool, 0644);
+module_param(pciehp_slot_with_bus, bool, 0644);
MODULE_PARM_DESC(pciehp_debug, "Debugging mode enabled or not");
MODULE_PARM_DESC(pciehp_poll_mode, "Using polling mechanism for hot-plug events or not");
MODULE_PARM_DESC(pciehp_poll_time, "Polling mechanism frequency, in seconds");
MODULE_PARM_DESC(pciehp_force, "Force pciehp, even if _OSC and OSHP are missing");
+MODULE_PARM_DESC(pciehp_slot_with_bus, "Use bus number in the slot name");
#define PCIE_MODULE_NAME "pciehp"
@@ -193,8 +196,12 @@
static void make_slot_name(struct slot *slot)
{
- snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
- slot->bus, slot->number);
+ if (pciehp_slot_with_bus)
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+ slot->bus, slot->number);
+ else
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d",
+ slot->number);
}
static int init_slots(struct controller *ctrl)
@@ -251,7 +258,7 @@
goto error_info;
}
/* create additional sysfs entries */
- if (EMI(ctrl->ctrlcap)) {
+ if (EMI(ctrl)) {
retval = sysfs_create_file(&hotplug_slot->kobj,
&hotplug_slot_attr_lock.attr);
if (retval) {
@@ -284,7 +291,7 @@
list_for_each_safe(tmp, next, &ctrl->slot_list) {
slot = list_entry(tmp, struct slot, slot_list);
list_del(&slot->slot_list);
- if (EMI(ctrl->ctrlcap))
+ if (EMI(ctrl))
sysfs_remove_file(&slot->hotplug_slot->kobj,
&hotplug_slot_attr_lock.attr);
cancel_delayed_work(&slot->work);
@@ -305,7 +312,7 @@
hotplug_slot->info->attention_status = status;
- if (ATTN_LED(slot->ctrl->ctrlcap))
+ if (ATTN_LED(slot->ctrl))
slot->hpc_ops->set_attention_status(slot, status);
return 0;
@@ -472,7 +479,7 @@
if (rc) /* -ENODEV: shouldn't happen, but deal with it */
value = 0;
}
- if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
+ if ((POWER_CTRL(ctrl)) && !value) {
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
if (rc)
goto err_out_free_ctrl_slot;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 0c481f7..0a7aa62 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -178,7 +178,7 @@
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
- if (POWER_CTRL(ctrl->ctrlcap)) {
+ if (POWER_CTRL(ctrl)) {
if (pslot->hpc_ops->power_off_slot(pslot)) {
err("%s: Issue of Slot Power Off command failed\n",
__func__);
@@ -186,10 +186,10 @@
}
}
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
pslot->hpc_ops->green_led_off(pslot);
- if (ATTN_LED(ctrl->ctrlcap)) {
+ if (ATTN_LED(ctrl)) {
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
err("%s: Issue of Set Attention Led command failed\n",
__func__);
@@ -214,14 +214,14 @@
__func__, p_slot->device,
ctrl->slot_device_offset, p_slot->hp_slot);
- if (POWER_CTRL(ctrl->ctrlcap)) {
+ if (POWER_CTRL(ctrl)) {
/* Power on slot */
retval = p_slot->hpc_ops->power_on_slot(p_slot);
if (retval)
return retval;
}
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_blink(p_slot);
/* Wait for ~1 second */
@@ -254,7 +254,7 @@
*/
if (pcie_mch_quirk)
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_on(p_slot);
return 0;
@@ -279,7 +279,7 @@
dbg("In %s, hp_slot = %d\n", __func__, p_slot->hp_slot);
- if (POWER_CTRL(ctrl->ctrlcap)) {
+ if (POWER_CTRL(ctrl)) {
/* power off slot */
retval = p_slot->hpc_ops->power_off_slot(p_slot);
if (retval) {
@@ -289,7 +289,7 @@
}
}
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
/* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot);
@@ -327,7 +327,7 @@
case POWERON_STATE:
mutex_unlock(&p_slot->lock);
if (pciehp_enable_slot(p_slot) &&
- PWR_LED(p_slot->ctrl->ctrlcap))
+ PWR_LED(p_slot->ctrl))
p_slot->hpc_ops->green_led_off(p_slot);
mutex_lock(&p_slot->lock);
p_slot->state = STATIC_STATE;
@@ -409,9 +409,9 @@
"press.\n", p_slot->name);
}
/* blink green LED and turn off amber */
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_blink(p_slot);
- if (ATTN_LED(ctrl->ctrlcap))
+ if (ATTN_LED(ctrl))
p_slot->hpc_ops->set_attention_status(p_slot, 0);
schedule_delayed_work(&p_slot->work, 5*HZ);
@@ -427,13 +427,13 @@
dbg("%s: button cancel\n", __func__);
cancel_delayed_work(&p_slot->work);
if (p_slot->state == BLINKINGOFF_STATE) {
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_on(p_slot);
} else {
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_off(p_slot);
}
- if (ATTN_LED(ctrl->ctrlcap))
+ if (ATTN_LED(ctrl))
p_slot->hpc_ops->set_attention_status(p_slot, 0);
info("PCI slot #%s - action canceled due to button press\n",
p_slot->name);
@@ -492,16 +492,16 @@
handle_button_press_event(p_slot);
break;
case INT_POWER_FAULT:
- if (!POWER_CTRL(ctrl->ctrlcap))
+ if (!POWER_CTRL(ctrl))
break;
- if (ATTN_LED(ctrl->ctrlcap))
+ if (ATTN_LED(ctrl))
p_slot->hpc_ops->set_attention_status(p_slot, 1);
- if (PWR_LED(ctrl->ctrlcap))
+ if (PWR_LED(ctrl))
p_slot->hpc_ops->green_led_off(p_slot);
break;
case INT_PRESENCE_ON:
case INT_PRESENCE_OFF:
- if (!HP_SUPR_RM(ctrl->ctrlcap))
+ if (!HP_SUPR_RM(ctrl))
break;
dbg("Surprise Removal\n");
update_slot_info(p_slot);
@@ -531,7 +531,7 @@
mutex_unlock(&p_slot->ctrl->crit_sect);
return -ENODEV;
}
- if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ if (MRL_SENS(p_slot->ctrl)) {
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: latch open on slot(%s)\n", __func__,
@@ -541,7 +541,7 @@
}
}
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+ if (POWER_CTRL(p_slot->ctrl)) {
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
info("%s: already enabled on slot(%s)\n", __func__,
@@ -576,7 +576,7 @@
/* Check to see if (latch closed, card present, power on) */
mutex_lock(&p_slot->ctrl->crit_sect);
- if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
+ if (!HP_SUPR_RM(p_slot->ctrl)) {
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: no adapter on slot(%s)\n", __func__,
@@ -586,7 +586,7 @@
}
}
- if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
+ if (MRL_SENS(p_slot->ctrl)) {
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
info("%s: latch open on slot(%s)\n", __func__,
@@ -596,7 +596,7 @@
}
}
- if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
+ if (POWER_CTRL(p_slot->ctrl)) {
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
info("%s: already disabled slot(%s)\n", __func__,
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index b4bbd07..891f81a 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -221,6 +221,32 @@
add_timer(&ctrl->poll_timer);
}
+static inline int pciehp_request_irq(struct controller *ctrl)
+{
+ int retval, irq = ctrl->pci_dev->irq;
+
+ /* Install interrupt polling timer. Start with 10 sec delay */
+ if (pciehp_poll_mode) {
+ init_timer(&ctrl->poll_timer);
+ start_int_poll_timer(ctrl, 10);
+ return 0;
+ }
+
+ /* Installs the interrupt handler */
+ retval = request_irq(irq, pcie_isr, IRQF_SHARED, MY_NAME, ctrl);
+ if (retval)
+ err("Cannot get irq %d for the hotplug controller\n", irq);
+ return retval;
+}
+
+static inline void pciehp_free_irq(struct controller *ctrl)
+{
+ if (pciehp_poll_mode)
+ del_timer_sync(&ctrl->poll_timer);
+ else
+ free_irq(ctrl->pci_dev->irq, ctrl);
+}
+
static inline int pcie_wait_cmd(struct controller *ctrl)
{
int retval = 0;
@@ -242,17 +268,15 @@
/**
* pcie_write_cmd - Issue controller command
- * @slot: slot to which the command is issued
+ * @ctrl: controller to which the command is issued
* @cmd: command value written to slot control register
* @mask: bitmask of slot control register to be modified
*/
-static int pcie_write_cmd(struct slot *slot, u16 cmd, u16 mask)
+static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
{
- struct controller *ctrl = slot->ctrl;
int retval = 0;
u16 slot_status;
u16 slot_ctrl;
- unsigned long flags;
mutex_lock(&ctrl->ctrl_lock);
@@ -270,24 +294,24 @@
__func__);
}
- spin_lock_irqsave(&ctrl->lock, flags);
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
if (retval) {
err("%s: Cannot read SLOTCTRL register\n", __func__);
- goto out_spin_unlock;
+ goto out;
}
slot_ctrl &= ~mask;
- slot_ctrl |= ((cmd & mask) | CMD_CMPL_INTR_ENABLE);
+ slot_ctrl |= (cmd & mask);
+ /* Don't enable command completed if caller is changing it. */
+ if (!(mask & CMD_CMPL_INTR_ENABLE))
+ slot_ctrl |= CMD_CMPL_INTR_ENABLE;
ctrl->cmd_busy = 1;
+ smp_mb();
retval = pciehp_writew(ctrl, SLOTCTRL, slot_ctrl);
if (retval)
err("%s: Cannot write to SLOTCTRL register\n", __func__);
- out_spin_unlock:
- spin_unlock_irqrestore(&ctrl->lock, flags);
-
/*
* Wait for command completion.
*/
@@ -467,12 +491,7 @@
slot_cmd = EMI_CTRL;
cmd_mask = EMI_CTRL;
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ rc = pcie_write_cmd(slot->ctrl, slot_cmd, cmd_mask);
slot->last_emi_toggle = get_seconds();
return rc;
@@ -499,12 +518,7 @@
default:
return -1;
}
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- rc = pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ rc = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
@@ -519,13 +533,7 @@
slot_cmd = 0x0100;
cmd_mask = PWR_LED_CTRL;
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- pcie_write_cmd(slot, slot_cmd, cmd_mask);
-
+ pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
}
@@ -538,12 +546,7 @@
slot_cmd = 0x0300;
cmd_mask = PWR_LED_CTRL;
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
}
@@ -556,23 +559,19 @@
slot_cmd = 0x0200;
cmd_mask = PWR_LED_CTRL;
- if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd | HP_INTR_ENABLE;
- cmd_mask = cmd_mask | HP_INTR_ENABLE;
- }
-
- pcie_write_cmd(slot, slot_cmd, cmd_mask);
-
+ pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
}
static void hpc_release_ctlr(struct controller *ctrl)
{
- if (pciehp_poll_mode)
- del_timer(&ctrl->poll_timer);
- else
- free_irq(ctrl->pci_dev->irq, ctrl);
+ /* Mask Hot-plug Interrupt Enable */
+ if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE))
+ err("%s: Cannot mask hotplut interrupt enable\n", __func__);
+
+ /* Free interrupt handler or interrupt polling timer */
+ pciehp_free_irq(ctrl);
/*
* If this is the last controller to be released, destroy the
@@ -612,19 +611,13 @@
cmd_mask = PWR_CTRL;
/* Enable detection that we turned off at slot power-off time */
if (!pciehp_poll_mode) {
- slot_cmd = slot_cmd |
- PWR_FAULT_DETECT_ENABLE |
- MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE |
- HP_INTR_ENABLE;
- cmd_mask = cmd_mask |
- PWR_FAULT_DETECT_ENABLE |
- MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE |
- HP_INTR_ENABLE;
+ slot_cmd |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE);
+ cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE);
}
- retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) {
err("%s: Write %x command failed!\n", __func__, slot_cmd);
@@ -697,18 +690,13 @@
* till the slot is powered on again.
*/
if (!pciehp_poll_mode) {
- slot_cmd = (slot_cmd &
- ~PWR_FAULT_DETECT_ENABLE &
- ~MRL_DETECT_ENABLE &
- ~PRSN_DETECT_ENABLE) | HP_INTR_ENABLE;
- cmd_mask = cmd_mask |
- PWR_FAULT_DETECT_ENABLE |
- MRL_DETECT_ENABLE |
- PRSN_DETECT_ENABLE |
- HP_INTR_ENABLE;
+ slot_cmd &= ~(PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE);
+ cmd_mask |= (PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE |
+ PRSN_DETECT_ENABLE);
}
- retval = pcie_write_cmd(slot, slot_cmd, cmd_mask);
+ retval = pcie_write_cmd(ctrl, slot_cmd, cmd_mask);
if (retval) {
err("%s: Write command failed!\n", __func__);
retval = -1;
@@ -733,139 +721,56 @@
static irqreturn_t pcie_isr(int irq, void *dev_id)
{
struct controller *ctrl = (struct controller *)dev_id;
- u16 slot_status, intr_detect, intr_loc;
- u16 temp_word;
- int hp_slot = 0; /* only 1 slot per PCI Express port */
- int rc = 0;
- unsigned long flags;
+ u16 detected, intr_loc;
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
- return IRQ_NONE;
- }
-
- intr_detect = (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
- MRL_SENS_CHANGED | PRSN_DETECT_CHANGED | CMD_COMPLETED);
-
- intr_loc = slot_status & intr_detect;
-
- /* Check to see if it was our interrupt */
- if ( !intr_loc )
- return IRQ_NONE;
-
- dbg("%s: intr_loc %x\n", __func__, intr_loc);
- /* Mask Hot-plug Interrupt Enable */
- if (!pciehp_poll_mode) {
- spin_lock_irqsave(&ctrl->lock, flags);
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOT_CTRL register\n",
- __func__);
- spin_unlock_irqrestore(&ctrl->lock, flags);
+ /*
+ * In order to guarantee that all interrupt events are
+ * serviced, we need to re-inspect Slot Status register after
+ * clearing what is presumed to be the last pending interrupt.
+ */
+ intr_loc = 0;
+ do {
+ if (pciehp_readw(ctrl, SLOTSTATUS, &detected)) {
+ err("%s: Cannot read SLOTSTATUS\n", __func__);
return IRQ_NONE;
}
- dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
- __func__, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE &
- ~CMD_CMPL_INTR_ENABLE) | 0x00;
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n",
- __func__);
- spin_unlock_irqrestore(&ctrl->lock, flags);
+ detected &= (ATTN_BUTTN_PRESSED | PWR_FAULT_DETECTED |
+ MRL_SENS_CHANGED | PRSN_DETECT_CHANGED |
+ CMD_COMPLETED);
+ intr_loc |= detected;
+ if (!intr_loc)
+ return IRQ_NONE;
+ if (pciehp_writew(ctrl, SLOTSTATUS, detected)) {
+ err("%s: Cannot write to SLOTSTATUS\n", __func__);
return IRQ_NONE;
}
- spin_unlock_irqrestore(&ctrl->lock, flags);
+ } while (detected);
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOT_STATUS register\n",
- __func__);
- return IRQ_NONE;
- }
- dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
- __func__, slot_status);
+ dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
- /* Clear command complete interrupt caused by this write */
- temp_word = 0x1f;
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n",
- __func__);
- return IRQ_NONE;
- }
- }
-
+ /* Check Command Complete Interrupt Pending */
if (intr_loc & CMD_COMPLETED) {
- /*
- * Command Complete Interrupt Pending
- */
ctrl->cmd_busy = 0;
+ smp_mb();
wake_up_interruptible(&ctrl->queue);
}
+ /* Check MRL Sensor Changed */
if (intr_loc & MRL_SENS_CHANGED)
- pciehp_handle_switch_change(hp_slot, ctrl);
+ pciehp_handle_switch_change(0, ctrl);
+ /* Check Attention Button Pressed */
if (intr_loc & ATTN_BUTTN_PRESSED)
- pciehp_handle_attention_button(hp_slot, ctrl);
+ pciehp_handle_attention_button(0, ctrl);
+ /* Check Presence Detect Changed */
if (intr_loc & PRSN_DETECT_CHANGED)
- pciehp_handle_presence_change(hp_slot, ctrl);
+ pciehp_handle_presence_change(0, ctrl);
+ /* Check Power Fault Detected */
if (intr_loc & PWR_FAULT_DETECTED)
- pciehp_handle_power_fault(hp_slot, ctrl);
-
- /* Clear all events after serving them */
- temp_word = 0x1F;
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n", __func__);
- return IRQ_NONE;
- }
- /* Unmask Hot-plug Interrupt Enable */
- if (!pciehp_poll_mode) {
- spin_lock_irqsave(&ctrl->lock, flags);
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n",
- __func__);
- spin_unlock_irqrestore(&ctrl->lock, flags);
- return IRQ_NONE;
- }
-
- dbg("%s: Unmask Hot-plug Interrupt Enable\n", __func__);
- temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
-
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n",
- __func__);
- spin_unlock_irqrestore(&ctrl->lock, flags);
- return IRQ_NONE;
- }
- spin_unlock_irqrestore(&ctrl->lock, flags);
-
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOT_STATUS register\n",
- __func__);
- return IRQ_NONE;
- }
-
- /* Clear command complete interrupt caused by this write */
- temp_word = 0x1F;
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS failed\n",
- __func__);
- return IRQ_NONE;
- }
- dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
- __func__, temp_word);
- }
+ pciehp_handle_power_fault(0, ctrl);
return IRQ_HANDLED;
}
@@ -1052,7 +957,7 @@
};
#ifdef CONFIG_ACPI
-int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
+static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
{
acpi_status status;
acpi_handle chandle, handle = DEVICE_ACPI_HANDLE(&(dev->dev));
@@ -1112,7 +1017,7 @@
break;
}
- err("Cannot get control of hotplug hardware for pci %s\n",
+ dbg("Cannot get control of hotplug hardware for pci %s\n",
pci_name(dev));
kfree(string.pointer);
@@ -1123,45 +1028,9 @@
static int pcie_init_hardware_part1(struct controller *ctrl,
struct pcie_device *dev)
{
- int rc;
- u16 temp_word;
- u32 slot_cap;
- u16 slot_status;
-
- rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
- if (rc) {
- err("%s: Cannot read SLOTCAP register\n", __func__);
- return -1;
- }
-
/* Mask Hot-plug Interrupt Enable */
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __func__);
- return -1;
- }
-
- dbg("%s: SLOTCTRL %x value read %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, temp_word);
- temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) |
- 0x00;
-
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n", __func__);
- return -1;
- }
-
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
- return -1;
- }
-
- temp_word = 0x1F; /* Clear all events */
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n", __func__);
+ if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) {
+ err("%s: Cannot mask hotplug interrupt enable\n", __func__);
return -1;
}
return 0;
@@ -1169,205 +1038,125 @@
int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
{
- int rc;
- u16 temp_word;
- u16 intr_enable = 0;
- u32 slot_cap;
- u16 slot_status;
-
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __func__);
- goto abort;
- }
-
- intr_enable = intr_enable | PRSN_DETECT_ENABLE;
-
- rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
- if (rc) {
- err("%s: Cannot read SLOTCAP register\n", __func__);
- goto abort;
- }
-
- if (ATTN_BUTTN(slot_cap))
- intr_enable = intr_enable | ATTN_BUTTN_ENABLE;
-
- if (POWER_CTRL(slot_cap))
- intr_enable = intr_enable | PWR_FAULT_DETECT_ENABLE;
-
- if (MRL_SENS(slot_cap))
- intr_enable = intr_enable | MRL_DETECT_ENABLE;
-
- temp_word = (temp_word & ~intr_enable) | intr_enable;
-
- if (pciehp_poll_mode) {
- temp_word = (temp_word & ~HP_INTR_ENABLE) | 0x0;
- } else {
- temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
- }
+ u16 cmd, mask;
/*
- * Unmask Hot-plug Interrupt Enable for the interrupt
- * notification mechanism case.
+ * We need to clear all events before enabling hotplug interrupt
+ * notification mechanism in order for hotplug controler to
+ * generate interrupts.
*/
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTCTRL register\n", __func__);
+ if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
+ err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
+ return -1;
+ }
+
+ cmd = PRSN_DETECT_ENABLE;
+ if (ATTN_BUTTN(ctrl))
+ cmd |= ATTN_BUTTN_ENABLE;
+ if (POWER_CTRL(ctrl))
+ cmd |= PWR_FAULT_DETECT_ENABLE;
+ if (MRL_SENS(ctrl))
+ cmd |= MRL_DETECT_ENABLE;
+ if (!pciehp_poll_mode)
+ cmd |= HP_INTR_ENABLE;
+
+ mask = PRSN_DETECT_ENABLE | ATTN_BUTTN_ENABLE |
+ PWR_FAULT_DETECT_ENABLE | MRL_DETECT_ENABLE | HP_INTR_ENABLE;
+
+ if (pcie_write_cmd(ctrl, cmd, mask)) {
+ err("%s: Cannot enable software notification\n", __func__);
goto abort;
}
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
- goto abort_disable_intr;
- }
- temp_word = 0x1F; /* Clear all events */
- rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
- if (rc) {
- err("%s: Cannot write to SLOTSTATUS register\n", __func__);
- goto abort_disable_intr;
- }
-
- if (pciehp_force) {
+ if (pciehp_force)
dbg("Bypassing BIOS check for pciehp use on %s\n",
pci_name(ctrl->pci_dev));
- } else {
- rc = pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev);
- if (rc)
- goto abort_disable_intr;
- }
+ else if (pciehp_get_hp_hw_control_from_firmware(ctrl->pci_dev))
+ goto abort_disable_intr;
return 0;
/* We end up here for the many possible ways to fail this API. */
abort_disable_intr:
- rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
- if (!rc) {
- temp_word &= ~(intr_enable | HP_INTR_ENABLE);
- rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
- }
- if (rc)
+ if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE))
err("%s : disabling interrupts failed\n", __func__);
abort:
return -1;
}
+static inline void dbg_ctrl(struct controller *ctrl)
+{
+ int i;
+ u16 reg16;
+ struct pci_dev *pdev = ctrl->pci_dev;
+
+ if (!pciehp_debug)
+ return;
+
+ dbg("Hotplug Controller:\n");
+ dbg(" Seg/Bus/Dev/Func/IRQ : %s IRQ %d\n", pci_name(pdev), pdev->irq);
+ dbg(" Vendor ID : 0x%04x\n", pdev->vendor);
+ dbg(" Device ID : 0x%04x\n", pdev->device);
+ dbg(" Subsystem ID : 0x%04x\n", pdev->subsystem_device);
+ dbg(" Subsystem Vendor ID : 0x%04x\n", pdev->subsystem_vendor);
+ dbg(" PCIe Cap offset : 0x%02x\n", ctrl->cap_base);
+ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+ if (!pci_resource_len(pdev, i))
+ continue;
+ dbg(" PCI resource [%d] : 0x%llx@0x%llx\n", i,
+ (unsigned long long)pci_resource_len(pdev, i),
+ (unsigned long long)pci_resource_start(pdev, i));
+ }
+ dbg("Slot Capabilities : 0x%08x\n", ctrl->slot_cap);
+ dbg(" Physical Slot Number : %d\n", ctrl->first_slot);
+ dbg(" Attention Button : %3s\n", ATTN_BUTTN(ctrl) ? "yes" : "no");
+ dbg(" Power Controller : %3s\n", POWER_CTRL(ctrl) ? "yes" : "no");
+ dbg(" MRL Sensor : %3s\n", MRL_SENS(ctrl) ? "yes" : "no");
+ dbg(" Attention Indicator : %3s\n", ATTN_LED(ctrl) ? "yes" : "no");
+ dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no");
+ dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no");
+ dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no");
+ pciehp_readw(ctrl, SLOTSTATUS, ®16);
+ dbg("Slot Status : 0x%04x\n", reg16);
+ pciehp_readw(ctrl, SLOTSTATUS, ®16);
+ dbg("Slot Control : 0x%04x\n", reg16);
+}
+
int pcie_init(struct controller *ctrl, struct pcie_device *dev)
{
- int rc;
- u16 cap_reg;
u32 slot_cap;
- int cap_base;
- u16 slot_status, slot_ctrl;
- struct pci_dev *pdev;
+ struct pci_dev *pdev = dev->port;
- pdev = dev->port;
- ctrl->pci_dev = pdev; /* save pci_dev in context */
-
- dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
- __func__, pdev->vendor, pdev->device);
-
- cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- if (cap_base == 0) {
- dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __func__);
+ ctrl->pci_dev = pdev;
+ ctrl->cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ if (!ctrl->cap_base) {
+ err("%s: Cannot find PCI Express capability\n", __func__);
goto abort;
}
-
- ctrl->cap_base = cap_base;
-
- dbg("%s: pcie_cap_base %x\n", __func__, cap_base);
-
- rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
- if (rc) {
- err("%s: Cannot read CAPREG register\n", __func__);
- goto abort;
- }
- dbg("%s: CAPREG offset %x cap_reg %x\n",
- __func__, ctrl->cap_base + CAPREG, cap_reg);
-
- if (((cap_reg & SLOT_IMPL) == 0) ||
- (((cap_reg & DEV_PORT_TYPE) != 0x0040)
- && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
- dbg("%s : This is not a root port or the port is not "
- "connected to a slot\n", __func__);
- goto abort;
- }
-
- rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
- if (rc) {
+ if (pciehp_readl(ctrl, SLOTCAP, &slot_cap)) {
err("%s: Cannot read SLOTCAP register\n", __func__);
goto abort;
}
- dbg("%s: SLOTCAP offset %x slot_cap %x\n",
- __func__, ctrl->cap_base + SLOTCAP, slot_cap);
- if (!(slot_cap & HP_CAP)) {
- dbg("%s : This slot is not hot-plug capable\n", __func__);
- goto abort;
- }
- /* For debugging purpose */
- rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
- if (rc) {
- err("%s: Cannot read SLOTSTATUS register\n", __func__);
- goto abort;
- }
- dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
- __func__, ctrl->cap_base + SLOTSTATUS, slot_status);
-
- rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
- if (rc) {
- err("%s: Cannot read SLOTCTRL register\n", __func__);
- goto abort;
- }
- dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
- __func__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
-
- for (rc = 0; rc < DEVICE_COUNT_RESOURCE; rc++)
- if (pci_resource_len(pdev, rc) > 0)
- dbg("pci resource[%d] start=0x%llx(len=0x%llx)\n", rc,
- (unsigned long long)pci_resource_start(pdev, rc),
- (unsigned long long)pci_resource_len(pdev, rc));
+ ctrl->slot_cap = slot_cap;
+ ctrl->first_slot = slot_cap >> 19;
+ ctrl->slot_device_offset = 0;
+ ctrl->num_slots = 1;
+ ctrl->hpc_ops = &pciehp_hpc_ops;
+ mutex_init(&ctrl->crit_sect);
+ mutex_init(&ctrl->ctrl_lock);
+ init_waitqueue_head(&ctrl->queue);
+ dbg_ctrl(ctrl);
info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
pdev->vendor, pdev->device,
pdev->subsystem_vendor, pdev->subsystem_device);
- mutex_init(&ctrl->crit_sect);
- mutex_init(&ctrl->ctrl_lock);
- spin_lock_init(&ctrl->lock);
-
- /* setup wait queue */
- init_waitqueue_head(&ctrl->queue);
-
- /* return PCI Controller Info */
- ctrl->slot_device_offset = 0;
- ctrl->num_slots = 1;
- ctrl->first_slot = slot_cap >> 19;
- ctrl->ctrlcap = slot_cap & 0x0000007f;
-
- rc = pcie_init_hardware_part1(ctrl, dev);
- if (rc)
+ if (pcie_init_hardware_part1(ctrl, dev))
goto abort;
- if (pciehp_poll_mode) {
- /* Install interrupt polling timer. Start with 10 sec delay */
- init_timer(&ctrl->poll_timer);
- start_int_poll_timer(ctrl, 10);
- } else {
- /* Installs the interrupt handler */
- rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
- MY_NAME, (void *)ctrl);
- dbg("%s: request_irq %d for hpc%d (returns %d)\n",
- __func__, ctrl->pci_dev->irq,
- atomic_read(&pciehp_num_controllers), rc);
- if (rc) {
- err("Can't get irq %d for the hotplug controller\n",
- ctrl->pci_dev->irq);
- goto abort;
- }
- }
- dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
- PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
+ if (pciehp_request_irq(ctrl))
+ goto abort;
/*
* If this is the first controller to be initialized,
@@ -1376,21 +1165,17 @@
if (atomic_add_return(1, &pciehp_num_controllers) == 1) {
pciehp_wq = create_singlethread_workqueue("pciehpd");
if (!pciehp_wq) {
- rc = -ENOMEM;
goto abort_free_irq;
}
}
- rc = pcie_init_hardware_part2(ctrl, dev);
- if (rc == 0) {
- ctrl->hpc_ops = &pciehp_hpc_ops;
- return 0;
- }
+ if (pcie_init_hardware_part2(ctrl, dev))
+ goto abort_free_irq;
+
+ return 0;
+
abort_free_irq:
- if (pciehp_poll_mode)
- del_timer_sync(&ctrl->poll_timer);
- else
- free_irq(ctrl->pci_dev->irq, ctrl);
+ pciehp_free_irq(ctrl);
abort:
return -1;
}
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index 43816d4..1648076 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -39,6 +39,7 @@
int shpchp_debug;
int shpchp_poll_mode;
int shpchp_poll_time;
+int shpchp_slot_with_bus;
struct workqueue_struct *shpchp_wq;
#define DRIVER_VERSION "0.4"
@@ -52,9 +53,11 @@
module_param(shpchp_debug, bool, 0644);
module_param(shpchp_poll_mode, bool, 0644);
module_param(shpchp_poll_time, int, 0644);
+module_param(shpchp_slot_with_bus, bool, 0644);
MODULE_PARM_DESC(shpchp_debug, "Debugging mode enabled or not");
MODULE_PARM_DESC(shpchp_poll_mode, "Using polling mechanism for hot-plug events or not");
MODULE_PARM_DESC(shpchp_poll_time, "Polling mechanism frequency, in seconds");
+MODULE_PARM_DESC(shpchp_slot_with_bus, "Use bus number in the slot name");
#define SHPC_MODULE_NAME "shpchp"
@@ -100,8 +103,12 @@
static void make_slot_name(struct slot *slot)
{
- snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
- slot->bus, slot->number);
+ if (shpchp_slot_with_bus)
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+ slot->bus, slot->number);
+ else
+ snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d",
+ slot->number);
}
static int init_slots(struct controller *ctrl)
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 26938da..8c61304c 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -123,7 +123,7 @@
}
}
-static void msi_set_mask_bit(unsigned int irq, int flag)
+static void msi_set_mask_bits(unsigned int irq, u32 mask, u32 flag)
{
struct msi_desc *entry;
@@ -137,8 +137,8 @@
pos = (long)entry->mask_base;
pci_read_config_dword(entry->dev, pos, &mask_bits);
- mask_bits &= ~(1);
- mask_bits |= flag;
+ mask_bits &= ~(mask);
+ mask_bits |= flag & mask;
pci_write_config_dword(entry->dev, pos, mask_bits);
} else {
msi_set_enable(entry->dev, !flag);
@@ -241,13 +241,13 @@
void mask_msi_irq(unsigned int irq)
{
- msi_set_mask_bit(irq, 1);
+ msi_set_mask_bits(irq, 1, 1);
msix_flush_writes(irq);
}
void unmask_msi_irq(unsigned int irq)
{
- msi_set_mask_bit(irq, 0);
+ msi_set_mask_bits(irq, 1, 0);
msix_flush_writes(irq);
}
@@ -291,7 +291,8 @@
msi_set_enable(dev, 0);
write_msi_msg(dev->irq, &entry->msg);
if (entry->msi_attrib.maskbit)
- msi_set_mask_bit(dev->irq, entry->msi_attrib.masked);
+ msi_set_mask_bits(dev->irq, entry->msi_attrib.maskbits_mask,
+ entry->msi_attrib.masked);
pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
control &= ~(PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
@@ -315,7 +316,7 @@
list_for_each_entry(entry, &dev->msi_list, list) {
write_msi_msg(entry->irq, &entry->msg);
- msi_set_mask_bit(entry->irq, entry->msi_attrib.masked);
+ msi_set_mask_bits(entry->irq, 1, entry->msi_attrib.masked);
}
BUG_ON(list_empty(&dev->msi_list));
@@ -382,6 +383,7 @@
pci_write_config_dword(dev,
msi_mask_bits_reg(pos, is_64bit_address(control)),
maskbits);
+ entry->msi_attrib.maskbits_mask = temp;
}
list_add_tail(&entry->list, &dev->msi_list);
@@ -569,10 +571,9 @@
}
EXPORT_SYMBOL(pci_enable_msi);
-void pci_disable_msi(struct pci_dev* dev)
+void pci_msi_shutdown(struct pci_dev* dev)
{
struct msi_desc *entry;
- int default_irq;
if (!pci_msi_enable || !dev || !dev->msi_enabled)
return;
@@ -583,15 +584,31 @@
BUG_ON(list_empty(&dev->msi_list));
entry = list_entry(dev->msi_list.next, struct msi_desc, list);
- if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
- return;
+ /* Return the the pci reset with msi irqs unmasked */
+ if (entry->msi_attrib.maskbit) {
+ u32 mask = entry->msi_attrib.maskbits_mask;
+ msi_set_mask_bits(dev->irq, mask, ~mask);
}
-
- default_irq = entry->msi_attrib.default_irq;
- msi_free_irqs(dev);
+ if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
+ return;
/* Restore dev->irq to its default pin-assertion irq */
- dev->irq = default_irq;
+ dev->irq = entry->msi_attrib.default_irq;
+}
+void pci_disable_msi(struct pci_dev* dev)
+{
+ struct msi_desc *entry;
+
+ if (!pci_msi_enable || !dev || !dev->msi_enabled)
+ return;
+
+ pci_msi_shutdown(dev);
+
+ entry = list_entry(dev->msi_list.next, struct msi_desc, list);
+ if (!entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI)
+ return;
+
+ msi_free_irqs(dev);
}
EXPORT_SYMBOL(pci_disable_msi);
@@ -684,7 +701,7 @@
msi_free_irqs(dev);
}
-void pci_disable_msix(struct pci_dev* dev)
+void pci_msix_shutdown(struct pci_dev* dev)
{
if (!pci_msi_enable || !dev || !dev->msix_enabled)
return;
@@ -692,6 +709,13 @@
msix_set_enable(dev, 0);
pci_intx_for_msi(dev, 1);
dev->msix_enabled = 0;
+}
+void pci_disable_msix(struct pci_dev* dev)
+{
+ if (!pci_msi_enable || !dev || !dev->msix_enabled)
+ return;
+
+ pci_msix_shutdown(dev);
msix_free_all_irqs(dev);
}
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e8d94fa..72cf61e 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -360,6 +360,8 @@
if (drv && drv->shutdown)
drv->shutdown(pci_dev);
+ pci_msi_shutdown(pci_dev);
+ pci_msix_shutdown(pci_dev);
}
/**
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 25b04fb..5a0c6ad 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -33,7 +33,7 @@
config PCIEASPM
bool "PCI Express ASPM support(Experimental)"
depends on PCI && EXPERIMENTAL && PCIEPORTBUS
- default y
+ default n
help
This enables PCI Express ASPM (Active State Power Management) and
Clock Power Management. ASPM supports state L0/L0s/L1.
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index f991359..4a55bf3 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -842,11 +842,14 @@
* reading the dword at 0x100 which must either be 0 or a valid extended
* capability header.
*/
-int pci_cfg_space_size(struct pci_dev *dev)
+int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix)
{
int pos;
u32 status;
+ if (!check_exp_pcix)
+ goto skip;
+
pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
if (!pos) {
pos = pci_find_capability(dev, PCI_CAP_ID_PCIX);
@@ -858,6 +861,7 @@
goto fail;
}
+ skip:
if (pci_read_config_dword(dev, 256, &status) != PCIBIOS_SUCCESSFUL)
goto fail;
if (status == 0xffffffff)
@@ -869,6 +873,11 @@
return PCI_CFG_SPACE_SIZE;
}
+int pci_cfg_space_size(struct pci_dev *dev)
+{
+ return pci_cfg_space_size_ext(dev, 1);
+}
+
static void pci_release_bus_bridge_dev(struct device *dev)
{
kfree(dev);
@@ -964,7 +973,6 @@
dev->dev.release = pci_release_dev;
pci_dev_get(dev);
- set_dev_node(&dev->dev, pcibus_to_node(bus));
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.dma_parms = &dev->dma_parms;
dev->dev.coherent_dma_mask = 0xffffffffull;
@@ -1080,6 +1088,10 @@
return max;
}
+void __attribute__((weak)) set_pci_bus_resources_arch_default(struct pci_bus *b)
+{
+}
+
struct pci_bus * pci_create_bus(struct device *parent,
int bus, struct pci_ops *ops, void *sysdata)
{
@@ -1119,6 +1131,9 @@
goto dev_reg_err;
b->bridge = get_device(dev);
+ if (!parent)
+ set_dev_node(b->bridge, pcibus_to_node(b));
+
b->dev.class = &pcibus_class;
b->dev.parent = b->bridge;
sprintf(b->dev.bus_id, "%04x:%02x", pci_domain_nr(b), bus);
@@ -1136,6 +1151,8 @@
b->resource[0] = &ioport_resource;
b->resource[1] = &iomem_resource;
+ set_pci_bus_resources_arch_default(b);
+
return b;
dev_create_file_err:
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index ef18fcd..963a976 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -293,6 +293,7 @@
#endif /* HAVE_PCI_MMAP */
static const struct file_operations proc_bus_pci_operations = {
+ .owner = THIS_MODULE,
.llseek = proc_bus_pci_lseek,
.read = proc_bus_pci_read,
.write = proc_bus_pci_write,
@@ -406,11 +407,10 @@
}
sprintf(name, "%02x.%x", PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- e = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir);
+ e = proc_create_data(name, S_IFREG | S_IRUGO | S_IWUSR, bus->procdir,
+ &proc_bus_pci_operations, dev);
if (!e)
return -ENOMEM;
- e->proc_fops = &proc_bus_pci_operations;
- e->data = dev;
e->size = dev->cfg_size;
dev->procent = e;
@@ -462,6 +462,7 @@
return seq_open(file, &proc_bus_pci_devices_op);
}
static const struct file_operations proc_bus_pci_dev_operations = {
+ .owner = THIS_MODULE,
.open = proc_bus_pci_dev_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -470,12 +471,10 @@
static int __init pci_proc_init(void)
{
- struct proc_dir_entry *entry;
struct pci_dev *dev = NULL;
- proc_bus_pci_dir = proc_mkdir("pci", proc_bus);
- entry = create_proc_entry("devices", 0, proc_bus_pci_dir);
- if (entry)
- entry->proc_fops = &proc_bus_pci_dev_operations;
+ proc_bus_pci_dir = proc_mkdir("bus/pci", NULL);
+ proc_create("devices", 0, proc_bus_pci_dir,
+ &proc_bus_pci_dev_operations);
proc_initialized = 1;
while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
pci_proc_attach_device(dev);
diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c
index 74e0515..c78d77f 100644
--- a/drivers/pcmcia/au1000_db1x00.c
+++ b/drivers/pcmcia/au1000_db1x00.c
@@ -194,7 +194,7 @@
default:
pwr |= SET_VCC_VPP(0,0,sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
state->Vcc,
state->Vpp);
break;
@@ -215,7 +215,7 @@
default:
pwr |= SET_VCC_VPP(0,0,sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
state->Vcc,
state->Vpp);
break;
@@ -224,7 +224,7 @@
default: /* what's this ? */
pwr |= SET_VCC_VPP(0,0,sock);
printk(KERN_ERR "%s: bad Vcc %d\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
break;
}
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c
index b693367..75e8f85 100644
--- a/drivers/pcmcia/au1000_generic.c
+++ b/drivers/pcmcia/au1000_generic.c
@@ -41,6 +41,7 @@
#include <linux/notifier.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <asm/io.h>
@@ -71,7 +72,7 @@
u32 *pcmcia_base_vaddrs[2];
extern const unsigned long mips_io_port_base;
-DECLARE_MUTEX(pcmcia_sockets_lock);
+static DEFINE_MUTEX(pcmcia_sockets_lock);
static int (*au1x00_pcmcia_hw_init[])(struct device *dev) = {
au1x_board_init,
@@ -472,7 +473,7 @@
struct skt_dev_info *sinfo = dev_get_drvdata(dev);
int i;
- down(&pcmcia_sockets_lock);
+ mutex_lock(&pcmcia_sockets_lock);
dev_set_drvdata(dev, NULL);
for (i = 0; i < sinfo->nskt; i++) {
@@ -488,7 +489,7 @@
}
kfree(sinfo);
- up(&pcmcia_sockets_lock);
+ mutex_unlock(&pcmcia_sockets_lock);
return 0;
}
@@ -501,13 +502,13 @@
{
int i, ret = -ENODEV;
- down(&pcmcia_sockets_lock);
+ mutex_lock(&pcmcia_sockets_lock);
for (i=0; i < ARRAY_SIZE(au1x00_pcmcia_hw_init); i++) {
ret = au1x00_pcmcia_hw_init[i](dev);
if (ret == 0)
break;
}
- up(&pcmcia_sockets_lock);
+ mutex_unlock(&pcmcia_sockets_lock);
return ret;
}
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index 86c0808..157e414 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -244,7 +244,7 @@
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -272,7 +272,7 @@
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -300,7 +300,7 @@
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,
configure->sock);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -309,7 +309,7 @@
default: /* what's this ? */
pcr |= SET_VCC_VPP(VCC_HIZ,VPP_HIZ,configure->sock);
printk(KERN_ERR "%s: bad Vcc %d\n",
- __FUNCTION__, configure->vcc);
+ __func__, configure->vcc);
break;
}
@@ -353,7 +353,7 @@
default:
pcr |= SET_VCC_VPP(0,0);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -374,7 +374,7 @@
default:
pcr |= SET_VCC_VPP(0,0);
printk("%s: bad Vcc/Vpp (%d:%d)\n",
- __FUNCTION__,
+ __func__,
configure->vcc,
configure->vpp);
break;
@@ -383,7 +383,7 @@
default: /* what's this ? */
pcr |= SET_VCC_VPP(0,0);
printk(KERN_ERR "%s: bad Vcc %d\n",
- __FUNCTION__, configure->vcc);
+ __func__, configure->vcc);
break;
}
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index ce9d5c4..c78ed53 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -56,7 +56,7 @@
#define PCMCIA_IRQ AU1000_GPIO_4
#if 0
-#define DEBUG(x,args...) printk(__FUNCTION__ ": " x,##args)
+#define DEBUG(x, args...) printk(__func__ ": " x, ##args)
#else
#define DEBUG(x,args...)
#endif
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 714baae..fb2f38d 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -209,7 +209,7 @@
}
}
-int cb_alloc(struct pcmcia_socket * s)
+int __ref cb_alloc(struct pcmcia_socket * s)
{
struct pci_bus *bus = s->cb_dev->subordinate;
struct pci_dev *dev;
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 06a85d7..3637953 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -402,15 +402,6 @@
======================================================================*/
-static inline u16 cis_get_u16(void *ptr)
-{
- return le16_to_cpu(get_unaligned((__le16 *) ptr));
-}
-static inline u32 cis_get_u32(void *ptr)
-{
- return le32_to_cpu(get_unaligned((__le32 *) ptr));
-}
-
typedef struct tuple_flags {
u_int link_space:4;
u_int has_link:1;
@@ -471,7 +462,7 @@
/* Get indirect link from the MFC tuple */
read_cis_cache(s, LINK_SPACE(tuple->Flags),
tuple->LinkOffset, 5, link);
- ofs = cis_get_u32(link + 1);
+ ofs = get_unaligned_le32(link + 1);
SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
/* Move to the next indirect link */
tuple->LinkOffset += 5;
@@ -679,8 +670,8 @@
if (tuple->TupleDataLen < 5)
return CS_BAD_TUPLE;
p = (u_char *) tuple->TupleData;
- csum->addr = tuple->CISOffset + cis_get_u16(p) - 2;
- csum->len = cis_get_u16(p + 2);
+ csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
+ csum->len = get_unaligned_le16(p + 2);
csum->sum = *(p + 4);
return CS_SUCCESS;
}
@@ -691,7 +682,7 @@
{
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- link->addr = cis_get_u32(tuple->TupleData);
+ link->addr = get_unaligned_le32(tuple->TupleData);
return CS_SUCCESS;
}
@@ -710,7 +701,7 @@
return CS_BAD_TUPLE;
for (i = 0; i < link->nfn; i++) {
link->fn[i].space = *p; p++;
- link->fn[i].addr = cis_get_u32(p);
+ link->fn[i].addr = get_unaligned_le32(p);
p += 4;
}
return CS_SUCCESS;
@@ -800,8 +791,8 @@
{
if (tuple->TupleDataLen < 4)
return CS_BAD_TUPLE;
- m->manf = cis_get_u16(tuple->TupleData);
- m->card = cis_get_u16(tuple->TupleData + 2);
+ m->manf = get_unaligned_le16(tuple->TupleData);
+ m->card = get_unaligned_le16(tuple->TupleData + 2);
return CS_SUCCESS;
}
@@ -1100,7 +1091,7 @@
break;
case 0x20:
entry->mem.nwin = 1;
- entry->mem.win[0].len = cis_get_u16(p) << 8;
+ entry->mem.win[0].len = get_unaligned_le16(p) << 8;
entry->mem.win[0].card_addr = 0;
entry->mem.win[0].host_addr = 0;
p += 2;
@@ -1108,8 +1099,8 @@
break;
case 0x40:
entry->mem.nwin = 1;
- entry->mem.win[0].len = cis_get_u16(p) << 8;
- entry->mem.win[0].card_addr = cis_get_u16(p + 2) << 8;
+ entry->mem.win[0].len = get_unaligned_le16(p) << 8;
+ entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
entry->mem.win[0].host_addr = 0;
p += 4;
if (p > q) return CS_BAD_TUPLE;
@@ -1146,7 +1137,7 @@
p = (u_char *)tuple->TupleData;
bar->attr = *p;
p += 2;
- bar->size = cis_get_u32(p);
+ bar->size = get_unaligned_le32(p);
return CS_SUCCESS;
}
@@ -1159,7 +1150,7 @@
return CS_BAD_TUPLE;
config->last_idx = *(++p);
p++;
- config->base = cis_get_u32(p);
+ config->base = get_unaligned_le32(p);
config->subtuples = tuple->TupleDataLen - 6;
return CS_SUCCESS;
}
@@ -1275,7 +1266,7 @@
v2->vers = p[0];
v2->comply = p[1];
- v2->dindex = cis_get_u16(p +2 );
+ v2->dindex = get_unaligned_le16(p +2 );
v2->vspec8 = p[6];
v2->vspec9 = p[7];
v2->nhdr = p[8];
@@ -1316,8 +1307,8 @@
fmt->type = p[0];
fmt->edc = p[1];
- fmt->offset = cis_get_u32(p + 2);
- fmt->length = cis_get_u32(p + 6);
+ fmt->offset = get_unaligned_le32(p + 2);
+ fmt->length = get_unaligned_le32(p + 6);
return CS_SUCCESS;
}
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index 56230db..29276bd 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -652,6 +652,9 @@
complete(&skt->thread_done);
return 0;
}
+ ret = pccard_sysfs_add_socket(&skt->dev);
+ if (ret)
+ dev_warn(&skt->dev, "err %d adding socket attributes\n", ret);
add_wait_queue(&skt->thread_wait, &wait);
complete(&skt->thread_done);
@@ -694,6 +697,7 @@
remove_wait_queue(&skt->thread_wait, &wait);
/* remove from the device core */
+ pccard_sysfs_remove_socket(&skt->dev);
device_unregister(&skt->dev);
return 0;
@@ -940,20 +944,13 @@
static int __init init_pcmcia_cs(void)
{
- int ret;
-
init_completion(&pcmcia_unload);
- ret = class_register(&pcmcia_socket_class);
- if (ret)
- return (ret);
- return class_interface_register(&pccard_sysfs_interface);
+ return class_register(&pcmcia_socket_class);
}
static void __exit exit_pcmcia_cs(void)
{
- class_interface_unregister(&pccard_sysfs_interface);
class_unregister(&pcmcia_socket_class);
-
wait_for_completion(&pcmcia_unload);
}
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 9fa207e..e7d5d14 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -121,7 +121,8 @@
void release_resource_db(struct pcmcia_socket *s);
/* In socket_sysfs.c */
-extern struct class_interface pccard_sysfs_interface;
+extern int pccard_sysfs_add_socket(struct device *dev);
+extern void pccard_sysfs_remove_socket(struct device *dev);
/* In cs.c */
extern struct rw_semaphore pcmcia_socket_list_rwsem;
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 5a85871..e407754 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -1520,7 +1520,7 @@
/* the pcmcia_bus_interface is used to handle pcmcia socket devices */
-static struct class_interface pcmcia_bus_interface = {
+static struct class_interface pcmcia_bus_interface __refdata = {
.class = &pcmcia_socket_class,
.add_dev = &pcmcia_bus_add_socket,
.remove_dev = &pcmcia_bus_remove_socket,
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index e54ecc5..e136186 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -53,7 +53,7 @@
}
#endif
-static struct pci_driver i82092aa_pci_drv = {
+static struct pci_driver i82092aa_pci_driver = {
.name = "i82092aa",
.id_table = i82092aa_pci_ids,
.probe = i82092aa_pci_probe,
@@ -714,13 +714,13 @@
static int i82092aa_module_init(void)
{
- return pci_register_driver(&i82092aa_pci_drv);
+ return pci_register_driver(&i82092aa_pci_driver);
}
static void i82092aa_module_exit(void)
{
enter("i82092aa_module_exit");
- pci_unregister_driver(&i82092aa_pci_drv);
+ pci_unregister_driver(&i82092aa_pci_driver);
if (sockets[0].io_base>0)
release_region(sockets[0].io_base, 2);
leave("i82092aa_module_exit");
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index bb6db3a..46314b4 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -153,7 +153,7 @@
static int omap_cf_ss_suspend(struct pcmcia_socket *s)
{
- pr_debug("%s: %s\n", driver_name, __FUNCTION__);
+ pr_debug("%s: %s\n", driver_name, __func__);
return omap_cf_set_socket(s, &dead_socket);
}
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
index 27523c5..5f186ab 100644
--- a/drivers/pcmcia/pcmcia_ioctl.c
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -787,7 +787,7 @@
major_dev = i;
#ifdef CONFIG_PROC_FS
- proc_pccard = proc_mkdir("pccard", proc_bus);
+ proc_pccard = proc_mkdir("bus/pccard", NULL);
if (proc_pccard)
create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
#endif
@@ -798,7 +798,7 @@
#ifdef CONFIG_PROC_FS
if (proc_pccard) {
remove_proc_entry("drivers", proc_pccard);
- remove_proc_entry("pccard", proc_bus);
+ remove_proc_entry("bus/pccard", NULL);
}
#endif
if (major_dev != -1)
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index abc10fe..8bed1da 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -778,7 +778,7 @@
};
MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
-static struct pci_driver pd6729_pci_drv = {
+static struct pci_driver pd6729_pci_driver = {
.name = "pd6729",
.id_table = pd6729_pci_ids,
.probe = pd6729_pci_probe,
@@ -791,12 +791,12 @@
static int pd6729_module_init(void)
{
- return pci_register_driver(&pd6729_pci_drv);
+ return pci_register_driver(&pd6729_pci_driver);
}
static void pd6729_module_exit(void)
{
- pci_unregister_driver(&pd6729_pci_drv);
+ pci_unregister_driver(&pd6729_pci_driver);
}
module_init(pd6729_module_init);
diff --git a/drivers/pcmcia/pxa2xx_lubbock.c b/drivers/pcmcia/pxa2xx_lubbock.c
index 4a05802..881ec8a 100644
--- a/drivers/pcmcia/pxa2xx_lubbock.c
+++ b/drivers/pcmcia/pxa2xx_lubbock.c
@@ -87,7 +87,7 @@
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
ret = -1;
}
@@ -104,7 +104,7 @@
pa_dwr_set |= GPIO_A0;
else {
printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
ret = -1;
break;
}
@@ -128,14 +128,14 @@
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
ret = -1;
break;
}
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
ret = -1;
break;
}
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c
index 6fa5eaa..145b85e 100644
--- a/drivers/pcmcia/pxa2xx_mainstone.c
+++ b/drivers/pcmcia/pxa2xx_mainstone.c
@@ -99,7 +99,7 @@
case 50: power |= MST_PCMCIA_PWR_VCC_50; break;
default:
printk(KERN_ERR "%s(): bad Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
ret = -1;
}
@@ -111,7 +111,7 @@
power |= MST_PCMCIA_PWR_VPP_VCC;
} else {
printk(KERN_ERR "%s(): bad Vpp %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
ret = -1;
}
}
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index a8d1007..0fcf763 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -1045,7 +1045,7 @@
device_remove_file(dev, *attr);
}
-static struct class_interface pccard_rsrc_interface = {
+static struct class_interface pccard_rsrc_interface __refdata = {
.class = &pcmcia_socket_class,
.add_dev = &pccard_sysfs_add_rsrc,
.remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
diff --git a/drivers/pcmcia/sa1100_assabet.c b/drivers/pcmcia/sa1100_assabet.c
index 7c57fdd..ce133ce 100644
--- a/drivers/pcmcia/sa1100_assabet.c
+++ b/drivers/pcmcia/sa1100_assabet.c
@@ -66,14 +66,14 @@
case 50:
printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V...\n",
- __FUNCTION__);
+ __func__);
case 33: /* Can only apply 3.3V to the CF slot. */
mask = ASSABET_BCR_CF_PWR;
break;
default:
- printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
+ printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __func__,
state->Vcc);
return -1;
}
diff --git a/drivers/pcmcia/sa1100_badge4.c b/drivers/pcmcia/sa1100_badge4.c
index 62bfc75..607c3f3 100644
--- a/drivers/pcmcia/sa1100_badge4.c
+++ b/drivers/pcmcia/sa1100_badge4.c
@@ -82,14 +82,14 @@
case 0:
if ((state->Vcc != 0) &&
(state->Vcc != badge4_pcmvcc)) {
- complain_about_jumpering(__FUNCTION__, "pcmvcc",
+ complain_about_jumpering(__func__, "pcmvcc",
badge4_pcmvcc, state->Vcc);
// Apply power regardless of the jumpering.
// return -1;
}
if ((state->Vpp != 0) &&
(state->Vpp != badge4_pcmvpp)) {
- complain_about_jumpering(__FUNCTION__, "pcmvpp",
+ complain_about_jumpering(__func__, "pcmvpp",
badge4_pcmvpp, state->Vpp);
return -1;
}
@@ -98,7 +98,7 @@
case 1:
if ((state->Vcc != 0) &&
(state->Vcc != badge4_cfvcc)) {
- complain_about_jumpering(__FUNCTION__, "cfvcc",
+ complain_about_jumpering(__func__, "cfvcc",
badge4_cfvcc, state->Vcc);
return -1;
}
@@ -143,7 +143,7 @@
if (machine_is_badge4()) {
printk(KERN_INFO
"%s: badge4_pcmvcc=%d, badge4_pcmvpp=%d, badge4_cfvcc=%d\n",
- __FUNCTION__,
+ __func__,
badge4_pcmvcc, badge4_pcmvpp, badge4_cfvcc);
ret = sa11xx_drv_pcmcia_probe(dev, &badge4_pcmcia_ops, 0, 2);
diff --git a/drivers/pcmcia/sa1100_cerf.c b/drivers/pcmcia/sa1100_cerf.c
index 549a152..7c3951a 100644
--- a/drivers/pcmcia/sa1100_cerf.c
+++ b/drivers/pcmcia/sa1100_cerf.c
@@ -63,7 +63,7 @@
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
return -1;
}
diff --git a/drivers/pcmcia/sa1100_jornada720.c b/drivers/pcmcia/sa1100_jornada720.c
index 6284c35..2167e67 100644
--- a/drivers/pcmcia/sa1100_jornada720.c
+++ b/drivers/pcmcia/sa1100_jornada720.c
@@ -42,7 +42,7 @@
unsigned int pa_dwr_mask, pa_dwr_set;
int ret;
-printk("%s(): config socket %d vcc %d vpp %d\n", __FUNCTION__,
+printk("%s(): config socket %d vcc %d vpp %d\n", __func__,
skt->nr, state->Vcc, state->Vpp);
switch (skt->nr) {
@@ -74,7 +74,7 @@
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): slot cannot support VPP %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
return -1;
}
diff --git a/drivers/pcmcia/sa1100_neponset.c b/drivers/pcmcia/sa1100_neponset.c
index 5bc9e95..687492f 100644
--- a/drivers/pcmcia/sa1100_neponset.c
+++ b/drivers/pcmcia/sa1100_neponset.c
@@ -59,7 +59,7 @@
ncr_set = NCR_A0VPP;
else {
printk(KERN_ERR "%s(): unrecognized VPP %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
return -1;
}
break;
@@ -71,7 +71,7 @@
if (state->Vpp != state->Vcc && state->Vpp != 0) {
printk(KERN_ERR "%s(): CF slot cannot support VPP %u\n",
- __FUNCTION__, state->Vpp);
+ __func__, state->Vpp);
return -1;
}
break;
diff --git a/drivers/pcmcia/sa1100_shannon.c b/drivers/pcmcia/sa1100_shannon.c
index 9456f54..494912f 100644
--- a/drivers/pcmcia/sa1100_shannon.c
+++ b/drivers/pcmcia/sa1100_shannon.c
@@ -73,19 +73,19 @@
{
switch (state->Vcc) {
case 0: /* power off */
- printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): CS asked for 0V, still applying 3.3V..\n", __func__);
break;
case 50:
- printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): CS asked for 5V, applying 3.3V..\n", __func__);
case 33:
break;
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
return -1;
}
- printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __FUNCTION__);
+ printk(KERN_WARNING "%s(): Warning, Can't perform reset\n", __func__);
/* Silently ignore Vpp, output enable, speaker enable. */
diff --git a/drivers/pcmcia/sa1100_simpad.c b/drivers/pcmcia/sa1100_simpad.c
index 04d6f7f..42567de 100644
--- a/drivers/pcmcia/sa1100_simpad.c
+++ b/drivers/pcmcia/sa1100_simpad.c
@@ -90,7 +90,7 @@
default:
printk(KERN_ERR "%s(): unrecognized Vcc %u\n",
- __FUNCTION__, state->Vcc);
+ __func__, state->Vcc);
clear_cs3_bit(VCC_3V_EN|VCC_5V_EN|EN0|EN1);
local_irq_restore(flags);
return -1;
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index aa7779d..420a775 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -37,6 +37,7 @@
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/mm.h>
+#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/spinlock.h>
@@ -353,7 +354,7 @@
(map->flags&MAP_PREFETCH)?"PREFETCH ":"");
if (map->map >= MAX_IO_WIN) {
- printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__,
+ printk(KERN_ERR "%s(): map (%d) out of range\n", __func__,
map->map);
return -1;
}
@@ -578,7 +579,7 @@
LIST_HEAD(soc_pcmcia_sockets);
-DECLARE_MUTEX(soc_pcmcia_sockets_lock);
+static DEFINE_MUTEX(soc_pcmcia_sockets_lock);
static const char *skt_names[] = {
"PCMCIA socket 0",
@@ -601,11 +602,11 @@
struct cpufreq_freqs *freqs = data;
int ret = 0;
- down(&soc_pcmcia_sockets_lock);
+ mutex_lock(&soc_pcmcia_sockets_lock);
list_for_each_entry(skt, &soc_pcmcia_sockets, node)
if ( skt->ops->frequency_change )
ret += skt->ops->frequency_change(skt, val, freqs);
- up(&soc_pcmcia_sockets_lock);
+ mutex_unlock(&soc_pcmcia_sockets_lock);
return ret;
}
@@ -642,7 +643,7 @@
struct soc_pcmcia_socket *skt;
int ret, i;
- down(&soc_pcmcia_sockets_lock);
+ mutex_lock(&soc_pcmcia_sockets_lock);
sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL);
if (!sinfo) {
@@ -782,7 +783,7 @@
kfree(sinfo);
out:
- up(&soc_pcmcia_sockets_lock);
+ mutex_unlock(&soc_pcmcia_sockets_lock);
return ret;
}
@@ -793,7 +794,7 @@
dev_set_drvdata(dev, NULL);
- down(&soc_pcmcia_sockets_lock);
+ mutex_lock(&soc_pcmcia_sockets_lock);
for (i = 0; i < sinfo->nskt; i++) {
struct soc_pcmcia_socket *skt = &sinfo->skt[i];
@@ -818,7 +819,7 @@
if (list_empty(&soc_pcmcia_sockets))
soc_pcmcia_cpufreq_unregister();
- up(&soc_pcmcia_sockets_lock);
+ mutex_unlock(&soc_pcmcia_sockets_lock);
kfree(sinfo);
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 6f14126..1edc1da 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -133,7 +133,6 @@
extern struct list_head soc_pcmcia_sockets;
-extern struct semaphore soc_pcmcia_sockets_lock;
extern int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr);
extern int soc_common_drv_pcmcia_remove(struct device *dev);
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index b440900..562384d 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -356,19 +356,23 @@
}
-static struct device_attribute *pccard_socket_attributes[] = {
- &dev_attr_card_type,
- &dev_attr_card_voltage,
- &dev_attr_card_vpp,
- &dev_attr_card_vcc,
- &dev_attr_card_insert,
- &dev_attr_card_pm_state,
- &dev_attr_card_eject,
- &dev_attr_card_irq_mask,
- &dev_attr_available_resources_setup_done,
+static struct attribute *pccard_socket_attributes[] = {
+ &dev_attr_card_type.attr,
+ &dev_attr_card_voltage.attr,
+ &dev_attr_card_vpp.attr,
+ &dev_attr_card_vcc.attr,
+ &dev_attr_card_insert.attr,
+ &dev_attr_card_pm_state.attr,
+ &dev_attr_card_eject.attr,
+ &dev_attr_card_irq_mask.attr,
+ &dev_attr_available_resources_setup_done.attr,
NULL,
};
+static const struct attribute_group socket_attrs = {
+ .attrs = pccard_socket_attributes,
+};
+
static struct bin_attribute pccard_cis_attr = {
.attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
.size = 0x200,
@@ -376,35 +380,21 @@
.write = pccard_store_cis,
};
-static int __devinit pccard_sysfs_add_socket(struct device *dev,
- struct class_interface *class_intf)
+int pccard_sysfs_add_socket(struct device *dev)
{
- struct device_attribute **attr;
int ret = 0;
- for (attr = pccard_socket_attributes; *attr; attr++) {
- ret = device_create_file(dev, *attr);
- if (ret)
- break;
- }
- if (!ret)
+ ret = sysfs_create_group(&dev->kobj, &socket_attrs);
+ if (!ret) {
ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
-
+ if (ret)
+ sysfs_remove_group(&dev->kobj, &socket_attrs);
+ }
return ret;
}
-static void __devexit pccard_sysfs_remove_socket(struct device *dev,
- struct class_interface *class_intf)
+void pccard_sysfs_remove_socket(struct device *dev)
{
- struct device_attribute **attr;
-
sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
- for (attr = pccard_socket_attributes; *attr; attr++)
- device_remove_file(dev, *attr);
+ sysfs_remove_group(&dev->kobj, &socket_attrs);
}
-
-struct class_interface pccard_sysfs_interface = {
- .class = &pcmcia_socket_class,
- .add_dev = &pccard_sysfs_add_socket,
- .remove_dev = __devexit_p(&pccard_sysfs_remove_socket),
-};
diff --git a/drivers/pnp/base.h b/drivers/pnp/base.h
index 31a633f..4fe7c58 100644
--- a/drivers/pnp/base.h
+++ b/drivers/pnp/base.h
@@ -1,12 +1,78 @@
extern spinlock_t pnp_lock;
void *pnp_alloc(long size);
+
+int pnp_register_protocol(struct pnp_protocol *protocol);
+void pnp_unregister_protocol(struct pnp_protocol *protocol);
+
+#define PNP_EISA_ID_MASK 0x7fffffff
+void pnp_eisa_id_to_string(u32 id, char *str);
+struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *, int id, char *pnpid);
+struct pnp_card *pnp_alloc_card(struct pnp_protocol *, int id, char *pnpid);
+
+int pnp_add_device(struct pnp_dev *dev);
+struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id);
int pnp_interface_attach_device(struct pnp_dev *dev);
+
+int pnp_add_card(struct pnp_card *card);
+struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id);
+void pnp_remove_card(struct pnp_card *card);
+int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev);
+void pnp_remove_card_device(struct pnp_dev *dev);
+
+struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
+struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
+ int priority);
+int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_irq *data);
+int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_dma *data);
+int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_port *data);
+int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_mem *data);
+void pnp_init_resources(struct pnp_dev *dev);
+
void pnp_fixup_device(struct pnp_dev *dev);
void pnp_free_option(struct pnp_option *option);
int __pnp_add_device(struct pnp_dev *dev);
void __pnp_remove_device(struct pnp_dev *dev);
-int pnp_check_port(struct pnp_dev * dev, int idx);
-int pnp_check_mem(struct pnp_dev * dev, int idx);
-int pnp_check_irq(struct pnp_dev * dev, int idx);
-int pnp_check_dma(struct pnp_dev * dev, int idx);
+int pnp_check_port(struct pnp_dev *dev, struct resource *res);
+int pnp_check_mem(struct pnp_dev *dev, struct resource *res);
+int pnp_check_irq(struct pnp_dev *dev, struct resource *res);
+int pnp_check_dma(struct pnp_dev *dev, struct resource *res);
+
+void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc);
+
+void pnp_init_resource(struct resource *res);
+
+struct pnp_resource *pnp_get_pnp_resource(struct pnp_dev *dev,
+ unsigned int type, unsigned int num);
+
+#define PNP_MAX_PORT 40
+#define PNP_MAX_MEM 24
+#define PNP_MAX_IRQ 2
+#define PNP_MAX_DMA 2
+
+struct pnp_resource {
+ struct resource res;
+ unsigned int index; /* ISAPNP config register index */
+};
+
+struct pnp_resource_table {
+ struct pnp_resource port[PNP_MAX_PORT];
+ struct pnp_resource mem[PNP_MAX_MEM];
+ struct pnp_resource dma[PNP_MAX_DMA];
+ struct pnp_resource irq[PNP_MAX_IRQ];
+};
+
+struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
+ int flags);
+struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
+ int flags);
+struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end, int flags);
+struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end, int flags);
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index da1c990..a762a41 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -5,6 +5,7 @@
*/
#include <linux/module.h>
+#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/pnp.h>
#include "base.h"
@@ -100,19 +101,33 @@
* @id: pointer to a pnp_id structure
* @card: pointer to the desired card
*/
-int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card)
+struct pnp_id *pnp_add_card_id(struct pnp_card *card, char *id)
{
- struct pnp_id *ptr;
+ struct pnp_id *dev_id, *ptr;
- id->next = NULL;
+ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ if (!dev_id)
+ return NULL;
+
+ dev_id->id[0] = id[0];
+ dev_id->id[1] = id[1];
+ dev_id->id[2] = id[2];
+ dev_id->id[3] = tolower(id[3]);
+ dev_id->id[4] = tolower(id[4]);
+ dev_id->id[5] = tolower(id[5]);
+ dev_id->id[6] = tolower(id[6]);
+ dev_id->id[7] = '\0';
+
+ dev_id->next = NULL;
ptr = card->id;
while (ptr && ptr->next)
ptr = ptr->next;
if (ptr)
- ptr->next = id;
+ ptr->next = dev_id;
else
- card->id = id;
- return 0;
+ card->id = dev_id;
+
+ return dev_id;
}
static void pnp_free_card_ids(struct pnp_card *card)
@@ -136,6 +151,31 @@
kfree(card);
}
+struct pnp_card *pnp_alloc_card(struct pnp_protocol *protocol, int id, char *pnpid)
+{
+ struct pnp_card *card;
+ struct pnp_id *dev_id;
+
+ card = kzalloc(sizeof(struct pnp_card), GFP_KERNEL);
+ if (!card)
+ return NULL;
+
+ card->protocol = protocol;
+ card->number = id;
+
+ card->dev.parent = &card->protocol->dev;
+ sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number,
+ card->number);
+
+ dev_id = pnp_add_card_id(card, pnpid);
+ if (!dev_id) {
+ kfree(card);
+ return NULL;
+ }
+
+ return card;
+}
+
static ssize_t pnp_show_card_name(struct device *dmdev,
struct device_attribute *attr, char *buf)
{
@@ -191,9 +231,6 @@
int error;
struct list_head *pos, *temp;
- sprintf(card->dev.bus_id, "%02x:%02x", card->protocol->number,
- card->number);
- card->dev.parent = &card->protocol->dev;
card->dev.bus = NULL;
card->dev.release = &pnp_release_card;
error = device_register(&card->dev);
diff --git a/drivers/pnp/core.c b/drivers/pnp/core.c
index 7d366ca..20771b7 100644
--- a/drivers/pnp/core.c
+++ b/drivers/pnp/core.c
@@ -106,18 +106,53 @@
pnp_free_option(dev->independent);
pnp_free_option(dev->dependent);
pnp_free_ids(dev);
+ kfree(dev->res);
kfree(dev);
}
+struct pnp_dev *pnp_alloc_dev(struct pnp_protocol *protocol, int id, char *pnpid)
+{
+ struct pnp_dev *dev;
+ struct pnp_id *dev_id;
+
+ dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->res = kzalloc(sizeof(struct pnp_resource_table), GFP_KERNEL);
+ if (!dev->res) {
+ kfree(dev);
+ return NULL;
+ }
+
+ dev->protocol = protocol;
+ dev->number = id;
+ dev->dma_mask = DMA_24BIT_MASK;
+
+ dev->dev.parent = &dev->protocol->dev;
+ dev->dev.bus = &pnp_bus_type;
+ dev->dev.dma_mask = &dev->dma_mask;
+ dev->dev.coherent_dma_mask = dev->dma_mask;
+ dev->dev.release = &pnp_release_device;
+
+ sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
+ dev->number);
+
+ dev_id = pnp_add_id(dev, pnpid);
+ if (!dev_id) {
+ kfree(dev->res);
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
int __pnp_add_device(struct pnp_dev *dev)
{
int ret;
pnp_fixup_device(dev);
- dev->dev.bus = &pnp_bus_type;
- dev->dev.dma_mask = &dev->dma_mask;
- dev->dma_mask = dev->dev.coherent_dma_mask = DMA_24BIT_MASK;
- dev->dev.release = &pnp_release_device;
dev->status = PNP_READY;
spin_lock(&pnp_lock);
list_add_tail(&dev->global_list, &pnp_global);
@@ -145,9 +180,6 @@
if (dev->card)
return -EINVAL;
- dev->dev.parent = &dev->protocol->dev;
- sprintf(dev->dev.bus_id, "%02x:%02x", dev->protocol->number,
- dev->number);
ret = __pnp_add_device(dev);
if (ret)
return ret;
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index e85cbf1..d3f869e 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -226,22 +226,36 @@
/**
* pnp_add_id - adds an EISA id to the specified device
- * @id: pointer to a pnp_id structure
* @dev: pointer to the desired device
+ * @id: pointer to an EISA id string
*/
-int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev)
+struct pnp_id *pnp_add_id(struct pnp_dev *dev, char *id)
{
- struct pnp_id *ptr;
+ struct pnp_id *dev_id, *ptr;
- id->next = NULL;
+ dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ if (!dev_id)
+ return NULL;
+
+ dev_id->id[0] = id[0];
+ dev_id->id[1] = id[1];
+ dev_id->id[2] = id[2];
+ dev_id->id[3] = tolower(id[3]);
+ dev_id->id[4] = tolower(id[4]);
+ dev_id->id[5] = tolower(id[5]);
+ dev_id->id[6] = tolower(id[6]);
+ dev_id->id[7] = '\0';
+
+ dev_id->next = NULL;
ptr = dev->id;
while (ptr && ptr->next)
ptr = ptr->next;
if (ptr)
- ptr->next = id;
+ ptr->next = dev_id;
else
- dev->id = id;
- return 0;
+ dev->id = dev_id;
+
+ return dev_id;
}
EXPORT_SYMBOL(pnp_register_driver);
diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c
index 9826584..5d9301de 100644
--- a/drivers/pnp/interface.c
+++ b/drivers/pnp/interface.c
@@ -248,6 +248,7 @@
char *buf)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
+ struct resource *res;
int i, ret;
pnp_info_buffer_t *buffer;
@@ -267,50 +268,46 @@
else
pnp_printf(buffer, "disabled\n");
- for (i = 0; i < PNP_MAX_PORT; i++) {
- if (pnp_port_valid(dev, i)) {
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
+ if (pnp_resource_valid(res)) {
pnp_printf(buffer, "io");
- if (pnp_port_flags(dev, i) & IORESOURCE_DISABLED)
+ if (res->flags & IORESOURCE_DISABLED)
pnp_printf(buffer, " disabled\n");
else
pnp_printf(buffer, " 0x%llx-0x%llx\n",
- (unsigned long long)
- pnp_port_start(dev, i),
- (unsigned long long)pnp_port_end(dev,
- i));
+ (unsigned long long) res->start,
+ (unsigned long long) res->end);
}
}
- for (i = 0; i < PNP_MAX_MEM; i++) {
- if (pnp_mem_valid(dev, i)) {
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
+ if (pnp_resource_valid(res)) {
pnp_printf(buffer, "mem");
- if (pnp_mem_flags(dev, i) & IORESOURCE_DISABLED)
+ if (res->flags & IORESOURCE_DISABLED)
pnp_printf(buffer, " disabled\n");
else
pnp_printf(buffer, " 0x%llx-0x%llx\n",
- (unsigned long long)
- pnp_mem_start(dev, i),
- (unsigned long long)pnp_mem_end(dev,
- i));
+ (unsigned long long) res->start,
+ (unsigned long long) res->end);
}
}
- for (i = 0; i < PNP_MAX_IRQ; i++) {
- if (pnp_irq_valid(dev, i)) {
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
+ if (pnp_resource_valid(res)) {
pnp_printf(buffer, "irq");
- if (pnp_irq_flags(dev, i) & IORESOURCE_DISABLED)
+ if (res->flags & IORESOURCE_DISABLED)
pnp_printf(buffer, " disabled\n");
else
pnp_printf(buffer, " %lld\n",
- (unsigned long long)pnp_irq(dev, i));
+ (unsigned long long) res->start);
}
}
- for (i = 0; i < PNP_MAX_DMA; i++) {
- if (pnp_dma_valid(dev, i)) {
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
+ if (pnp_resource_valid(res)) {
pnp_printf(buffer, "dma");
- if (pnp_dma_flags(dev, i) & IORESOURCE_DISABLED)
+ if (res->flags & IORESOURCE_DISABLED)
pnp_printf(buffer, " disabled\n");
else
pnp_printf(buffer, " %lld\n",
- (unsigned long long)pnp_dma(dev, i));
+ (unsigned long long) res->start);
}
}
ret = (buffer->curr - buf);
@@ -323,8 +320,10 @@
const char *ubuf, size_t count)
{
struct pnp_dev *dev = to_pnp_dev(dmdev);
+ struct pnp_resource *pnp_res;
char *buf = (void *)ubuf;
int retval = 0;
+ resource_size_t start, end;
if (dev->status & PNP_ATTACHED) {
retval = -EBUSY;
@@ -351,20 +350,20 @@
if (!strnicmp(buf, "auto", 4)) {
if (dev->active)
goto done;
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
retval = pnp_auto_config_dev(dev);
goto done;
}
if (!strnicmp(buf, "clear", 5)) {
if (dev->active)
goto done;
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
goto done;
}
if (!strnicmp(buf, "get", 3)) {
mutex_lock(&pnp_res_mutex);
if (pnp_can_read(dev))
- dev->protocol->get(dev, &dev->res);
+ dev->protocol->get(dev);
mutex_unlock(&pnp_res_mutex);
goto done;
}
@@ -373,7 +372,7 @@
if (dev->active)
goto done;
buf += 3;
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
mutex_lock(&pnp_res_mutex);
while (1) {
while (isspace(*buf))
@@ -382,76 +381,60 @@
buf += 2;
while (isspace(*buf))
++buf;
- dev->res.port_resource[nport].start =
- simple_strtoul(buf, &buf, 0);
+ start = simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
++buf;
if (*buf == '-') {
buf += 1;
while (isspace(*buf))
++buf;
- dev->res.port_resource[nport].end =
- simple_strtoul(buf, &buf, 0);
+ end = simple_strtoul(buf, &buf, 0);
} else
- dev->res.port_resource[nport].end =
- dev->res.port_resource[nport].start;
- dev->res.port_resource[nport].flags =
- IORESOURCE_IO;
- nport++;
- if (nport >= PNP_MAX_PORT)
- break;
+ end = start;
+ pnp_res = pnp_add_io_resource(dev, start, end,
+ 0);
+ if (pnp_res)
+ pnp_res->index = nport++;
continue;
}
if (!strnicmp(buf, "mem", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
- dev->res.mem_resource[nmem].start =
- simple_strtoul(buf, &buf, 0);
+ start = simple_strtoul(buf, &buf, 0);
while (isspace(*buf))
++buf;
if (*buf == '-') {
buf += 1;
while (isspace(*buf))
++buf;
- dev->res.mem_resource[nmem].end =
- simple_strtoul(buf, &buf, 0);
+ end = simple_strtoul(buf, &buf, 0);
} else
- dev->res.mem_resource[nmem].end =
- dev->res.mem_resource[nmem].start;
- dev->res.mem_resource[nmem].flags =
- IORESOURCE_MEM;
- nmem++;
- if (nmem >= PNP_MAX_MEM)
- break;
+ end = start;
+ pnp_res = pnp_add_mem_resource(dev, start, end,
+ 0);
+ if (pnp_res)
+ pnp_res->index = nmem++;
continue;
}
if (!strnicmp(buf, "irq", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
- dev->res.irq_resource[nirq].start =
- dev->res.irq_resource[nirq].end =
- simple_strtoul(buf, &buf, 0);
- dev->res.irq_resource[nirq].flags =
- IORESOURCE_IRQ;
- nirq++;
- if (nirq >= PNP_MAX_IRQ)
- break;
+ start = simple_strtoul(buf, &buf, 0);
+ pnp_res = pnp_add_irq_resource(dev, start, 0);
+ if (pnp_res)
+ nirq++;
continue;
}
if (!strnicmp(buf, "dma", 3)) {
buf += 3;
while (isspace(*buf))
++buf;
- dev->res.dma_resource[ndma].start =
- dev->res.dma_resource[ndma].end =
- simple_strtoul(buf, &buf, 0);
- dev->res.dma_resource[ndma].flags =
- IORESOURCE_DMA;
- ndma++;
- if (ndma >= PNP_MAX_DMA)
- break;
+ start = simple_strtoul(buf, &buf, 0);
+ pnp_res = pnp_add_dma_resource(dev, start, 0);
+ if (pnp_res)
+ pnp_res->index = ndma++;
continue;
}
break;
diff --git a/drivers/pnp/isapnp/Makefile b/drivers/pnp/isapnp/Makefile
index cac18bb..3e38f06 100644
--- a/drivers/pnp/isapnp/Makefile
+++ b/drivers/pnp/isapnp/Makefile
@@ -5,3 +5,7 @@
isapnp-proc-$(CONFIG_PROC_FS) = proc.o
obj-y := core.o compat.o $(isapnp-proc-y)
+
+ifeq ($(CONFIG_PNP_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index 257f5d8..f1bccdb 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -44,6 +44,8 @@
#include <linux/mutex.h>
#include <asm/io.h>
+#include "../base.h"
+
#if 0
#define ISAPNP_REGION_OK
#endif
@@ -88,6 +90,14 @@
#define _LTAG_MEM32RANGE 0x85
#define _LTAG_FIXEDMEM32RANGE 0x86
+/* Logical device control and configuration registers */
+
+#define ISAPNP_CFG_ACTIVATE 0x30 /* byte */
+#define ISAPNP_CFG_MEM 0x40 /* 4 * dword */
+#define ISAPNP_CFG_PORT 0x60 /* 8 * word */
+#define ISAPNP_CFG_IRQ 0x70 /* 2 * word */
+#define ISAPNP_CFG_DMA 0x74 /* 2 * byte */
+
/*
* Sizes of ISAPNP logical device configuration register sets.
* See PNP-ISA-v1.0a.pdf, Appendix A.
@@ -388,28 +398,6 @@
}
/*
- * Parse EISA id.
- */
-static void isapnp_parse_id(struct pnp_dev *dev, unsigned short vendor,
- unsigned short device)
-{
- struct pnp_id *id;
-
- if (!dev)
- return;
- id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
- if (!id)
- return;
- sprintf(id->id, "%c%c%c%x%x%x%x",
- 'A' + ((vendor >> 2) & 0x3f) - 1,
- 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
- 'A' + ((vendor >> 8) & 0x1f) - 1,
- (device >> 4) & 0x0f,
- device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
- pnp_add_id(id, dev);
-}
-
-/*
* Parse logical device tag.
*/
static struct pnp_dev *__init isapnp_parse_device(struct pnp_card *card,
@@ -417,30 +405,31 @@
{
unsigned char tmp[6];
struct pnp_dev *dev;
+ u32 eisa_id;
+ char id[8];
isapnp_peek(tmp, size);
- dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ eisa_id = tmp[0] | tmp[1] << 8 | tmp[2] << 16 | tmp[3] << 24;
+ pnp_eisa_id_to_string(eisa_id, id);
+
+ dev = pnp_alloc_dev(&isapnp_protocol, number, id);
if (!dev)
return NULL;
- dev->number = number;
- isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0], (tmp[3] << 8) | tmp[2]);
- dev->regs = tmp[4];
+
dev->card = card;
- if (size > 5)
- dev->regs |= tmp[5] << 8;
- dev->protocol = &isapnp_protocol;
dev->capabilities |= PNP_CONFIGURABLE;
dev->capabilities |= PNP_READ;
dev->capabilities |= PNP_WRITE;
dev->capabilities |= PNP_DISABLE;
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
return dev;
}
/*
* Add IRQ resource to resources list.
*/
-static void __init isapnp_parse_irq_resource(struct pnp_option *option,
+static void __init isapnp_parse_irq_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[3];
@@ -457,13 +446,14 @@
irq->flags = tmp[2];
else
irq->flags = IORESOURCE_IRQ_HIGHEDGE;
- pnp_register_irq_resource(option, irq);
+ pnp_register_irq_resource(dev, option, irq);
}
/*
* Add DMA resource to resources list.
*/
-static void __init isapnp_parse_dma_resource(struct pnp_option *option,
+static void __init isapnp_parse_dma_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[2];
@@ -475,13 +465,14 @@
return;
dma->map = tmp[0];
dma->flags = tmp[1];
- pnp_register_dma_resource(option, dma);
+ pnp_register_dma_resource(dev, option, dma);
}
/*
* Add port resource to resources list.
*/
-static void __init isapnp_parse_port_resource(struct pnp_option *option,
+static void __init isapnp_parse_port_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[7];
@@ -496,13 +487,14 @@
port->align = tmp[5];
port->size = tmp[6];
port->flags = tmp[0] ? PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
/*
* Add fixed port resource to resources list.
*/
-static void __init isapnp_parse_fixed_port_resource(struct pnp_option *option,
+static void __init isapnp_parse_fixed_port_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[3];
@@ -516,13 +508,14 @@
port->size = tmp[2];
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
/*
* Add memory resource to resources list.
*/
-static void __init isapnp_parse_mem_resource(struct pnp_option *option,
+static void __init isapnp_parse_mem_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[9];
@@ -537,13 +530,14 @@
mem->align = (tmp[6] << 8) | tmp[5];
mem->size = ((tmp[8] << 8) | tmp[7]) << 8;
mem->flags = tmp[0];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
/*
* Add 32-bit memory resource to resources list.
*/
-static void __init isapnp_parse_mem32_resource(struct pnp_option *option,
+static void __init isapnp_parse_mem32_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[17];
@@ -560,13 +554,14 @@
mem->size =
(tmp[16] << 24) | (tmp[15] << 16) | (tmp[14] << 8) | tmp[13];
mem->flags = tmp[0];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
/*
* Add 32-bit fixed memory resource to resources list.
*/
-static void __init isapnp_parse_fixed_mem32_resource(struct pnp_option *option,
+static void __init isapnp_parse_fixed_mem32_resource(struct pnp_dev *dev,
+ struct pnp_option *option,
int size)
{
unsigned char tmp[9];
@@ -581,7 +576,7 @@
mem->size = (tmp[8] << 24) | (tmp[7] << 16) | (tmp[6] << 8) | tmp[5];
mem->align = 0;
mem->flags = tmp[0];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
/*
@@ -613,6 +608,8 @@
unsigned char type, tmp[17];
struct pnp_option *option;
struct pnp_dev *dev;
+ u32 eisa_id;
+ char id[8];
if ((dev = isapnp_parse_device(card, size, number++)) == NULL)
return 1;
@@ -652,8 +649,10 @@
case _STAG_COMPATDEVID:
if (size == 4 && compat < DEVICE_COUNT_COMPATIBLE) {
isapnp_peek(tmp, 4);
- isapnp_parse_id(dev, (tmp[1] << 8) | tmp[0],
- (tmp[3] << 8) | tmp[2]);
+ eisa_id = tmp[0] | tmp[1] << 8 |
+ tmp[2] << 16 | tmp[3] << 24;
+ pnp_eisa_id_to_string(eisa_id, id);
+ pnp_add_id(dev, id);
compat++;
size = 0;
}
@@ -661,13 +660,13 @@
case _STAG_IRQ:
if (size < 2 || size > 3)
goto __skip;
- isapnp_parse_irq_resource(option, size);
+ isapnp_parse_irq_resource(dev, option, size);
size = 0;
break;
case _STAG_DMA:
if (size != 2)
goto __skip;
- isapnp_parse_dma_resource(option, size);
+ isapnp_parse_dma_resource(dev, option, size);
size = 0;
break;
case _STAG_STARTDEP:
@@ -687,17 +686,18 @@
if (size != 0)
goto __skip;
priority = 0;
+ dev_dbg(&dev->dev, "end dependent options\n");
break;
case _STAG_IOPORT:
if (size != 7)
goto __skip;
- isapnp_parse_port_resource(option, size);
+ isapnp_parse_port_resource(dev, option, size);
size = 0;
break;
case _STAG_FIXEDIO:
if (size != 3)
goto __skip;
- isapnp_parse_fixed_port_resource(option, size);
+ isapnp_parse_fixed_port_resource(dev, option, size);
size = 0;
break;
case _STAG_VENDOR:
@@ -705,7 +705,7 @@
case _LTAG_MEMRANGE:
if (size != 9)
goto __skip;
- isapnp_parse_mem_resource(option, size);
+ isapnp_parse_mem_resource(dev, option, size);
size = 0;
break;
case _LTAG_ANSISTR:
@@ -720,13 +720,13 @@
case _LTAG_MEM32RANGE:
if (size != 17)
goto __skip;
- isapnp_parse_mem32_resource(option, size);
+ isapnp_parse_mem32_resource(dev, option, size);
size = 0;
break;
case _LTAG_FIXEDMEM32RANGE:
if (size != 9)
goto __skip;
- isapnp_parse_fixed_mem32_resource(option, size);
+ isapnp_parse_fixed_mem32_resource(dev, option, size);
size = 0;
break;
case _STAG_END:
@@ -734,9 +734,8 @@
isapnp_skip_bytes(size);
return 1;
default:
- printk(KERN_ERR
- "isapnp: unexpected or unknown tag type 0x%x for logical device %i (device %i), ignored\n",
- type, dev->number, card->number);
+ dev_err(&dev->dev, "unknown tag %#x (card %i), "
+ "ignored\n", type, card->number);
}
__skip:
if (size > 0)
@@ -789,9 +788,8 @@
isapnp_skip_bytes(size);
return;
default:
- printk(KERN_ERR
- "isapnp: unexpected or unknown tag type 0x%x for device %i, ignored\n",
- type, card->number);
+ dev_err(&card->dev, "unknown tag %#x, ignored\n",
+ type);
}
__skip:
if (size > 0)
@@ -822,25 +820,6 @@
}
/*
- * Parse EISA id for ISA PnP card.
- */
-static void isapnp_parse_card_id(struct pnp_card *card, unsigned short vendor,
- unsigned short device)
-{
- struct pnp_id *id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
-
- if (!id)
- return;
- sprintf(id->id, "%c%c%c%x%x%x%x",
- 'A' + ((vendor >> 2) & 0x3f) - 1,
- 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
- 'A' + ((vendor >> 8) & 0x1f) - 1,
- (device >> 4) & 0x0f,
- device & 0x0f, (device >> 12) & 0x0f, (device >> 8) & 0x0f);
- pnp_add_card_id(id, card);
-}
-
-/*
* Build device list for all present ISA PnP devices.
*/
static int __init isapnp_build_device_list(void)
@@ -848,6 +827,8 @@
int csn;
unsigned char header[9], checksum;
struct pnp_card *card;
+ u32 eisa_id;
+ char id[8];
isapnp_wait();
isapnp_key();
@@ -855,32 +836,30 @@
isapnp_wake(csn);
isapnp_peek(header, 9);
checksum = isapnp_checksum(header);
+ eisa_id = header[0] | header[1] << 8 |
+ header[2] << 16 | header[3] << 24;
+ pnp_eisa_id_to_string(eisa_id, id);
+ card = pnp_alloc_card(&isapnp_protocol, csn, id);
+ if (!card)
+ continue;
+
#if 0
- printk(KERN_DEBUG
+ dev_info(&card->dev,
"vendor: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
header[0], header[1], header[2], header[3], header[4],
header[5], header[6], header[7], header[8]);
- printk(KERN_DEBUG "checksum = 0x%x\n", checksum);
+ dev_info(&card->dev, "checksum = %#x\n", checksum);
#endif
- if ((card =
- kzalloc(sizeof(struct pnp_card), GFP_KERNEL)) == NULL)
- continue;
-
- card->number = csn;
INIT_LIST_HEAD(&card->devices);
- isapnp_parse_card_id(card, (header[1] << 8) | header[0],
- (header[3] << 8) | header[2]);
card->serial =
(header[7] << 24) | (header[6] << 16) | (header[5] << 8) |
header[4];
isapnp_checksum_value = 0x00;
isapnp_parse_resource_map(card);
if (isapnp_checksum_value != 0x00)
- printk(KERN_ERR
- "isapnp: checksum for device %i is not valid (0x%x)\n",
- csn, isapnp_checksum_value);
+ dev_err(&card->dev, "invalid checksum %#x\n",
+ isapnp_checksum_value);
card->checksum = isapnp_checksum_value;
- card->protocol = &isapnp_protocol;
pnp_add_card(card);
}
@@ -947,100 +926,117 @@
EXPORT_SYMBOL(isapnp_cfg_end);
EXPORT_SYMBOL(isapnp_write_byte);
-static int isapnp_read_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int isapnp_get_resources(struct pnp_dev *dev)
{
- int tmp, ret;
+ struct pnp_resource *pnp_res;
+ int i, ret;
+ dev_dbg(&dev->dev, "get resources\n");
+ pnp_init_resources(dev);
+ isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = isapnp_read_byte(ISAPNP_CFG_ACTIVATE);
- if (dev->active) {
- for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) {
- ret = isapnp_read_word(ISAPNP_CFG_PORT + (tmp << 1));
- if (!ret)
- continue;
- res->port_resource[tmp].start = ret;
- res->port_resource[tmp].flags = IORESOURCE_IO;
- }
- for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) {
- ret =
- isapnp_read_word(ISAPNP_CFG_MEM + (tmp << 3)) << 8;
- if (!ret)
- continue;
- res->mem_resource[tmp].start = ret;
- res->mem_resource[tmp].flags = IORESOURCE_MEM;
- }
- for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) {
- ret =
- (isapnp_read_word(ISAPNP_CFG_IRQ + (tmp << 1)) >>
- 8);
- if (!ret)
- continue;
- res->irq_resource[tmp].start =
- res->irq_resource[tmp].end = ret;
- res->irq_resource[tmp].flags = IORESOURCE_IRQ;
- }
- for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) {
- ret = isapnp_read_byte(ISAPNP_CFG_DMA + tmp);
- if (ret == 4)
- continue;
- res->dma_resource[tmp].start =
- res->dma_resource[tmp].end = ret;
- res->dma_resource[tmp].flags = IORESOURCE_DMA;
+ if (!dev->active)
+ goto __end;
+
+ for (i = 0; i < ISAPNP_MAX_PORT; i++) {
+ ret = isapnp_read_word(ISAPNP_CFG_PORT + (i << 1));
+ if (ret) {
+ pnp_res = pnp_add_io_resource(dev, ret, ret, 0);
+ if (pnp_res)
+ pnp_res->index = i;
}
}
+ for (i = 0; i < ISAPNP_MAX_MEM; i++) {
+ ret = isapnp_read_word(ISAPNP_CFG_MEM + (i << 3)) << 8;
+ if (ret) {
+ pnp_res = pnp_add_mem_resource(dev, ret, ret, 0);
+ if (pnp_res)
+ pnp_res->index = i;
+ }
+ }
+ for (i = 0; i < ISAPNP_MAX_IRQ; i++) {
+ ret = isapnp_read_word(ISAPNP_CFG_IRQ + (i << 1)) >> 8;
+ if (ret) {
+ pnp_res = pnp_add_irq_resource(dev, ret, 0);
+ if (pnp_res)
+ pnp_res->index = i;
+ }
+ }
+ for (i = 0; i < ISAPNP_MAX_DMA; i++) {
+ ret = isapnp_read_byte(ISAPNP_CFG_DMA + i);
+ if (ret != 4) {
+ pnp_res = pnp_add_dma_resource(dev, ret, 0);
+ if (pnp_res)
+ pnp_res->index = i;
+ }
+ }
+
+__end:
+ isapnp_cfg_end();
return 0;
}
-static int isapnp_get_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int isapnp_set_resources(struct pnp_dev *dev)
{
- int ret;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ int tmp, index;
- pnp_init_resource_table(res);
- isapnp_cfg_begin(dev->card->number, dev->number);
- ret = isapnp_read_resources(dev, res);
- isapnp_cfg_end();
- return ret;
-}
-
-static int isapnp_set_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
-{
- int tmp;
-
+ dev_dbg(&dev->dev, "set resources\n");
isapnp_cfg_begin(dev->card->number, dev->number);
dev->active = 1;
- for (tmp = 0;
- tmp < ISAPNP_MAX_PORT
- && (res->port_resource[tmp].
- flags & (IORESOURCE_IO | IORESOURCE_UNSET)) == IORESOURCE_IO;
- tmp++)
- isapnp_write_word(ISAPNP_CFG_PORT + (tmp << 1),
- res->port_resource[tmp].start);
- for (tmp = 0;
- tmp < ISAPNP_MAX_IRQ
- && (res->irq_resource[tmp].
- flags & (IORESOURCE_IRQ | IORESOURCE_UNSET)) == IORESOURCE_IRQ;
- tmp++) {
- int irq = res->irq_resource[tmp].start;
- if (irq == 2)
- irq = 9;
- isapnp_write_byte(ISAPNP_CFG_IRQ + (tmp << 1), irq);
+ for (tmp = 0; tmp < ISAPNP_MAX_PORT; tmp++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, tmp);
+ if (!pnp_res)
+ continue;
+ res = &pnp_res->res;
+ if (pnp_resource_valid(res)) {
+ index = pnp_res->index;
+ dev_dbg(&dev->dev, " set io %d to %#llx\n",
+ index, (unsigned long long) res->start);
+ isapnp_write_word(ISAPNP_CFG_PORT + (index << 1),
+ res->start);
+ }
}
- for (tmp = 0;
- tmp < ISAPNP_MAX_DMA
- && (res->dma_resource[tmp].
- flags & (IORESOURCE_DMA | IORESOURCE_UNSET)) == IORESOURCE_DMA;
- tmp++)
- isapnp_write_byte(ISAPNP_CFG_DMA + tmp,
- res->dma_resource[tmp].start);
- for (tmp = 0;
- tmp < ISAPNP_MAX_MEM
- && (res->mem_resource[tmp].
- flags & (IORESOURCE_MEM | IORESOURCE_UNSET)) == IORESOURCE_MEM;
- tmp++)
- isapnp_write_word(ISAPNP_CFG_MEM + (tmp << 3),
- (res->mem_resource[tmp].start >> 8) & 0xffff);
+ for (tmp = 0; tmp < ISAPNP_MAX_IRQ; tmp++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, tmp);
+ if (!pnp_res)
+ continue;
+ res = &pnp_res->res;
+ if (pnp_resource_valid(res)) {
+ int irq = res->start;
+ if (irq == 2)
+ irq = 9;
+ index = pnp_res->index;
+ dev_dbg(&dev->dev, " set irq %d to %d\n", index, irq);
+ isapnp_write_byte(ISAPNP_CFG_IRQ + (index << 1), irq);
+ }
+ }
+ for (tmp = 0; tmp < ISAPNP_MAX_DMA; tmp++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, tmp);
+ if (!pnp_res)
+ continue;
+ res = &pnp_res->res;
+ if (pnp_resource_valid(res)) {
+ index = pnp_res->index;
+ dev_dbg(&dev->dev, " set dma %d to %lld\n",
+ index, (unsigned long long) res->start);
+ isapnp_write_byte(ISAPNP_CFG_DMA + index, res->start);
+ }
+ }
+ for (tmp = 0; tmp < ISAPNP_MAX_MEM; tmp++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, tmp);
+ if (!pnp_res)
+ continue;
+ res = &pnp_res->res;
+ if (pnp_resource_valid(res)) {
+ index = pnp_res->index;
+ dev_dbg(&dev->dev, " set mem %d to %#llx\n",
+ index, (unsigned long long) res->start);
+ isapnp_write_word(ISAPNP_CFG_MEM + (index << 3),
+ (res->start >> 8) & 0xffff);
+ }
+ }
/* FIXME: We aren't handling 32bit mems properly here */
isapnp_activate(dev->number);
isapnp_cfg_end();
@@ -1138,13 +1134,13 @@
protocol_for_each_card(&isapnp_protocol, card) {
cards++;
if (isapnp_verbose) {
- printk(KERN_INFO "isapnp: Card '%s'\n",
- card->name[0] ? card->name : "Unknown");
+ dev_info(&card->dev, "card '%s'\n",
+ card->name[0] ? card->name : "unknown");
if (isapnp_verbose < 2)
continue;
card_for_each_dev(card, dev) {
- printk(KERN_INFO "isapnp: Device '%s'\n",
- dev->name[0] ? dev->name : "Unknown");
+ dev_info(&card->dev, "device '%s'\n",
+ dev->name[0] ? dev->name : "unknown");
}
}
}
diff --git a/drivers/pnp/isapnp/proc.c b/drivers/pnp/isapnp/proc.c
index 2b8266c..3f94eda 100644
--- a/drivers/pnp/isapnp/proc.c
+++ b/drivers/pnp/isapnp/proc.c
@@ -85,6 +85,7 @@
}
static const struct file_operations isapnp_proc_bus_file_operations = {
+ .owner = THIS_MODULE,
.llseek = isapnp_proc_bus_lseek,
.read = isapnp_proc_bus_read,
};
@@ -102,12 +103,10 @@
return -ENOMEM;
}
sprintf(name, "%02x", dev->number);
- e = dev->procent = create_proc_entry(name, S_IFREG | S_IRUGO, de);
+ e = dev->procent = proc_create_data(name, S_IFREG | S_IRUGO, de,
+ &isapnp_proc_bus_file_operations, dev);
if (!e)
return -ENOMEM;
- e->proc_fops = &isapnp_proc_bus_file_operations;
- e->owner = THIS_MODULE;
- e->data = dev;
e->size = 256;
return 0;
}
@@ -116,7 +115,7 @@
{
struct pnp_dev *dev;
- isapnp_proc_bus_dir = proc_mkdir("isapnp", proc_bus);
+ isapnp_proc_bus_dir = proc_mkdir("bus/isapnp", NULL);
protocol_for_each_dev(&isapnp_protocol, dev) {
isapnp_proc_attach_device(dev);
}
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index c28caf2..bea0914 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -19,100 +19,118 @@
static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
- if (idx >= PNP_MAX_PORT) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, idx);
+ if (!pnp_res) {
dev_err(&dev->dev, "too many I/O port resources\n");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
- /* check if this resource has been manually set, if so skip */
- if (!(dev->res.port_resource[idx].flags & IORESOURCE_AUTO))
- return 1;
+ res = &pnp_res->res;
- start = &dev->res.port_resource[idx].start;
- end = &dev->res.port_resource[idx].end;
- flags = &dev->res.port_resource[idx].flags;
+ /* check if this resource has been manually set, if so skip */
+ if (!(res->flags & IORESOURCE_AUTO)) {
+ dev_dbg(&dev->dev, " io %d already set to %#llx-%#llx "
+ "flags %#lx\n", idx, (unsigned long long) res->start,
+ (unsigned long long) res->end, res->flags);
+ return 1;
+ }
/* set the initial values */
- *flags |= rule->flags | IORESOURCE_IO;
- *flags &= ~IORESOURCE_UNSET;
+ pnp_res->index = idx;
+ res->flags |= rule->flags | IORESOURCE_IO;
+ res->flags &= ~IORESOURCE_UNSET;
if (!rule->size) {
- *flags |= IORESOURCE_DISABLED;
+ res->flags |= IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " io %d disabled\n", idx);
return 1; /* skip disabled resource requests */
}
- *start = rule->min;
- *end = *start + rule->size - 1;
+ res->start = rule->min;
+ res->end = res->start + rule->size - 1;
/* run through until pnp_check_port is happy */
- while (!pnp_check_port(dev, idx)) {
- *start += rule->align;
- *end = *start + rule->size - 1;
- if (*start > rule->max || !rule->align)
+ while (!pnp_check_port(dev, res)) {
+ res->start += rule->align;
+ res->end = res->start + rule->size - 1;
+ if (res->start > rule->max || !rule->align) {
+ dev_dbg(&dev->dev, " couldn't assign io %d\n", idx);
return 0;
+ }
}
+ dev_dbg(&dev->dev, " assign io %d %#llx-%#llx\n", idx,
+ (unsigned long long) res->start, (unsigned long long) res->end);
return 1;
}
static int pnp_assign_mem(struct pnp_dev *dev, struct pnp_mem *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
- if (idx >= PNP_MAX_MEM) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, idx);
+ if (!pnp_res) {
dev_err(&dev->dev, "too many memory resources\n");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
- /* check if this resource has been manually set, if so skip */
- if (!(dev->res.mem_resource[idx].flags & IORESOURCE_AUTO))
- return 1;
+ res = &pnp_res->res;
- start = &dev->res.mem_resource[idx].start;
- end = &dev->res.mem_resource[idx].end;
- flags = &dev->res.mem_resource[idx].flags;
+ /* check if this resource has been manually set, if so skip */
+ if (!(res->flags & IORESOURCE_AUTO)) {
+ dev_dbg(&dev->dev, " mem %d already set to %#llx-%#llx "
+ "flags %#lx\n", idx, (unsigned long long) res->start,
+ (unsigned long long) res->end, res->flags);
+ return 1;
+ }
/* set the initial values */
- *flags |= rule->flags | IORESOURCE_MEM;
- *flags &= ~IORESOURCE_UNSET;
+ pnp_res->index = idx;
+ res->flags |= rule->flags | IORESOURCE_MEM;
+ res->flags &= ~IORESOURCE_UNSET;
/* convert pnp flags to standard Linux flags */
if (!(rule->flags & IORESOURCE_MEM_WRITEABLE))
- *flags |= IORESOURCE_READONLY;
+ res->flags |= IORESOURCE_READONLY;
if (rule->flags & IORESOURCE_MEM_CACHEABLE)
- *flags |= IORESOURCE_CACHEABLE;
+ res->flags |= IORESOURCE_CACHEABLE;
if (rule->flags & IORESOURCE_MEM_RANGELENGTH)
- *flags |= IORESOURCE_RANGELENGTH;
+ res->flags |= IORESOURCE_RANGELENGTH;
if (rule->flags & IORESOURCE_MEM_SHADOWABLE)
- *flags |= IORESOURCE_SHADOWABLE;
+ res->flags |= IORESOURCE_SHADOWABLE;
if (!rule->size) {
- *flags |= IORESOURCE_DISABLED;
+ res->flags |= IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " mem %d disabled\n", idx);
return 1; /* skip disabled resource requests */
}
- *start = rule->min;
- *end = *start + rule->size - 1;
+ res->start = rule->min;
+ res->end = res->start + rule->size - 1;
/* run through until pnp_check_mem is happy */
- while (!pnp_check_mem(dev, idx)) {
- *start += rule->align;
- *end = *start + rule->size - 1;
- if (*start > rule->max || !rule->align)
+ while (!pnp_check_mem(dev, res)) {
+ res->start += rule->align;
+ res->end = res->start + rule->size - 1;
+ if (res->start > rule->max || !rule->align) {
+ dev_dbg(&dev->dev, " couldn't assign mem %d\n", idx);
return 0;
+ }
}
+ dev_dbg(&dev->dev, " assign mem %d %#llx-%#llx\n", idx,
+ (unsigned long long) res->start, (unsigned long long) res->end);
return 1;
}
static int pnp_assign_irq(struct pnp_dev *dev, struct pnp_irq *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
int i;
/* IRQ priority: this table is good for i386 */
@@ -120,49 +138,59 @@
5, 10, 11, 12, 9, 14, 15, 7, 3, 4, 13, 0, 1, 6, 8, 2
};
- if (idx >= PNP_MAX_IRQ) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, idx);
+ if (!pnp_res) {
dev_err(&dev->dev, "too many IRQ resources\n");
/* pretend we were successful so at least the manager won't try again */
return 1;
}
- /* check if this resource has been manually set, if so skip */
- if (!(dev->res.irq_resource[idx].flags & IORESOURCE_AUTO))
- return 1;
+ res = &pnp_res->res;
- start = &dev->res.irq_resource[idx].start;
- end = &dev->res.irq_resource[idx].end;
- flags = &dev->res.irq_resource[idx].flags;
+ /* check if this resource has been manually set, if so skip */
+ if (!(res->flags & IORESOURCE_AUTO)) {
+ dev_dbg(&dev->dev, " irq %d already set to %d flags %#lx\n",
+ idx, (int) res->start, res->flags);
+ return 1;
+ }
/* set the initial values */
- *flags |= rule->flags | IORESOURCE_IRQ;
- *flags &= ~IORESOURCE_UNSET;
+ pnp_res->index = idx;
+ res->flags |= rule->flags | IORESOURCE_IRQ;
+ res->flags &= ~IORESOURCE_UNSET;
if (bitmap_empty(rule->map, PNP_IRQ_NR)) {
- *flags |= IORESOURCE_DISABLED;
+ res->flags |= IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " irq %d disabled\n", idx);
return 1; /* skip disabled resource requests */
}
/* TBD: need check for >16 IRQ */
- *start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
- if (*start < PNP_IRQ_NR) {
- *end = *start;
+ res->start = find_next_bit(rule->map, PNP_IRQ_NR, 16);
+ if (res->start < PNP_IRQ_NR) {
+ res->end = res->start;
+ dev_dbg(&dev->dev, " assign irq %d %d\n", idx,
+ (int) res->start);
return 1;
}
for (i = 0; i < 16; i++) {
if (test_bit(xtab[i], rule->map)) {
- *start = *end = xtab[i];
- if (pnp_check_irq(dev, idx))
+ res->start = res->end = xtab[i];
+ if (pnp_check_irq(dev, res)) {
+ dev_dbg(&dev->dev, " assign irq %d %d\n", idx,
+ (int) res->start);
return 1;
+ }
}
}
+ dev_dbg(&dev->dev, " couldn't assign irq %d\n", idx);
return 0;
}
static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
{
- resource_size_t *start, *end;
- unsigned long *flags;
+ struct pnp_resource *pnp_res;
+ struct resource *res;
int i;
/* DMA priority: this table is good for i386 */
@@ -170,71 +198,89 @@
1, 3, 5, 6, 7, 0, 2, 4
};
- if (idx >= PNP_MAX_DMA) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, idx);
+ if (!pnp_res) {
dev_err(&dev->dev, "too many DMA resources\n");
return;
}
- /* check if this resource has been manually set, if so skip */
- if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
- return;
+ res = &pnp_res->res;
- start = &dev->res.dma_resource[idx].start;
- end = &dev->res.dma_resource[idx].end;
- flags = &dev->res.dma_resource[idx].flags;
+ /* check if this resource has been manually set, if so skip */
+ if (!(res->flags & IORESOURCE_AUTO)) {
+ dev_dbg(&dev->dev, " dma %d already set to %d flags %#lx\n",
+ idx, (int) res->start, res->flags);
+ return;
+ }
/* set the initial values */
- *flags |= rule->flags | IORESOURCE_DMA;
- *flags &= ~IORESOURCE_UNSET;
+ pnp_res->index = idx;
+ res->flags |= rule->flags | IORESOURCE_DMA;
+ res->flags &= ~IORESOURCE_UNSET;
for (i = 0; i < 8; i++) {
if (rule->map & (1 << xtab[i])) {
- *start = *end = xtab[i];
- if (pnp_check_dma(dev, idx))
+ res->start = res->end = xtab[i];
+ if (pnp_check_dma(dev, res)) {
+ dev_dbg(&dev->dev, " assign dma %d %d\n", idx,
+ (int) res->start);
return;
+ }
}
}
#ifdef MAX_DMA_CHANNELS
- *start = *end = MAX_DMA_CHANNELS;
+ res->start = res->end = MAX_DMA_CHANNELS;
#endif
- *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ dev_dbg(&dev->dev, " disable dma %d\n", idx);
+}
+
+void pnp_init_resource(struct resource *res)
+{
+ unsigned long type;
+
+ type = res->flags & (IORESOURCE_IO | IORESOURCE_MEM |
+ IORESOURCE_IRQ | IORESOURCE_DMA);
+
+ res->name = NULL;
+ res->flags = type | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ if (type == IORESOURCE_IRQ || type == IORESOURCE_DMA) {
+ res->start = -1;
+ res->end = -1;
+ } else {
+ res->start = 0;
+ res->end = 0;
+ }
}
/**
* pnp_init_resources - Resets a resource table to default values.
* @table: pointer to the desired resource table
*/
-void pnp_init_resource_table(struct pnp_resource_table *table)
+void pnp_init_resources(struct pnp_dev *dev)
{
+ struct resource *res;
int idx;
for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
- table->irq_resource[idx].name = NULL;
- table->irq_resource[idx].start = -1;
- table->irq_resource[idx].end = -1;
- table->irq_resource[idx].flags =
- IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->irq[idx].res;
+ res->flags = IORESOURCE_IRQ;
+ pnp_init_resource(res);
}
for (idx = 0; idx < PNP_MAX_DMA; idx++) {
- table->dma_resource[idx].name = NULL;
- table->dma_resource[idx].start = -1;
- table->dma_resource[idx].end = -1;
- table->dma_resource[idx].flags =
- IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->dma[idx].res;
+ res->flags = IORESOURCE_DMA;
+ pnp_init_resource(res);
}
for (idx = 0; idx < PNP_MAX_PORT; idx++) {
- table->port_resource[idx].name = NULL;
- table->port_resource[idx].start = 0;
- table->port_resource[idx].end = 0;
- table->port_resource[idx].flags =
- IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->port[idx].res;
+ res->flags = IORESOURCE_IO;
+ pnp_init_resource(res);
}
for (idx = 0; idx < PNP_MAX_MEM; idx++) {
- table->mem_resource[idx].name = NULL;
- table->mem_resource[idx].start = 0;
- table->mem_resource[idx].end = 0;
- table->mem_resource[idx].flags =
- IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->mem[idx].res;
+ res->flags = IORESOURCE_MEM;
+ pnp_init_resource(res);
}
}
@@ -242,41 +288,38 @@
* pnp_clean_resources - clears resources that were not manually set
* @res: the resources to clean
*/
-static void pnp_clean_resource_table(struct pnp_resource_table *res)
+static void pnp_clean_resource_table(struct pnp_dev *dev)
{
+ struct resource *res;
int idx;
for (idx = 0; idx < PNP_MAX_IRQ; idx++) {
- if (!(res->irq_resource[idx].flags & IORESOURCE_AUTO))
- continue;
- res->irq_resource[idx].start = -1;
- res->irq_resource[idx].end = -1;
- res->irq_resource[idx].flags =
- IORESOURCE_IRQ | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->irq[idx].res;
+ if (res->flags & IORESOURCE_AUTO) {
+ res->flags = IORESOURCE_IRQ;
+ pnp_init_resource(res);
+ }
}
for (idx = 0; idx < PNP_MAX_DMA; idx++) {
- if (!(res->dma_resource[idx].flags & IORESOURCE_AUTO))
- continue;
- res->dma_resource[idx].start = -1;
- res->dma_resource[idx].end = -1;
- res->dma_resource[idx].flags =
- IORESOURCE_DMA | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->dma[idx].res;
+ if (res->flags & IORESOURCE_AUTO) {
+ res->flags = IORESOURCE_DMA;
+ pnp_init_resource(res);
+ }
}
for (idx = 0; idx < PNP_MAX_PORT; idx++) {
- if (!(res->port_resource[idx].flags & IORESOURCE_AUTO))
- continue;
- res->port_resource[idx].start = 0;
- res->port_resource[idx].end = 0;
- res->port_resource[idx].flags =
- IORESOURCE_IO | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->port[idx].res;
+ if (res->flags & IORESOURCE_AUTO) {
+ res->flags = IORESOURCE_IO;
+ pnp_init_resource(res);
+ }
}
for (idx = 0; idx < PNP_MAX_MEM; idx++) {
- if (!(res->mem_resource[idx].flags & IORESOURCE_AUTO))
- continue;
- res->mem_resource[idx].start = 0;
- res->mem_resource[idx].end = 0;
- res->mem_resource[idx].flags =
- IORESOURCE_MEM | IORESOURCE_AUTO | IORESOURCE_UNSET;
+ res = &dev->res->mem[idx].res;
+ if (res->flags & IORESOURCE_AUTO) {
+ res->flags = IORESOURCE_MEM;
+ pnp_init_resource(res);
+ }
}
}
@@ -298,9 +341,11 @@
if (!pnp_can_configure(dev))
return -ENODEV;
+ dbg_pnp_show_resources(dev, "before pnp_assign_resources");
mutex_lock(&pnp_res_mutex);
- pnp_clean_resource_table(&dev->res); /* start with a fresh slate */
+ pnp_clean_resource_table(dev);
if (dev->independent) {
+ dev_dbg(&dev->dev, "assigning independent options\n");
port = dev->independent->port;
mem = dev->independent->mem;
irq = dev->independent->irq;
@@ -333,6 +378,8 @@
if (depnum) {
struct pnp_option *dep;
int i;
+
+ dev_dbg(&dev->dev, "assigning dependent option %d\n", depnum);
for (i = 1, dep = dev->dependent; i < depnum;
i++, dep = dep->next)
if (!dep)
@@ -368,68 +415,17 @@
goto fail;
mutex_unlock(&pnp_res_mutex);
+ dbg_pnp_show_resources(dev, "after pnp_assign_resources");
return 1;
fail:
- pnp_clean_resource_table(&dev->res);
+ pnp_clean_resource_table(dev);
mutex_unlock(&pnp_res_mutex);
+ dbg_pnp_show_resources(dev, "after pnp_assign_resources (failed)");
return 0;
}
/**
- * pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
- * @dev: pointer to the desired device
- * @res: pointer to the new resource config
- * @mode: 0 or PNP_CONFIG_FORCE
- *
- * This function can be used by drivers that want to manually set thier resources.
- */
-int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
- int mode)
-{
- int i;
- struct pnp_resource_table *bak;
-
- if (!pnp_can_configure(dev))
- return -ENODEV;
- bak = pnp_alloc(sizeof(struct pnp_resource_table));
- if (!bak)
- return -ENOMEM;
- *bak = dev->res;
-
- mutex_lock(&pnp_res_mutex);
- dev->res = *res;
- if (!(mode & PNP_CONFIG_FORCE)) {
- for (i = 0; i < PNP_MAX_PORT; i++) {
- if (!pnp_check_port(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_MEM; i++) {
- if (!pnp_check_mem(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_IRQ; i++) {
- if (!pnp_check_irq(dev, i))
- goto fail;
- }
- for (i = 0; i < PNP_MAX_DMA; i++) {
- if (!pnp_check_dma(dev, i))
- goto fail;
- }
- }
- mutex_unlock(&pnp_res_mutex);
-
- kfree(bak);
- return 0;
-
-fail:
- dev->res = *bak;
- mutex_unlock(&pnp_res_mutex);
- kfree(bak);
- return -EINVAL;
-}
-
-/**
* pnp_auto_config_dev - automatically assigns resources to a device
* @dev: pointer to the desired device
*/
@@ -473,7 +469,8 @@
return -EINVAL;
}
- if (dev->protocol->set(dev, &dev->res) < 0) {
+ dbg_pnp_show_resources(dev, "pnp_start_dev");
+ if (dev->protocol->set(dev) < 0) {
dev_err(&dev->dev, "activation failed\n");
return -EIO;
}
@@ -549,30 +546,13 @@
/* release the resources so that other devices can use them */
mutex_lock(&pnp_res_mutex);
- pnp_clean_resource_table(&dev->res);
+ pnp_clean_resource_table(dev);
mutex_unlock(&pnp_res_mutex);
return 0;
}
-/**
- * pnp_resource_change - change one resource
- * @resource: pointer to resource to be changed
- * @start: start of region
- * @size: size of region
- */
-void pnp_resource_change(struct resource *resource, resource_size_t start,
- resource_size_t size)
-{
- resource->flags &= ~(IORESOURCE_AUTO | IORESOURCE_UNSET);
- resource->start = start;
- resource->end = start + size - 1;
-}
-
-EXPORT_SYMBOL(pnp_manual_config_dev);
EXPORT_SYMBOL(pnp_start_dev);
EXPORT_SYMBOL(pnp_stop_dev);
EXPORT_SYMBOL(pnp_activate_dev);
EXPORT_SYMBOL(pnp_disable_dev);
-EXPORT_SYMBOL(pnp_resource_change);
-EXPORT_SYMBOL(pnp_init_resource_table);
diff --git a/drivers/pnp/pnpacpi/Makefile b/drivers/pnp/pnpacpi/Makefile
index 905326f..2d7a1e6 100644
--- a/drivers/pnp/pnpacpi/Makefile
+++ b/drivers/pnp/pnpacpi/Makefile
@@ -3,3 +3,7 @@
#
obj-y := core.o rsparser.o
+
+ifeq ($(CONFIG_PNP_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index c283a9a..5090277 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -25,6 +25,7 @@
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>
+#include "../base.h"
#include "pnpacpi.h"
static int num = 0;
@@ -44,7 +45,7 @@
{"", 0},
};
-static inline int is_exclusive_device(struct acpi_device *dev)
+static inline int __init is_exclusive_device(struct acpi_device *dev)
{
return (!acpi_match_device_ids(dev, excluded_id_list));
}
@@ -72,40 +73,24 @@
return 1;
}
-static void __init pnpidacpi_to_pnpid(char *id, char *str)
+static int pnpacpi_get_resources(struct pnp_dev *dev)
{
- str[0] = id[0];
- str[1] = id[1];
- str[2] = id[2];
- str[3] = tolower(id[3]);
- str[4] = tolower(id[4]);
- str[5] = tolower(id[5]);
- str[6] = tolower(id[6]);
- str[7] = '\0';
+ dev_dbg(&dev->dev, "get resources\n");
+ return pnpacpi_parse_allocated_resource(dev);
}
-static int pnpacpi_get_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
-{
- acpi_status status;
-
- status = pnpacpi_parse_allocated_resource((acpi_handle) dev->data,
- &dev->res);
- return ACPI_FAILURE(status) ? -ENODEV : 0;
-}
-
-static int pnpacpi_set_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int pnpacpi_set_resources(struct pnp_dev *dev)
{
acpi_handle handle = dev->data;
struct acpi_buffer buffer;
- int ret = 0;
+ int ret;
acpi_status status;
- ret = pnpacpi_build_resource_template(handle, &buffer);
+ dev_dbg(&dev->dev, "set resources\n");
+ ret = pnpacpi_build_resource_template(dev, &buffer);
if (ret)
return ret;
- ret = pnpacpi_encode_resources(res, &buffer);
+ ret = pnpacpi_encode_resources(dev, &buffer);
if (ret) {
kfree(buffer.pointer);
return ret;
@@ -163,7 +148,6 @@
{
acpi_handle temp = NULL;
acpi_status status;
- struct pnp_id *dev_id;
struct pnp_dev *dev;
status = acpi_get_handle(device->handle, "_CRS", &temp);
@@ -171,11 +155,10 @@
is_exclusive_device(device))
return 0;
- dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
- if (!dev) {
- pnp_err("Out of memory");
+ dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device));
+ if (!dev)
return -ENOMEM;
- }
+
dev->data = device->handle;
/* .enabled means the device can decode the resources */
dev->active = device->status.enabled;
@@ -191,44 +174,17 @@
if (ACPI_SUCCESS(status))
dev->capabilities |= PNP_DISABLE;
- dev->protocol = &pnpacpi_protocol;
-
if (strlen(acpi_device_name(device)))
strncpy(dev->name, acpi_device_name(device), sizeof(dev->name));
else
strncpy(dev->name, acpi_device_bid(device), sizeof(dev->name));
- dev->number = num;
+ if (dev->active)
+ pnpacpi_parse_allocated_resource(dev);
- /* set the initial values for the PnP device */
- dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
- if (!dev_id)
- goto err;
- pnpidacpi_to_pnpid(acpi_device_hid(device), dev_id->id);
- pnp_add_id(dev_id, dev);
+ if (dev->capabilities & PNP_CONFIGURABLE)
+ pnpacpi_parse_resource_option_data(dev);
- if (dev->active) {
- /* parse allocated resource */
- status = pnpacpi_parse_allocated_resource(device->handle,
- &dev->res);
- if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- pnp_err("PnPACPI: METHOD_NAME__CRS failure for %s",
- dev_id->id);
- goto err1;
- }
- }
-
- if (dev->capabilities & PNP_CONFIGURABLE) {
- status = pnpacpi_parse_resource_option_data(device->handle,
- dev);
- if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
- pnp_err("PnPACPI: METHOD_NAME__PRS failure for %s",
- dev_id->id);
- goto err1;
- }
- }
-
- /* parse compatible ids */
if (device->flags.compatible_ids) {
struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
int i;
@@ -236,27 +192,17 @@
for (i = 0; i < cid_list->count; i++) {
if (!ispnpidacpi(cid_list->id[i].value))
continue;
- dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
- if (!dev_id)
- continue;
-
- pnpidacpi_to_pnpid(cid_list->id[i].value, dev_id->id);
- pnp_add_id(dev_id, dev);
+ pnp_add_id(dev, cid_list->id[i].value);
}
}
/* clear out the damaged flags */
if (!dev->active)
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
pnp_add_device(dev);
num++;
return AE_OK;
-err1:
- kfree(dev_id);
-err:
- kfree(dev);
- return -EINVAL;
}
static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
diff --git a/drivers/pnp/pnpacpi/pnpacpi.h b/drivers/pnp/pnpacpi/pnpacpi.h
index f28e2ed..3e60225 100644
--- a/drivers/pnp/pnpacpi/pnpacpi.h
+++ b/drivers/pnp/pnpacpi/pnpacpi.h
@@ -5,8 +5,8 @@
#include <linux/acpi.h>
#include <linux/pnp.h>
-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 *);
-int pnpacpi_build_resource_template(acpi_handle, struct acpi_buffer*);
+int pnpacpi_parse_allocated_resource(struct pnp_dev *);
+int pnpacpi_parse_resource_option_data(struct pnp_dev *);
+int pnpacpi_encode_resources(struct pnp_dev *, struct acpi_buffer *);
+int pnpacpi_build_resource_template(struct pnp_dev *, struct acpi_buffer *);
#endif
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 98cbc9f..0201c8a 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -21,6 +21,8 @@
#include <linux/kernel.h>
#include <linux/acpi.h>
#include <linux/pci.h>
+#include <linux/pnp.h>
+#include "../base.h"
#include "pnpacpi.h"
#ifdef CONFIG_IA64
@@ -32,19 +34,26 @@
/*
* Allocated Resources
*/
-static int irq_flags(int triggering, int polarity)
+static int irq_flags(int triggering, int polarity, int shareable)
{
+ int flags;
+
if (triggering == ACPI_LEVEL_SENSITIVE) {
if (polarity == ACPI_ACTIVE_LOW)
- return IORESOURCE_IRQ_LOWLEVEL;
+ flags = IORESOURCE_IRQ_LOWLEVEL;
else
- return IORESOURCE_IRQ_HIGHLEVEL;
+ flags = IORESOURCE_IRQ_HIGHLEVEL;
} else {
if (polarity == ACPI_ACTIVE_LOW)
- return IORESOURCE_IRQ_LOWEDGE;
+ flags = IORESOURCE_IRQ_LOWEDGE;
else
- return IORESOURCE_IRQ_HIGHEDGE;
+ flags = IORESOURCE_IRQ_HIGHEDGE;
}
+
+ if (shareable)
+ flags |= IORESOURCE_IRQ_SHAREABLE;
+
+ return flags;
}
static void decode_irq_flags(int flag, int *triggering, int *polarity)
@@ -69,29 +78,16 @@
}
}
-static void pnpacpi_parse_allocated_irqresource(struct pnp_resource_table *res,
+static void pnpacpi_parse_allocated_irqresource(struct pnp_dev *dev,
u32 gsi, int triggering,
int polarity, int shareable)
{
- int i = 0;
- int irq;
+ int irq, flags;
int p, t;
- static unsigned char warned;
if (!valid_IRQ(gsi))
return;
- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_IRQ)
- i++;
- if (i >= PNP_MAX_IRQ) {
- if (!warned) {
- printk(KERN_WARNING "pnpacpi: exceeded the max number"
- " of IRQ resources: %d\n", PNP_MAX_IRQ);
- warned = 1;
- }
- return;
- }
/*
* in IO-APIC mode, use overrided attribute. Two reasons:
* 1. BIOS bug in DSDT
@@ -102,27 +98,21 @@
p = p ? ACPI_ACTIVE_LOW : ACPI_ACTIVE_HIGH;
if (triggering != t || polarity != p) {
- pnp_warn("IRQ %d override to %s, %s",
+ dev_warn(&dev->dev, "IRQ %d override to %s, %s\n",
gsi, t ? "edge":"level", p ? "low":"high");
triggering = t;
polarity = p;
}
}
- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- res->irq_resource[i].flags |= irq_flags(triggering, polarity);
+ flags = irq_flags(triggering, polarity, shareable);
irq = acpi_register_gsi(gsi, triggering, polarity);
- if (irq < 0) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
+ if (irq >= 0)
+ pcibios_penalize_isa_irq(irq, 1);
+ else
+ flags |= IORESOURCE_DISABLED;
- if (shareable)
- res->irq_resource[i].flags |= IORESOURCE_IRQ_SHAREABLE;
-
- res->irq_resource[i].start = irq;
- res->irq_resource[i].end = irq;
- pcibios_penalize_isa_irq(irq, 1);
+ pnp_add_irq_resource(dev, irq, flags);
}
static int dma_flags(int type, int bus_master, int transfer)
@@ -168,88 +158,36 @@
return flags;
}
-static void pnpacpi_parse_allocated_dmaresource(struct pnp_resource_table *res,
- u32 dma, int type,
- int bus_master, int transfer)
+static void pnpacpi_parse_allocated_ioresource(struct pnp_dev *dev, u64 start,
+ u64 len, int io_decode)
{
- int i = 0;
- static unsigned char warned;
+ int flags = 0;
+ u64 end = start + len - 1;
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- res->dma_resource[i].flags |=
- dma_flags(type, bus_master, transfer);
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start = dma;
- res->dma_resource[i].end = dma;
- } else if (!warned) {
- printk(KERN_WARNING "pnpacpi: exceeded the max number of DMA "
- "resources: %d \n", PNP_MAX_DMA);
- warned = 1;
- }
+ if (io_decode == ACPI_DECODE_16)
+ flags |= PNP_PORT_FLAG_16BITADDR;
+ if (len == 0 || end >= 0x10003)
+ flags |= IORESOURCE_DISABLED;
+
+ pnp_add_io_resource(dev, start, end, flags);
}
-static void pnpacpi_parse_allocated_ioresource(struct pnp_resource_table *res,
- u64 io, u64 len, int io_decode)
-{
- int i = 0;
- static unsigned char warned;
-
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET) &&
- i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (io_decode == ACPI_DECODE_16)
- res->port_resource[i].flags |= PNP_PORT_FLAG_16BITADDR;
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = io;
- res->port_resource[i].end = io + len - 1;
- } else if (!warned) {
- printk(KERN_WARNING "pnpacpi: exceeded the max number of IO "
- "resources: %d \n", PNP_MAX_PORT);
- warned = 1;
- }
-}
-
-static void pnpacpi_parse_allocated_memresource(struct pnp_resource_table *res,
- u64 mem, u64 len,
+static void pnpacpi_parse_allocated_memresource(struct pnp_dev *dev,
+ u64 start, u64 len,
int write_protect)
{
- int i = 0;
- static unsigned char warned;
+ int flags = 0;
+ u64 end = start + len - 1;
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET) &&
- (i < PNP_MAX_MEM))
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- if (write_protect == ACPI_READ_WRITE_MEMORY)
- res->mem_resource[i].flags |= IORESOURCE_MEM_WRITEABLE;
+ if (len == 0)
+ flags |= IORESOURCE_DISABLED;
+ if (write_protect == ACPI_READ_WRITE_MEMORY)
+ flags |= IORESOURCE_MEM_WRITEABLE;
- res->mem_resource[i].start = mem;
- res->mem_resource[i].end = mem + len - 1;
- } else if (!warned) {
- printk(KERN_WARNING "pnpacpi: exceeded the max number of mem "
- "resources: %d\n", PNP_MAX_MEM);
- warned = 1;
- }
+ pnp_add_mem_resource(dev, start, end, flags);
}
-static void pnpacpi_parse_allocated_address_space(struct pnp_resource_table *res_table,
+static void pnpacpi_parse_allocated_address_space(struct pnp_dev *dev,
struct acpi_resource *res)
{
struct acpi_resource_address64 addr, *p = &addr;
@@ -257,7 +195,7 @@
status = acpi_resource_to_address64(res, p);
if (!ACPI_SUCCESS(status)) {
- pnp_warn("PnPACPI: failed to convert resource type %d",
+ dev_warn(&dev->dev, "failed to convert resource type %d\n",
res->type);
return;
}
@@ -266,11 +204,11 @@
return;
if (p->resource_type == ACPI_MEMORY_RANGE)
- pnpacpi_parse_allocated_memresource(res_table,
+ pnpacpi_parse_allocated_memresource(dev,
p->minimum, p->address_length,
p->info.mem.write_protect);
else if (p->resource_type == ACPI_IO_RANGE)
- pnpacpi_parse_allocated_ioresource(res_table,
+ pnpacpi_parse_allocated_ioresource(dev,
p->minimum, p->address_length,
p->granularity == 0xfff ? ACPI_DECODE_10 :
ACPI_DECODE_16);
@@ -279,8 +217,16 @@
static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
void *data)
{
- struct pnp_resource_table *res_table = data;
- int i;
+ struct pnp_dev *dev = data;
+ struct acpi_resource_irq *irq;
+ struct acpi_resource_dma *dma;
+ struct acpi_resource_io *io;
+ struct acpi_resource_fixed_io *fixed_io;
+ struct acpi_resource_memory24 *memory24;
+ struct acpi_resource_memory32 *memory32;
+ struct acpi_resource_fixed_memory32 *fixed_memory32;
+ struct acpi_resource_extended_irq *extended_irq;
+ int i, flags;
switch (res->type) {
case ACPI_RESOURCE_TYPE_IRQ:
@@ -288,29 +234,33 @@
* Per spec, only one interrupt per descriptor is allowed in
* _CRS, but some firmware violates this, so parse them all.
*/
- for (i = 0; i < res->data.irq.interrupt_count; i++) {
- pnpacpi_parse_allocated_irqresource(res_table,
- res->data.irq.interrupts[i],
- res->data.irq.triggering,
- res->data.irq.polarity,
- res->data.irq.sharable);
+ irq = &res->data.irq;
+ for (i = 0; i < irq->interrupt_count; i++) {
+ pnpacpi_parse_allocated_irqresource(dev,
+ irq->interrupts[i],
+ irq->triggering,
+ irq->polarity,
+ irq->sharable);
}
break;
case ACPI_RESOURCE_TYPE_DMA:
- if (res->data.dma.channel_count > 0)
- pnpacpi_parse_allocated_dmaresource(res_table,
- res->data.dma.channels[0],
- res->data.dma.type,
- res->data.dma.bus_master,
- res->data.dma.transfer);
+ dma = &res->data.dma;
+ if (dma->channel_count > 0) {
+ flags = dma_flags(dma->type, dma->bus_master,
+ dma->transfer);
+ if (dma->channels[0] == (u8) -1)
+ flags |= IORESOURCE_DISABLED;
+ pnp_add_dma_resource(dev, dma->channels[0], flags);
+ }
break;
case ACPI_RESOURCE_TYPE_IO:
- pnpacpi_parse_allocated_ioresource(res_table,
- res->data.io.minimum,
- res->data.io.address_length,
- res->data.io.io_decode);
+ io = &res->data.io;
+ pnpacpi_parse_allocated_ioresource(dev,
+ io->minimum,
+ io->address_length,
+ io->io_decode);
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -318,9 +268,10 @@
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
- pnpacpi_parse_allocated_ioresource(res_table,
- res->data.fixed_io.address,
- res->data.fixed_io.address_length,
+ fixed_io = &res->data.fixed_io;
+ pnpacpi_parse_allocated_ioresource(dev,
+ fixed_io->address,
+ fixed_io->address_length,
ACPI_DECODE_10);
break;
@@ -331,27 +282,30 @@
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
- pnpacpi_parse_allocated_memresource(res_table,
- res->data.memory24.minimum,
- res->data.memory24.address_length,
- res->data.memory24.write_protect);
+ memory24 = &res->data.memory24;
+ pnpacpi_parse_allocated_memresource(dev,
+ memory24->minimum,
+ memory24->address_length,
+ memory24->write_protect);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
- pnpacpi_parse_allocated_memresource(res_table,
- res->data.memory32.minimum,
- res->data.memory32.address_length,
- res->data.memory32.write_protect);
+ memory32 = &res->data.memory32;
+ pnpacpi_parse_allocated_memresource(dev,
+ memory32->minimum,
+ memory32->address_length,
+ memory32->write_protect);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- pnpacpi_parse_allocated_memresource(res_table,
- res->data.fixed_memory32.address,
- res->data.fixed_memory32.address_length,
- res->data.fixed_memory32.write_protect);
+ fixed_memory32 = &res->data.fixed_memory32;
+ pnpacpi_parse_allocated_memresource(dev,
+ fixed_memory32->address,
+ fixed_memory32->address_length,
+ fixed_memory32->write_protect);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
- pnpacpi_parse_allocated_address_space(res_table, res);
+ pnpacpi_parse_allocated_address_space(dev, res);
break;
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
@@ -360,15 +314,16 @@
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- if (res->data.extended_irq.producer_consumer == ACPI_PRODUCER)
+ extended_irq = &res->data.extended_irq;
+ if (extended_irq->producer_consumer == ACPI_PRODUCER)
return AE_OK;
- for (i = 0; i < res->data.extended_irq.interrupt_count; i++) {
- pnpacpi_parse_allocated_irqresource(res_table,
- res->data.extended_irq.interrupts[i],
- res->data.extended_irq.triggering,
- res->data.extended_irq.polarity,
- res->data.extended_irq.sharable);
+ for (i = 0; i < extended_irq->interrupt_count; i++) {
+ pnpacpi_parse_allocated_irqresource(dev,
+ extended_irq->interrupts[i],
+ extended_irq->triggering,
+ extended_irq->polarity,
+ extended_irq->sharable);
}
break;
@@ -376,24 +331,36 @@
break;
default:
- pnp_warn("PnPACPI: unknown resource type %d", res->type);
+ dev_warn(&dev->dev, "unknown resource type %d in _CRS\n",
+ res->type);
return AE_ERROR;
}
return AE_OK;
}
-acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle,
- struct pnp_resource_table * res)
+int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
{
- /* Blank the resource table values */
- pnp_init_resource_table(res);
+ acpi_handle handle = dev->data;
+ acpi_status status;
- return acpi_walk_resources(handle, METHOD_NAME__CRS,
- pnpacpi_allocated_resource, res);
+ dev_dbg(&dev->dev, "parse allocated resources\n");
+
+ pnp_init_resources(dev);
+
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ pnpacpi_allocated_resource, dev);
+
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND)
+ dev_err(&dev->dev, "can't evaluate _CRS: %d", status);
+ return -EPERM;
+ }
+ return 0;
}
-static __init void pnpacpi_parse_dma_option(struct pnp_option *option,
+static __init void pnpacpi_parse_dma_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_dma *p)
{
int i;
@@ -410,10 +377,11 @@
dma->flags = dma_flags(p->type, p->bus_master, p->transfer);
- pnp_register_dma_resource(option, dma);
+ pnp_register_dma_resource(dev, option, dma);
}
-static __init void pnpacpi_parse_irq_option(struct pnp_option *option,
+static __init void pnpacpi_parse_irq_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_irq *p)
{
int i;
@@ -428,12 +396,13 @@
for (i = 0; i < p->interrupt_count; i++)
if (p->interrupts[i])
__set_bit(p->interrupts[i], irq->map);
- irq->flags = irq_flags(p->triggering, p->polarity);
+ irq->flags = irq_flags(p->triggering, p->polarity, p->sharable);
- pnp_register_irq_resource(option, irq);
+ pnp_register_irq_resource(dev, option, irq);
}
-static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option,
+static __init void pnpacpi_parse_ext_irq_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_extended_irq *p)
{
int i;
@@ -448,12 +417,13 @@
for (i = 0; i < p->interrupt_count; i++)
if (p->interrupts[i])
__set_bit(p->interrupts[i], irq->map);
- irq->flags = irq_flags(p->triggering, p->polarity);
+ irq->flags = irq_flags(p->triggering, p->polarity, p->sharable);
- pnp_register_irq_resource(option, irq);
+ pnp_register_irq_resource(dev, option, irq);
}
-static __init void pnpacpi_parse_port_option(struct pnp_option *option,
+static __init void pnpacpi_parse_port_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_io *io)
{
struct pnp_port *port;
@@ -469,10 +439,11 @@
port->size = io->address_length;
port->flags = ACPI_DECODE_16 == io->io_decode ?
PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
-static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option,
+static __init void pnpacpi_parse_fixed_port_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_fixed_io *io)
{
struct pnp_port *port;
@@ -486,10 +457,11 @@
port->size = io->address_length;
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
-static __init void pnpacpi_parse_mem24_option(struct pnp_option *option,
+static __init void pnpacpi_parse_mem24_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_memory24 *p)
{
struct pnp_mem *mem;
@@ -507,10 +479,11 @@
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpacpi_parse_mem32_option(struct pnp_option *option,
+static __init void pnpacpi_parse_mem32_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_memory32 *p)
{
struct pnp_mem *mem;
@@ -528,10 +501,11 @@
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
+static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource_fixed_memory32 *p)
{
struct pnp_mem *mem;
@@ -548,10 +522,11 @@
mem->flags = (ACPI_READ_WRITE_MEMORY == p->write_protect) ?
IORESOURCE_MEM_WRITEABLE : 0;
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpacpi_parse_address_option(struct pnp_option *option,
+static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
+ struct pnp_option *option,
struct acpi_resource *r)
{
struct acpi_resource_address64 addr, *p = &addr;
@@ -579,7 +554,7 @@
mem->flags = (p->info.mem.write_protect ==
ACPI_READ_WRITE_MEMORY) ? IORESOURCE_MEM_WRITEABLE
: 0;
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
} else if (p->resource_type == ACPI_IO_RANGE) {
port = kzalloc(sizeof(struct pnp_port), GFP_KERNEL);
if (!port)
@@ -588,7 +563,7 @@
port->size = p->address_length;
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
}
@@ -608,11 +583,11 @@
switch (res->type) {
case ACPI_RESOURCE_TYPE_IRQ:
- pnpacpi_parse_irq_option(option, &res->data.irq);
+ pnpacpi_parse_irq_option(dev, option, &res->data.irq);
break;
case ACPI_RESOURCE_TYPE_DMA:
- pnpacpi_parse_dma_option(option, &res->data.dma);
+ pnpacpi_parse_dma_option(dev, option, &res->data.dma);
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -642,19 +617,22 @@
case ACPI_RESOURCE_TYPE_END_DEPENDENT:
/*only one EndDependentFn is allowed */
if (!parse_data->option_independent) {
- pnp_warn("PnPACPI: more than one EndDependentFn");
+ dev_warn(&dev->dev, "more than one EndDependentFn "
+ "in _PRS\n");
return AE_ERROR;
}
parse_data->option = parse_data->option_independent;
parse_data->option_independent = NULL;
+ dev_dbg(&dev->dev, "end dependent options\n");
break;
case ACPI_RESOURCE_TYPE_IO:
- pnpacpi_parse_port_option(option, &res->data.io);
+ pnpacpi_parse_port_option(dev, option, &res->data.io);
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
- pnpacpi_parse_fixed_port_option(option, &res->data.fixed_io);
+ pnpacpi_parse_fixed_port_option(dev, option,
+ &res->data.fixed_io);
break;
case ACPI_RESOURCE_TYPE_VENDOR:
@@ -662,57 +640,67 @@
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
- pnpacpi_parse_mem24_option(option, &res->data.memory24);
+ pnpacpi_parse_mem24_option(dev, option, &res->data.memory24);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
- pnpacpi_parse_mem32_option(option, &res->data.memory32);
+ pnpacpi_parse_mem32_option(dev, option, &res->data.memory32);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- pnpacpi_parse_fixed_mem32_option(option,
+ pnpacpi_parse_fixed_mem32_option(dev, option,
&res->data.fixed_memory32);
break;
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
- pnpacpi_parse_address_option(option, res);
+ pnpacpi_parse_address_option(dev, option, res);
break;
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- pnpacpi_parse_ext_irq_option(option, &res->data.extended_irq);
+ pnpacpi_parse_ext_irq_option(dev, option,
+ &res->data.extended_irq);
break;
case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
break;
default:
- pnp_warn("PnPACPI: unknown resource type %d", res->type);
+ dev_warn(&dev->dev, "unknown resource type %d in _PRS\n",
+ res->type);
return AE_ERROR;
}
return AE_OK;
}
-acpi_status __init pnpacpi_parse_resource_option_data(acpi_handle handle,
- struct pnp_dev *dev)
+int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
{
+ acpi_handle handle = dev->data;
acpi_status status;
struct acpipnp_parse_option_s parse_data;
+ dev_dbg(&dev->dev, "parse resource options\n");
+
parse_data.option = pnp_register_independent_option(dev);
if (!parse_data.option)
- return AE_ERROR;
+ return -ENOMEM;
+
parse_data.option_independent = parse_data.option;
parse_data.dev = dev;
status = acpi_walk_resources(handle, METHOD_NAME__PRS,
pnpacpi_option_resource, &parse_data);
- return status;
+ if (ACPI_FAILURE(status)) {
+ if (status != AE_NOT_FOUND)
+ dev_err(&dev->dev, "can't evaluate _PRS: %d", status);
+ return -EPERM;
+ }
+ return 0;
}
static int pnpacpi_supported_resource(struct acpi_resource *res)
@@ -760,9 +748,10 @@
return AE_OK;
}
-int pnpacpi_build_resource_template(acpi_handle handle,
+int pnpacpi_build_resource_template(struct pnp_dev *dev,
struct acpi_buffer *buffer)
{
+ acpi_handle handle = dev->data;
struct acpi_resource *resource;
int res_cnt = 0;
acpi_status status;
@@ -770,7 +759,7 @@
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
pnpacpi_count_resources, &res_cnt);
if (ACPI_FAILURE(status)) {
- pnp_err("Evaluate _CRS failed");
+ dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
return -EINVAL;
}
if (!res_cnt)
@@ -779,13 +768,13 @@
buffer->pointer = kzalloc(buffer->length - 1, GFP_KERNEL);
if (!buffer->pointer)
return -ENOMEM;
- pnp_dbg("Res cnt %d", res_cnt);
+
resource = (struct acpi_resource *)buffer->pointer;
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
pnpacpi_type_resources, &resource);
if (ACPI_FAILURE(status)) {
kfree(buffer->pointer);
- pnp_err("Evaluate _CRS failed");
+ dev_err(&dev->dev, "can't evaluate _CRS: %d\n", status);
return -EINVAL;
}
/* resource will pointer the end resource now */
@@ -794,129 +783,184 @@
return 0;
}
-static void pnpacpi_encode_irq(struct acpi_resource *resource,
+static void pnpacpi_encode_irq(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_irq *irq = &resource->data.irq;
int triggering, polarity;
decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
- resource->data.irq.triggering = triggering;
- resource->data.irq.polarity = polarity;
+ irq->triggering = triggering;
+ irq->polarity = polarity;
if (triggering == ACPI_EDGE_SENSITIVE)
- resource->data.irq.sharable = ACPI_EXCLUSIVE;
+ irq->sharable = ACPI_EXCLUSIVE;
else
- resource->data.irq.sharable = ACPI_SHARED;
- resource->data.irq.interrupt_count = 1;
- resource->data.irq.interrupts[0] = p->start;
+ irq->sharable = ACPI_SHARED;
+ irq->interrupt_count = 1;
+ irq->interrupts[0] = p->start;
+
+ dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start,
+ triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
+ polarity == ACPI_ACTIVE_LOW ? "low" : "high",
+ irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
}
-static void pnpacpi_encode_ext_irq(struct acpi_resource *resource,
+static void pnpacpi_encode_ext_irq(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_extended_irq *extended_irq = &resource->data.extended_irq;
int triggering, polarity;
decode_irq_flags(p->flags & IORESOURCE_BITS, &triggering, &polarity);
- resource->data.extended_irq.producer_consumer = ACPI_CONSUMER;
- resource->data.extended_irq.triggering = triggering;
- resource->data.extended_irq.polarity = polarity;
+ extended_irq->producer_consumer = ACPI_CONSUMER;
+ extended_irq->triggering = triggering;
+ extended_irq->polarity = polarity;
if (triggering == ACPI_EDGE_SENSITIVE)
- resource->data.irq.sharable = ACPI_EXCLUSIVE;
+ extended_irq->sharable = ACPI_EXCLUSIVE;
else
- resource->data.irq.sharable = ACPI_SHARED;
- resource->data.extended_irq.interrupt_count = 1;
- resource->data.extended_irq.interrupts[0] = p->start;
+ extended_irq->sharable = ACPI_SHARED;
+ extended_irq->interrupt_count = 1;
+ extended_irq->interrupts[0] = p->start;
+
+ dev_dbg(&dev->dev, " encode irq %d %s %s %s\n", (int) p->start,
+ triggering == ACPI_LEVEL_SENSITIVE ? "level" : "edge",
+ polarity == ACPI_ACTIVE_LOW ? "low" : "high",
+ extended_irq->sharable == ACPI_SHARED ? "shared" : "exclusive");
}
-static void pnpacpi_encode_dma(struct acpi_resource *resource,
+static void pnpacpi_encode_dma(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_dma *dma = &resource->data.dma;
+
/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
case IORESOURCE_DMA_TYPEA:
- resource->data.dma.type = ACPI_TYPE_A;
+ dma->type = ACPI_TYPE_A;
break;
case IORESOURCE_DMA_TYPEB:
- resource->data.dma.type = ACPI_TYPE_B;
+ dma->type = ACPI_TYPE_B;
break;
case IORESOURCE_DMA_TYPEF:
- resource->data.dma.type = ACPI_TYPE_F;
+ dma->type = ACPI_TYPE_F;
break;
default:
- resource->data.dma.type = ACPI_COMPATIBILITY;
+ dma->type = ACPI_COMPATIBILITY;
}
switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
case IORESOURCE_DMA_8BIT:
- resource->data.dma.transfer = ACPI_TRANSFER_8;
+ dma->transfer = ACPI_TRANSFER_8;
break;
case IORESOURCE_DMA_8AND16BIT:
- resource->data.dma.transfer = ACPI_TRANSFER_8_16;
+ dma->transfer = ACPI_TRANSFER_8_16;
break;
default:
- resource->data.dma.transfer = ACPI_TRANSFER_16;
+ dma->transfer = ACPI_TRANSFER_16;
}
- resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
- resource->data.dma.channel_count = 1;
- resource->data.dma.channels[0] = p->start;
+ dma->bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
+ dma->channel_count = 1;
+ dma->channels[0] = p->start;
+
+ dev_dbg(&dev->dev, " encode dma %d "
+ "type %#x transfer %#x master %d\n",
+ (int) p->start, dma->type, dma->transfer, dma->bus_master);
}
-static void pnpacpi_encode_io(struct acpi_resource *resource,
+static void pnpacpi_encode_io(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_io *io = &resource->data.io;
+
/* Note: pnp_assign_port will copy pnp_port->flags into p->flags */
- resource->data.io.io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ?
+ io->io_decode = (p->flags & PNP_PORT_FLAG_16BITADDR) ?
ACPI_DECODE_16 : ACPI_DECODE_10;
- resource->data.io.minimum = p->start;
- resource->data.io.maximum = p->end;
- resource->data.io.alignment = 0; /* Correct? */
- resource->data.io.address_length = p->end - p->start + 1;
+ io->minimum = p->start;
+ io->maximum = p->end;
+ io->alignment = 0; /* Correct? */
+ io->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode io %#llx-%#llx decode %#x\n",
+ (unsigned long long) p->start, (unsigned long long) p->end,
+ io->io_decode);
}
-static void pnpacpi_encode_fixed_io(struct acpi_resource *resource,
+static void pnpacpi_encode_fixed_io(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
- resource->data.fixed_io.address = p->start;
- resource->data.fixed_io.address_length = p->end - p->start + 1;
+ struct acpi_resource_fixed_io *fixed_io = &resource->data.fixed_io;
+
+ fixed_io->address = p->start;
+ fixed_io->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode fixed_io %#llx-%#llx\n",
+ (unsigned long long) p->start, (unsigned long long) p->end);
}
-static void pnpacpi_encode_mem24(struct acpi_resource *resource,
+static void pnpacpi_encode_mem24(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
+ struct acpi_resource_memory24 *memory24 = &resource->data.memory24;
+
/* Note: pnp_assign_mem will copy pnp_mem->flags into p->flags */
- resource->data.memory24.write_protect =
+ memory24->write_protect =
(p->flags & IORESOURCE_MEM_WRITEABLE) ?
ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
- resource->data.memory24.minimum = p->start;
- resource->data.memory24.maximum = p->end;
- resource->data.memory24.alignment = 0;
- resource->data.memory24.address_length = p->end - p->start + 1;
+ memory24->minimum = p->start;
+ memory24->maximum = p->end;
+ memory24->alignment = 0;
+ memory24->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode mem24 %#llx-%#llx write_protect %#x\n",
+ (unsigned long long) p->start, (unsigned long long) p->end,
+ memory24->write_protect);
}
-static void pnpacpi_encode_mem32(struct acpi_resource *resource,
+static void pnpacpi_encode_mem32(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
- resource->data.memory32.write_protect =
+ struct acpi_resource_memory32 *memory32 = &resource->data.memory32;
+
+ memory32->write_protect =
(p->flags & IORESOURCE_MEM_WRITEABLE) ?
ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
- resource->data.memory32.minimum = p->start;
- resource->data.memory32.maximum = p->end;
- resource->data.memory32.alignment = 0;
- resource->data.memory32.address_length = p->end - p->start + 1;
+ memory32->minimum = p->start;
+ memory32->maximum = p->end;
+ memory32->alignment = 0;
+ memory32->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode mem32 %#llx-%#llx write_protect %#x\n",
+ (unsigned long long) p->start, (unsigned long long) p->end,
+ memory32->write_protect);
}
-static void pnpacpi_encode_fixed_mem32(struct acpi_resource *resource,
+static void pnpacpi_encode_fixed_mem32(struct pnp_dev *dev,
+ struct acpi_resource *resource,
struct resource *p)
{
- resource->data.fixed_memory32.write_protect =
+ struct acpi_resource_fixed_memory32 *fixed_memory32 = &resource->data.fixed_memory32;
+
+ fixed_memory32->write_protect =
(p->flags & IORESOURCE_MEM_WRITEABLE) ?
ACPI_READ_WRITE_MEMORY : ACPI_READ_ONLY_MEMORY;
- resource->data.fixed_memory32.address = p->start;
- resource->data.fixed_memory32.address_length = p->end - p->start + 1;
+ fixed_memory32->address = p->start;
+ fixed_memory32->address_length = p->end - p->start + 1;
+
+ dev_dbg(&dev->dev, " encode fixed_mem32 %#llx-%#llx "
+ "write_protect %#x\n",
+ (unsigned long long) p->start, (unsigned long long) p->end,
+ fixed_memory32->write_protect);
}
-int pnpacpi_encode_resources(struct pnp_resource_table *res_table,
- struct acpi_buffer *buffer)
+int pnpacpi_encode_resources(struct pnp_dev *dev, struct acpi_buffer *buffer)
{
int i = 0;
/* pnpacpi_build_resource_template allocates extra mem */
@@ -924,58 +968,48 @@
struct acpi_resource *resource = buffer->pointer;
int port = 0, irq = 0, dma = 0, mem = 0;
- pnp_dbg("res cnt %d", res_cnt);
+ dev_dbg(&dev->dev, "encode %d resources\n", res_cnt);
while (i < res_cnt) {
switch (resource->type) {
case ACPI_RESOURCE_TYPE_IRQ:
- pnp_dbg("Encode irq");
- pnpacpi_encode_irq(resource,
- &res_table->irq_resource[irq]);
+ pnpacpi_encode_irq(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_IRQ, irq));
irq++;
break;
case ACPI_RESOURCE_TYPE_DMA:
- pnp_dbg("Encode dma");
- pnpacpi_encode_dma(resource,
- &res_table->dma_resource[dma]);
+ pnpacpi_encode_dma(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_DMA, dma));
dma++;
break;
case ACPI_RESOURCE_TYPE_IO:
- pnp_dbg("Encode io");
- pnpacpi_encode_io(resource,
- &res_table->port_resource[port]);
+ pnpacpi_encode_io(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_IO, port));
port++;
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
- pnp_dbg("Encode fixed io");
- pnpacpi_encode_fixed_io(resource,
- &res_table->
- port_resource[port]);
+ pnpacpi_encode_fixed_io(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_IO, port));
port++;
break;
case ACPI_RESOURCE_TYPE_MEMORY24:
- pnp_dbg("Encode mem24");
- pnpacpi_encode_mem24(resource,
- &res_table->mem_resource[mem]);
+ pnpacpi_encode_mem24(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
- pnp_dbg("Encode mem32");
- pnpacpi_encode_mem32(resource,
- &res_table->mem_resource[mem]);
+ pnpacpi_encode_mem32(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- pnp_dbg("Encode fixed mem32");
- pnpacpi_encode_fixed_mem32(resource,
- &res_table->
- mem_resource[mem]);
+ pnpacpi_encode_fixed_mem32(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
- pnp_dbg("Encode ext irq");
- pnpacpi_encode_ext_irq(resource,
- &res_table->irq_resource[irq]);
+ pnpacpi_encode_ext_irq(dev, resource,
+ pnp_get_resource(dev, IORESOURCE_IRQ, irq));
irq++;
break;
case ACPI_RESOURCE_TYPE_START_DEPENDENT:
@@ -988,7 +1022,8 @@
case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
default: /* other type */
- pnp_warn("unknown resource type %d", resource->type);
+ dev_warn(&dev->dev, "can't encode unknown resource "
+ "type %d\n", resource->type);
return -EINVAL;
}
resource++;
diff --git a/drivers/pnp/pnpbios/Makefile b/drivers/pnp/pnpbios/Makefile
index 3cd3ed7..310e2b3 100644
--- a/drivers/pnp/pnpbios/Makefile
+++ b/drivers/pnp/pnpbios/Makefile
@@ -5,3 +5,7 @@
pnpbios-proc-$(CONFIG_PNPBIOS_PROC_FS) = proc.o
obj-y := core.o bioscalls.o rsparser.o $(pnpbios-proc-y)
+
+ifeq ($(CONFIG_PNP_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
diff --git a/drivers/pnp/pnpbios/bioscalls.c b/drivers/pnp/pnpbios/bioscalls.c
index a8364d8..7ff8244 100644
--- a/drivers/pnp/pnpbios/bioscalls.c
+++ b/drivers/pnp/pnpbios/bioscalls.c
@@ -7,7 +7,6 @@
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/kernel.h>
-#include <linux/pnpbios.h>
#include <linux/device.h>
#include <linux/pnp.h>
#include <linux/mm.h>
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index a8a5150..19a4be1 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -50,7 +50,6 @@
#include <linux/init.h>
#include <linux/linkage.h>
#include <linux/kernel.h>
-#include <linux/pnpbios.h>
#include <linux/device.h>
#include <linux/pnp.h>
#include <linux/mm.h>
@@ -69,6 +68,7 @@
#include <asm/system.h>
#include <asm/byteorder.h>
+#include "../base.h"
#include "pnpbios.h"
/*
@@ -203,8 +203,7 @@
#endif /* CONFIG_HOTPLUG */
-static int pnpbios_get_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int pnpbios_get_resources(struct pnp_dev *dev)
{
u8 nodenum = dev->number;
struct pnp_bios_node *node;
@@ -212,6 +211,7 @@
if (!pnpbios_is_dynamic(dev))
return -EPERM;
+ dev_dbg(&dev->dev, "get resources\n");
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
@@ -219,14 +219,13 @@
kfree(node);
return -ENODEV;
}
- pnpbios_read_resources_from_node(res, node);
+ pnpbios_read_resources_from_node(dev, node);
dev->active = pnp_is_active(dev);
kfree(node);
return 0;
}
-static int pnpbios_set_resources(struct pnp_dev *dev,
- struct pnp_resource_table *res)
+static int pnpbios_set_resources(struct pnp_dev *dev)
{
u8 nodenum = dev->number;
struct pnp_bios_node *node;
@@ -235,6 +234,7 @@
if (!pnpbios_is_dynamic(dev))
return -EPERM;
+ dev_dbg(&dev->dev, "set resources\n");
node = kzalloc(node_info.max_node_size, GFP_KERNEL);
if (!node)
return -1;
@@ -242,7 +242,7 @@
kfree(node);
return -ENODEV;
}
- if (pnpbios_write_resources_to_node(res, node) < 0) {
+ if (pnpbios_write_resources_to_node(dev, node) < 0) {
kfree(node);
return -1;
}
@@ -317,7 +317,6 @@
{
struct list_head *pos;
struct pnp_dev *dev;
- struct pnp_id *dev_id;
char id[8];
/* check if the device is already added */
@@ -327,20 +326,11 @@
return -1;
}
- dev = kzalloc(sizeof(struct pnp_dev), GFP_KERNEL);
+ pnp_eisa_id_to_string(node->eisa_id & PNP_EISA_ID_MASK, id);
+ dev = pnp_alloc_dev(&pnpbios_protocol, node->handle, id);
if (!dev)
return -1;
- dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
- if (!dev_id) {
- kfree(dev);
- return -1;
- }
-
- dev->number = node->handle;
- pnpid32_to_pnpid(node->eisa_id, id);
- memcpy(dev_id->id, id, 7);
- pnp_add_id(dev_id, dev);
pnpbios_parse_data_stream(dev, node);
dev->active = pnp_is_active(dev);
dev->flags = node->flags;
@@ -353,11 +343,10 @@
dev->capabilities |= PNP_WRITE;
if (dev->flags & PNPBIOS_REMOVABLE)
dev->capabilities |= PNP_REMOVABLE;
- dev->protocol = &pnpbios_protocol;
/* clear out the damaged flags */
if (!dev->active)
- pnp_init_resource_table(&dev->res);
+ pnp_init_resources(dev);
pnp_add_device(dev);
pnpbios_interface_attach_device(node);
diff --git a/drivers/pnp/pnpbios/pnpbios.h b/drivers/pnp/pnpbios/pnpbios.h
index d8cb2fd..b09cf6d 100644
--- a/drivers/pnp/pnpbios/pnpbios.h
+++ b/drivers/pnp/pnpbios/pnpbios.h
@@ -2,6 +2,142 @@
* pnpbios.h - contains local definitions
*/
+/*
+ * Include file for the interface to a PnP BIOS
+ *
+ * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
+ * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dahinds@users.sourceforge.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, 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
+ */
+
+/*
+ * Return codes
+ */
+#define PNP_SUCCESS 0x00
+#define PNP_NOT_SET_STATICALLY 0x7f
+#define PNP_UNKNOWN_FUNCTION 0x81
+#define PNP_FUNCTION_NOT_SUPPORTED 0x82
+#define PNP_INVALID_HANDLE 0x83
+#define PNP_BAD_PARAMETER 0x84
+#define PNP_SET_FAILED 0x85
+#define PNP_EVENTS_NOT_PENDING 0x86
+#define PNP_SYSTEM_NOT_DOCKED 0x87
+#define PNP_NO_ISA_PNP_CARDS 0x88
+#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89
+#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a
+#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b
+#define PNP_BUFFER_TOO_SMALL 0x8c
+#define PNP_USE_ESCD_SUPPORT 0x8d
+#define PNP_MESSAGE_NOT_SUPPORTED 0x8e
+#define PNP_HARDWARE_ERROR 0x8f
+
+#define ESCD_SUCCESS 0x00
+#define ESCD_IO_ERROR_READING 0x55
+#define ESCD_INVALID 0x56
+#define ESCD_BUFFER_TOO_SMALL 0x59
+#define ESCD_NVRAM_TOO_SMALL 0x5a
+#define ESCD_FUNCTION_NOT_SUPPORTED 0x81
+
+/*
+ * Events that can be received by "get event"
+ */
+#define PNPEV_ABOUT_TO_CHANGE_CONFIG 0x0001
+#define PNPEV_DOCK_CHANGED 0x0002
+#define PNPEV_SYSTEM_DEVICE_CHANGED 0x0003
+#define PNPEV_CONFIG_CHANGED_FAILED 0x0004
+#define PNPEV_UNKNOWN_SYSTEM_EVENT 0xffff
+/* 0x8000 through 0xfffe are OEM defined */
+
+/*
+ * Messages that should be sent through "send message"
+ */
+#define PNPMSG_OK 0x00
+#define PNPMSG_ABORT 0x01
+#define PNPMSG_UNDOCK_DEFAULT_ACTION 0x40
+#define PNPMSG_POWER_OFF 0x41
+#define PNPMSG_PNP_OS_ACTIVE 0x42
+#define PNPMSG_PNP_OS_INACTIVE 0x43
+
+/*
+ * Plug and Play BIOS flags
+ */
+#define PNPBIOS_NO_DISABLE 0x0001
+#define PNPBIOS_NO_CONFIG 0x0002
+#define PNPBIOS_OUTPUT 0x0004
+#define PNPBIOS_INPUT 0x0008
+#define PNPBIOS_BOOTABLE 0x0010
+#define PNPBIOS_DOCK 0x0020
+#define PNPBIOS_REMOVABLE 0x0040
+#define pnpbios_is_static(x) (((x)->flags & 0x0100) == 0x0000)
+#define pnpbios_is_dynamic(x) ((x)->flags & 0x0080)
+
+/*
+ * Function Parameters
+ */
+#define PNPMODE_STATIC 1
+#define PNPMODE_DYNAMIC 0
+
+/* 0x8000 through 0xffff are OEM defined */
+
+#pragma pack(1)
+struct pnp_dev_node_info {
+ __u16 no_nodes;
+ __u16 max_node_size;
+};
+struct pnp_docking_station_info {
+ __u32 location_id;
+ __u32 serial;
+ __u16 capabilities;
+};
+struct pnp_isa_config_struc {
+ __u8 revision;
+ __u8 no_csns;
+ __u16 isa_rd_data_port;
+ __u16 reserved;
+};
+struct escd_info_struc {
+ __u16 min_escd_write_size;
+ __u16 escd_size;
+ __u32 nv_storage_base;
+};
+struct pnp_bios_node {
+ __u16 size;
+ __u8 handle;
+ __u32 eisa_id;
+ __u8 type_code[3];
+ __u16 flags;
+ __u8 data[0];
+};
+#pragma pack()
+
+/* non-exported */
+extern struct pnp_dev_node_info node_info;
+
+extern int pnp_bios_dev_node_info(struct pnp_dev_node_info *data);
+extern int pnp_bios_get_dev_node(u8 *nodenum, char config,
+ struct pnp_bios_node *data);
+extern int pnp_bios_set_dev_node(u8 nodenum, char config,
+ struct pnp_bios_node *data);
+extern int pnp_bios_get_stat_res(char *info);
+extern int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data);
+extern int pnp_bios_escd_info(struct escd_info_struc *data);
+extern int pnp_bios_read_escd(char *data, u32 nvram_base);
+extern int pnp_bios_dock_station_info(struct pnp_docking_station_info *data);
+
#pragma pack(1)
union pnp_bios_install_struct {
struct {
@@ -28,8 +164,8 @@
extern int pnpbios_dont_use_current_config;
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);
-extern int pnpbios_write_resources_to_node(struct pnp_resource_table *res, struct pnp_bios_node * node);
+extern int pnpbios_read_resources_from_node(struct pnp_dev *dev, struct pnp_bios_node *node);
+extern int pnpbios_write_resources_to_node(struct pnp_dev *dev, struct pnp_bios_node *node);
extern void pnpid32_to_pnpid(u32 id, char *str);
extern void pnpbios_print_status(const char * module, u16 status);
diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c
index bb19bc9..b35d921 100644
--- a/drivers/pnp/pnpbios/proc.c
+++ b/drivers/pnp/pnpbios/proc.c
@@ -23,7 +23,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
-#include <linux/pnpbios.h>
+#include <linux/pnp.h>
#include <linux/init.h>
#include <asm/uaccess.h>
@@ -256,7 +256,7 @@
*/
int __init pnpbios_proc_init(void)
{
- proc_pnp = proc_mkdir("pnp", proc_bus);
+ proc_pnp = proc_mkdir("bus/pnp", NULL);
if (!proc_pnp)
return -EIO;
proc_pnp_boot = proc_mkdir("boot", proc_pnp);
@@ -294,5 +294,5 @@
remove_proc_entry("configuration_info", proc_pnp);
remove_proc_entry("devices", proc_pnp);
remove_proc_entry("boot", proc_pnp);
- remove_proc_entry("pnp", proc_bus);
+ remove_proc_entry("bus/pnp", NULL);
}
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index caade35..5ff9a4c 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -4,7 +4,6 @@
#include <linux/ctype.h>
#include <linux/pnp.h>
-#include <linux/pnpbios.h>
#include <linux/string.h>
#include <linux/slab.h>
@@ -16,6 +15,7 @@
}
#endif /* CONFIG_PCI */
+#include "../base.h"
#include "pnpbios.h"
/* standard resource tags */
@@ -53,97 +53,43 @@
* Allocated Resources
*/
-static void pnpbios_parse_allocated_irqresource(struct pnp_resource_table *res,
- int irq)
+static void pnpbios_parse_allocated_ioresource(struct pnp_dev *dev,
+ int start, int len)
{
- int i = 0;
+ int flags = 0;
+ int end = start + len - 1;
- while (!(res->irq_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_IRQ)
- i++;
- if (i < PNP_MAX_IRQ) {
- res->irq_resource[i].flags = IORESOURCE_IRQ; // Also clears _UNSET flag
- if (irq == -1) {
- res->irq_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->irq_resource[i].start =
- res->irq_resource[i].end = (unsigned long)irq;
- pcibios_penalize_isa_irq(irq, 1);
- }
+ if (len <= 0 || end >= 0x10003)
+ flags |= IORESOURCE_DISABLED;
+
+ pnp_add_io_resource(dev, start, end, flags);
}
-static void pnpbios_parse_allocated_dmaresource(struct pnp_resource_table *res,
- int dma)
+static void pnpbios_parse_allocated_memresource(struct pnp_dev *dev,
+ int start, int len)
{
- int i = 0;
+ int flags = 0;
+ int end = start + len - 1;
- while (i < PNP_MAX_DMA &&
- !(res->dma_resource[i].flags & IORESOURCE_UNSET))
- i++;
- if (i < PNP_MAX_DMA) {
- res->dma_resource[i].flags = IORESOURCE_DMA; // Also clears _UNSET flag
- if (dma == -1) {
- res->dma_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->dma_resource[i].start =
- res->dma_resource[i].end = (unsigned long)dma;
- }
+ if (len <= 0)
+ flags |= IORESOURCE_DISABLED;
+
+ pnp_add_mem_resource(dev, start, end, flags);
}
-static void pnpbios_parse_allocated_ioresource(struct pnp_resource_table *res,
- int io, int len)
-{
- int i = 0;
-
- while (!(res->port_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_PORT)
- i++;
- if (i < PNP_MAX_PORT) {
- res->port_resource[i].flags = IORESOURCE_IO; // Also clears _UNSET flag
- if (len <= 0 || (io + len - 1) >= 0x10003) {
- res->port_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->port_resource[i].start = (unsigned long)io;
- res->port_resource[i].end = (unsigned long)(io + len - 1);
- }
-}
-
-static void pnpbios_parse_allocated_memresource(struct pnp_resource_table *res,
- int mem, int len)
-{
- int i = 0;
-
- while (!(res->mem_resource[i].flags & IORESOURCE_UNSET)
- && i < PNP_MAX_MEM)
- i++;
- if (i < PNP_MAX_MEM) {
- res->mem_resource[i].flags = IORESOURCE_MEM; // Also clears _UNSET flag
- if (len <= 0) {
- res->mem_resource[i].flags |= IORESOURCE_DISABLED;
- return;
- }
- res->mem_resource[i].start = (unsigned long)mem;
- res->mem_resource[i].end = (unsigned long)(mem + len - 1);
- }
-}
-
-static unsigned char *pnpbios_parse_allocated_resource_data(unsigned char *p,
- unsigned char *end,
- struct
- pnp_resource_table
- *res)
+static unsigned char *pnpbios_parse_allocated_resource_data(struct pnp_dev *dev,
+ unsigned char *p,
+ unsigned char *end)
{
unsigned int len, tag;
- int io, size, mask, i;
+ int io, size, mask, i, flags;
if (!p)
return NULL;
- /* Blank the resource table values */
- pnp_init_resource_table(res);
+ dev_dbg(&dev->dev, "parse allocated resources\n");
+
+ pnp_init_resources(dev);
while ((char *)p < (char *)end) {
@@ -163,7 +109,7 @@
goto len_err;
io = *(short *)&p[4];
size = *(short *)&p[10];
- pnpbios_parse_allocated_memresource(res, io, size);
+ pnpbios_parse_allocated_memresource(dev, io, size);
break;
case LARGE_TAG_ANSISTR:
@@ -179,7 +125,7 @@
goto len_err;
io = *(int *)&p[4];
size = *(int *)&p[16];
- pnpbios_parse_allocated_memresource(res, io, size);
+ pnpbios_parse_allocated_memresource(dev, io, size);
break;
case LARGE_TAG_FIXEDMEM32:
@@ -187,29 +133,37 @@
goto len_err;
io = *(int *)&p[4];
size = *(int *)&p[8];
- pnpbios_parse_allocated_memresource(res, io, size);
+ pnpbios_parse_allocated_memresource(dev, io, size);
break;
case SMALL_TAG_IRQ:
if (len < 2 || len > 3)
goto len_err;
+ flags = 0;
io = -1;
mask = p[1] + p[2] * 256;
for (i = 0; i < 16; i++, mask = mask >> 1)
if (mask & 0x01)
io = i;
- pnpbios_parse_allocated_irqresource(res, io);
+ if (io != -1)
+ pcibios_penalize_isa_irq(io, 1);
+ else
+ flags = IORESOURCE_DISABLED;
+ pnp_add_irq_resource(dev, io, flags);
break;
case SMALL_TAG_DMA:
if (len != 2)
goto len_err;
+ flags = 0;
io = -1;
mask = p[1];
for (i = 0; i < 8; i++, mask = mask >> 1)
if (mask & 0x01)
io = i;
- pnpbios_parse_allocated_dmaresource(res, io);
+ if (io == -1)
+ flags = IORESOURCE_DISABLED;
+ pnp_add_dma_resource(dev, io, flags);
break;
case SMALL_TAG_PORT:
@@ -217,7 +171,7 @@
goto len_err;
io = p[2] + p[3] * 256;
size = p[7];
- pnpbios_parse_allocated_ioresource(res, io, size);
+ pnpbios_parse_allocated_ioresource(dev, io, size);
break;
case SMALL_TAG_VENDOR:
@@ -229,7 +183,7 @@
goto len_err;
io = p[1] + p[2] * 256;
size = p[3];
- pnpbios_parse_allocated_ioresource(res, io, size);
+ pnpbios_parse_allocated_ioresource(dev, io, size);
break;
case SMALL_TAG_END:
@@ -239,9 +193,8 @@
default: /* an unkown tag */
len_err:
- printk(KERN_ERR
- "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
- tag, len);
+ dev_err(&dev->dev, "unknown tag %#x length %d\n",
+ tag, len);
break;
}
@@ -252,8 +205,7 @@
p += len + 1;
}
- printk(KERN_ERR
- "PnPBIOS: Resource structure does not contain an end tag.\n");
+ dev_err(&dev->dev, "no end tag in resource structure\n");
return NULL;
}
@@ -262,7 +214,8 @@
* Resource Configuration Options
*/
-static __init void pnpbios_parse_mem_option(unsigned char *p, int size,
+static __init void pnpbios_parse_mem_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -275,10 +228,11 @@
mem->align = (p[9] << 8) | p[8];
mem->size = ((p[11] << 8) | p[10]) << 8;
mem->flags = p[3];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpbios_parse_mem32_option(unsigned char *p, int size,
+static __init void pnpbios_parse_mem32_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -291,10 +245,11 @@
mem->align = (p[15] << 24) | (p[14] << 16) | (p[13] << 8) | p[12];
mem->size = (p[19] << 24) | (p[18] << 16) | (p[17] << 8) | p[16];
mem->flags = p[3];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size,
+static __init void pnpbios_parse_fixed_mem32_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_mem *mem;
@@ -306,11 +261,12 @@
mem->size = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
mem->align = 0;
mem->flags = p[3];
- pnp_register_mem_resource(option, mem);
+ pnp_register_mem_resource(dev, option, mem);
}
-static __init void pnpbios_parse_irq_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_irq_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_irq *irq;
unsigned long bits;
@@ -324,11 +280,12 @@
irq->flags = p[3];
else
irq->flags = IORESOURCE_IRQ_HIGHEDGE;
- pnp_register_irq_resource(option, irq);
+ pnp_register_irq_resource(dev, option, irq);
}
-static __init void pnpbios_parse_dma_option(unsigned char *p, int size,
- struct pnp_option *option)
+static __init void pnpbios_parse_dma_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
+ struct pnp_option *option)
{
struct pnp_dma *dma;
@@ -337,10 +294,11 @@
return;
dma->map = p[1];
dma->flags = p[2];
- pnp_register_dma_resource(option, dma);
+ pnp_register_dma_resource(dev, option, dma);
}
-static __init void pnpbios_parse_port_option(unsigned char *p, int size,
+static __init void pnpbios_parse_port_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_port *port;
@@ -353,10 +311,11 @@
port->align = p[6];
port->size = p[7];
port->flags = p[1] ? PNP_PORT_FLAG_16BITADDR : 0;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
-static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size,
+static __init void pnpbios_parse_fixed_port_option(struct pnp_dev *dev,
+ unsigned char *p, int size,
struct pnp_option *option)
{
struct pnp_port *port;
@@ -368,7 +327,7 @@
port->size = p[3];
port->align = 0;
port->flags = PNP_PORT_FLAG_FIXED;
- pnp_register_port_resource(option, port);
+ pnp_register_port_resource(dev, option, port);
}
static __init unsigned char *
@@ -382,6 +341,8 @@
if (!p)
return NULL;
+ dev_dbg(&dev->dev, "parse resource options\n");
+
option_independent = option = pnp_register_independent_option(dev);
if (!option)
return NULL;
@@ -402,37 +363,37 @@
case LARGE_TAG_MEM:
if (len != 9)
goto len_err;
- pnpbios_parse_mem_option(p, len, option);
+ pnpbios_parse_mem_option(dev, p, len, option);
break;
case LARGE_TAG_MEM32:
if (len != 17)
goto len_err;
- pnpbios_parse_mem32_option(p, len, option);
+ pnpbios_parse_mem32_option(dev, p, len, option);
break;
case LARGE_TAG_FIXEDMEM32:
if (len != 9)
goto len_err;
- pnpbios_parse_fixed_mem32_option(p, len, option);
+ pnpbios_parse_fixed_mem32_option(dev, p, len, option);
break;
case SMALL_TAG_IRQ:
if (len < 2 || len > 3)
goto len_err;
- pnpbios_parse_irq_option(p, len, option);
+ pnpbios_parse_irq_option(dev, p, len, option);
break;
case SMALL_TAG_DMA:
if (len != 2)
goto len_err;
- pnpbios_parse_dma_option(p, len, option);
+ pnpbios_parse_dma_option(dev, p, len, option);
break;
case SMALL_TAG_PORT:
if (len != 7)
goto len_err;
- pnpbios_parse_port_option(p, len, option);
+ pnpbios_parse_port_option(dev, p, len, option);
break;
case SMALL_TAG_VENDOR:
@@ -442,7 +403,7 @@
case SMALL_TAG_FIXEDPORT:
if (len != 3)
goto len_err;
- pnpbios_parse_fixed_port_option(p, len, option);
+ pnpbios_parse_fixed_port_option(dev, p, len, option);
break;
case SMALL_TAG_STARTDEP:
@@ -460,9 +421,10 @@
if (len != 0)
goto len_err;
if (option_independent == option)
- printk(KERN_WARNING
- "PnPBIOS: Missing SMALL_TAG_STARTDEP tag\n");
+ dev_warn(&dev->dev, "missing "
+ "SMALL_TAG_STARTDEP tag\n");
option = option_independent;
+ dev_dbg(&dev->dev, "end dependent options\n");
break;
case SMALL_TAG_END:
@@ -470,9 +432,8 @@
default: /* an unkown tag */
len_err:
- printk(KERN_ERR
- "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
- tag, len);
+ dev_err(&dev->dev, "unknown tag %#x length %d\n",
+ tag, len);
break;
}
@@ -483,8 +444,7 @@
p += len + 1;
}
- printk(KERN_ERR
- "PnPBIOS: Resource structure does not contain an end tag.\n");
+ dev_err(&dev->dev, "no end tag in resource structure\n");
return NULL;
}
@@ -493,32 +453,12 @@
* Compatible Device IDs
*/
-#define HEX(id,a) hex[((id)>>a) & 15]
-#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
-
-void pnpid32_to_pnpid(u32 id, char *str)
-{
- const char *hex = "0123456789abcdef";
-
- id = be32_to_cpu(id);
- str[0] = CHAR(id, 26);
- str[1] = CHAR(id, 21);
- str[2] = CHAR(id, 16);
- str[3] = HEX(id, 12);
- str[4] = HEX(id, 8);
- str[5] = HEX(id, 4);
- str[6] = HEX(id, 0);
- str[7] = '\0';
-}
-
-#undef CHAR
-#undef HEX
-
static unsigned char *pnpbios_parse_compatible_ids(unsigned char *p,
unsigned char *end,
struct pnp_dev *dev)
{
int len, tag;
+ u32 eisa_id;
char id[8];
struct pnp_id *dev_id;
@@ -548,13 +488,11 @@
case SMALL_TAG_COMPATDEVID: /* compatible ID */
if (len != 4)
goto len_err;
- dev_id = kzalloc(sizeof(struct pnp_id), GFP_KERNEL);
+ eisa_id = p[1] | p[2] << 8 | p[3] << 16 | p[4] << 24;
+ pnp_eisa_id_to_string(eisa_id & PNP_EISA_ID_MASK, id);
+ dev_id = pnp_add_id(dev, id);
if (!dev_id)
return NULL;
- pnpid32_to_pnpid(p[1] | p[2] << 8 | p[3] << 16 | p[4] <<
- 24, id);
- memcpy(&dev_id->id, id, 7);
- pnp_add_id(dev_id, dev);
break;
case SMALL_TAG_END:
@@ -564,9 +502,8 @@
default: /* an unkown tag */
len_err:
- printk(KERN_ERR
- "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
- tag, len);
+ dev_err(&dev->dev, "unknown tag %#x length %d\n",
+ tag, len);
break;
}
@@ -577,8 +514,7 @@
p += len + 1;
}
- printk(KERN_ERR
- "PnPBIOS: Resource structure does not contain an end tag.\n");
+ dev_err(&dev->dev, "no end tag in resource structure\n");
return NULL;
}
@@ -587,7 +523,8 @@
* Allocated Resource Encoding
*/
-static void pnpbios_encode_mem(unsigned char *p, struct resource *res)
+static void pnpbios_encode_mem(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -598,9 +535,13 @@
p[7] = ((base >> 8) >> 8) & 0xff;
p[10] = (len >> 8) & 0xff;
p[11] = ((len >> 8) >> 8) & 0xff;
+
+ dev_dbg(&dev->dev, " encode mem %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static void pnpbios_encode_mem32(unsigned char *p, struct resource *res)
+static void pnpbios_encode_mem32(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -617,9 +558,13 @@
p[17] = (len >> 8) & 0xff;
p[18] = (len >> 16) & 0xff;
p[19] = (len >> 24) & 0xff;
+
+ dev_dbg(&dev->dev, " encode mem32 %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static void pnpbios_encode_fixed_mem32(unsigned char *p, struct resource *res)
+static void pnpbios_encode_fixed_mem32(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -632,26 +577,38 @@
p[9] = (len >> 8) & 0xff;
p[10] = (len >> 16) & 0xff;
p[11] = (len >> 24) & 0xff;
+
+ dev_dbg(&dev->dev, " encode fixed_mem32 %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static void pnpbios_encode_irq(unsigned char *p, struct resource *res)
+static void pnpbios_encode_irq(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long map = 0;
map = 1 << res->start;
p[1] = map & 0xff;
p[2] = (map >> 8) & 0xff;
+
+ dev_dbg(&dev->dev, " encode irq %llu\n",
+ (unsigned long long)res->start);
}
-static void pnpbios_encode_dma(unsigned char *p, struct resource *res)
+static void pnpbios_encode_dma(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long map = 0;
map = 1 << res->start;
p[1] = map & 0xff;
+
+ dev_dbg(&dev->dev, " encode dma %llu\n",
+ (unsigned long long)res->start);
}
-static void pnpbios_encode_port(unsigned char *p, struct resource *res)
+static void pnpbios_encode_port(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -661,9 +618,13 @@
p[4] = base & 0xff;
p[5] = (base >> 8) & 0xff;
p[7] = len & 0xff;
+
+ dev_dbg(&dev->dev, " encode io %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static void pnpbios_encode_fixed_port(unsigned char *p, struct resource *res)
+static void pnpbios_encode_fixed_port(struct pnp_dev *dev, unsigned char *p,
+ struct resource *res)
{
unsigned long base = res->start;
unsigned long len = res->end - res->start + 1;
@@ -671,13 +632,15 @@
p[1] = base & 0xff;
p[2] = (base >> 8) & 0xff;
p[3] = len & 0xff;
+
+ dev_dbg(&dev->dev, " encode fixed_io %#llx-%#llx\n",
+ (unsigned long long) res->start, (unsigned long long) res->end);
}
-static unsigned char *pnpbios_encode_allocated_resource_data(unsigned char *p,
- unsigned char *end,
- struct
- pnp_resource_table
- *res)
+static unsigned char *pnpbios_encode_allocated_resource_data(struct pnp_dev
+ *dev,
+ unsigned char *p,
+ unsigned char *end)
{
unsigned int len, tag;
int port = 0, irq = 0, dma = 0, mem = 0;
@@ -701,42 +664,48 @@
case LARGE_TAG_MEM:
if (len != 9)
goto len_err;
- pnpbios_encode_mem(p, &res->mem_resource[mem]);
+ pnpbios_encode_mem(dev, p,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case LARGE_TAG_MEM32:
if (len != 17)
goto len_err;
- pnpbios_encode_mem32(p, &res->mem_resource[mem]);
+ pnpbios_encode_mem32(dev, p,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case LARGE_TAG_FIXEDMEM32:
if (len != 9)
goto len_err;
- pnpbios_encode_fixed_mem32(p, &res->mem_resource[mem]);
+ pnpbios_encode_fixed_mem32(dev, p,
+ pnp_get_resource(dev, IORESOURCE_MEM, mem));
mem++;
break;
case SMALL_TAG_IRQ:
if (len < 2 || len > 3)
goto len_err;
- pnpbios_encode_irq(p, &res->irq_resource[irq]);
+ pnpbios_encode_irq(dev, p,
+ pnp_get_resource(dev, IORESOURCE_IRQ, irq));
irq++;
break;
case SMALL_TAG_DMA:
if (len != 2)
goto len_err;
- pnpbios_encode_dma(p, &res->dma_resource[dma]);
+ pnpbios_encode_dma(dev, p,
+ pnp_get_resource(dev, IORESOURCE_DMA, dma));
dma++;
break;
case SMALL_TAG_PORT:
if (len != 7)
goto len_err;
- pnpbios_encode_port(p, &res->port_resource[port]);
+ pnpbios_encode_port(dev, p,
+ pnp_get_resource(dev, IORESOURCE_IO, port));
port++;
break;
@@ -747,7 +716,8 @@
case SMALL_TAG_FIXEDPORT:
if (len != 3)
goto len_err;
- pnpbios_encode_fixed_port(p, &res->port_resource[port]);
+ pnpbios_encode_fixed_port(dev, p,
+ pnp_get_resource(dev, IORESOURCE_IO, port));
port++;
break;
@@ -758,9 +728,8 @@
default: /* an unkown tag */
len_err:
- printk(KERN_ERR
- "PnPBIOS: Unknown tag '0x%x', length '%d'.\n",
- tag, len);
+ dev_err(&dev->dev, "unknown tag %#x length %d\n",
+ tag, len);
break;
}
@@ -771,8 +740,7 @@
p += len + 1;
}
- printk(KERN_ERR
- "PnPBIOS: Resource structure does not contain an end tag.\n");
+ dev_err(&dev->dev, "no end tag in resource structure\n");
return NULL;
}
@@ -787,7 +755,7 @@
unsigned char *p = (char *)node->data;
unsigned char *end = (char *)(node->data + node->size);
- p = pnpbios_parse_allocated_resource_data(p, end, &dev->res);
+ p = pnpbios_parse_allocated_resource_data(dev, p, end);
if (!p)
return -EIO;
p = pnpbios_parse_resource_option_data(p, end, dev);
@@ -799,25 +767,25 @@
return 0;
}
-int pnpbios_read_resources_from_node(struct pnp_resource_table *res,
+int pnpbios_read_resources_from_node(struct pnp_dev *dev,
struct pnp_bios_node *node)
{
unsigned char *p = (char *)node->data;
unsigned char *end = (char *)(node->data + node->size);
- p = pnpbios_parse_allocated_resource_data(p, end, res);
+ p = pnpbios_parse_allocated_resource_data(dev, p, end);
if (!p)
return -EIO;
return 0;
}
-int pnpbios_write_resources_to_node(struct pnp_resource_table *res,
+int pnpbios_write_resources_to_node(struct pnp_dev *dev,
struct pnp_bios_node *node)
{
unsigned char *p = (char *)node->data;
unsigned char *end = (char *)(node->data + node->size);
- p = pnpbios_encode_allocated_resource_data(p, end, res);
+ p = pnpbios_encode_allocated_resource_data(dev, p, end);
if (!p)
return -EIO;
return 0;
diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c
index e4daf46..d049a22 100644
--- a/drivers/pnp/quirks.c
+++ b/drivers/pnp/quirks.c
@@ -117,6 +117,7 @@
static void quirk_system_pci_resources(struct pnp_dev *dev)
{
struct pci_dev *pdev = NULL;
+ struct resource *res;
resource_size_t pnp_start, pnp_end, pci_start, pci_end;
int i, j;
@@ -137,13 +138,15 @@
pci_start = pci_resource_start(pdev, i);
pci_end = pci_resource_end(pdev, i);
- for (j = 0; j < PNP_MAX_MEM; j++) {
- if (!pnp_mem_valid(dev, j) ||
- pnp_mem_len(dev, j) == 0)
+ for (j = 0;
+ (res = pnp_get_resource(dev, IORESOURCE_MEM, j));
+ j++) {
+ if (res->flags & IORESOURCE_UNSET ||
+ (res->start == 0 && res->end == 0))
continue;
- pnp_start = pnp_mem_start(dev, j);
- pnp_end = pnp_mem_end(dev, j);
+ pnp_start = res->start;
+ pnp_end = res->end;
/*
* If the PNP region doesn't overlap the PCI
@@ -176,7 +179,7 @@
pci_name(pdev), i,
(unsigned long long) pci_start,
(unsigned long long) pci_end);
- pnp_mem_flags(dev, j) = 0;
+ res->flags = 0;
}
}
}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index e50ebcf..2041620 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -53,6 +53,8 @@
if (dev->independent)
dev_err(&dev->dev, "independent resource already registered\n");
dev->independent = option;
+
+ dev_dbg(&dev->dev, "new independent option\n");
return option;
}
@@ -70,12 +72,18 @@
parent->next = option;
} else
dev->dependent = option;
+
+ dev_dbg(&dev->dev, "new dependent option (priority %#x)\n", priority);
return option;
}
-int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
+int pnp_register_irq_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_irq *data)
{
struct pnp_irq *ptr;
+#ifdef DEBUG
+ char buf[PNP_IRQ_NR]; /* hex-encoded, so this is overkill but safe */
+#endif
ptr = option->irq;
while (ptr && ptr->next)
@@ -94,10 +102,17 @@
pcibios_penalize_isa_irq(i, 0);
}
#endif
+
+#ifdef DEBUG
+ bitmap_scnprintf(buf, sizeof(buf), data->map, PNP_IRQ_NR);
+ dev_dbg(&dev->dev, " irq bitmask %s flags %#x\n", buf,
+ data->flags);
+#endif
return 0;
}
-int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data)
+int pnp_register_dma_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_dma *data)
{
struct pnp_dma *ptr;
@@ -109,10 +124,13 @@
else
option->dma = data;
+ dev_dbg(&dev->dev, " dma bitmask %#x flags %#x\n", data->map,
+ data->flags);
return 0;
}
-int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data)
+int pnp_register_port_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_port *data)
{
struct pnp_port *ptr;
@@ -124,10 +142,14 @@
else
option->port = data;
+ dev_dbg(&dev->dev, " io "
+ "min %#x max %#x align %d size %d flags %#x\n",
+ data->min, data->max, data->align, data->size, data->flags);
return 0;
}
-int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data)
+int pnp_register_mem_resource(struct pnp_dev *dev, struct pnp_option *option,
+ struct pnp_mem *data)
{
struct pnp_mem *ptr;
@@ -138,6 +160,10 @@
ptr->next = data;
else
option->mem = data;
+
+ dev_dbg(&dev->dev, " mem "
+ "min %#x max %#x align %d size %d flags %#x\n",
+ data->min, data->max, data->align, data->size, data->flags);
return 0;
}
@@ -213,17 +239,18 @@
#define cannot_compare(flags) \
((flags) & (IORESOURCE_UNSET | IORESOURCE_DISABLED))
-int pnp_check_port(struct pnp_dev *dev, int idx)
+int pnp_check_port(struct pnp_dev *dev, struct resource *res)
{
- int tmp;
+ int i;
struct pnp_dev *tdev;
+ struct resource *tres;
resource_size_t *port, *end, *tport, *tend;
- port = &dev->res.port_resource[idx].start;
- end = &dev->res.port_resource[idx].end;
+ port = &res->start;
+ end = &res->end;
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.port_resource[idx].flags))
+ if (cannot_compare(res->flags))
return 1;
/* check if the resource is already in use, skip if the
@@ -234,18 +261,18 @@
}
/* check if the resource is reserved */
- for (tmp = 0; tmp < 8; tmp++) {
- int rport = pnp_reserve_io[tmp << 1];
- int rend = pnp_reserve_io[(tmp << 1) + 1] + rport - 1;
+ for (i = 0; i < 8; i++) {
+ int rport = pnp_reserve_io[i << 1];
+ int rend = pnp_reserve_io[(i << 1) + 1] + rport - 1;
if (ranged_conflict(port, end, &rport, &rend))
return 0;
}
/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_PORT && tmp != idx; tmp++) {
- if (dev->res.port_resource[tmp].flags & IORESOURCE_IO) {
- tport = &dev->res.port_resource[tmp].start;
- tend = &dev->res.port_resource[tmp].end;
+ for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
+ if (tres != res && tres->flags & IORESOURCE_IO) {
+ tport = &tres->start;
+ tend = &tres->end;
if (ranged_conflict(port, end, tport, tend))
return 0;
}
@@ -255,13 +282,14 @@
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_PORT; tmp++) {
- if (tdev->res.port_resource[tmp].flags & IORESOURCE_IO) {
- if (cannot_compare
- (tdev->res.port_resource[tmp].flags))
+ for (i = 0;
+ (tres = pnp_get_resource(tdev, IORESOURCE_IO, i));
+ i++) {
+ if (tres->flags & IORESOURCE_IO) {
+ if (cannot_compare(tres->flags))
continue;
- tport = &tdev->res.port_resource[tmp].start;
- tend = &tdev->res.port_resource[tmp].end;
+ tport = &tres->start;
+ tend = &tres->end;
if (ranged_conflict(port, end, tport, tend))
return 0;
}
@@ -271,17 +299,18 @@
return 1;
}
-int pnp_check_mem(struct pnp_dev *dev, int idx)
+int pnp_check_mem(struct pnp_dev *dev, struct resource *res)
{
- int tmp;
+ int i;
struct pnp_dev *tdev;
+ struct resource *tres;
resource_size_t *addr, *end, *taddr, *tend;
- addr = &dev->res.mem_resource[idx].start;
- end = &dev->res.mem_resource[idx].end;
+ addr = &res->start;
+ end = &res->end;
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.mem_resource[idx].flags))
+ if (cannot_compare(res->flags))
return 1;
/* check if the resource is already in use, skip if the
@@ -292,18 +321,18 @@
}
/* check if the resource is reserved */
- for (tmp = 0; tmp < 8; tmp++) {
- int raddr = pnp_reserve_mem[tmp << 1];
- int rend = pnp_reserve_mem[(tmp << 1) + 1] + raddr - 1;
+ for (i = 0; i < 8; i++) {
+ int raddr = pnp_reserve_mem[i << 1];
+ int rend = pnp_reserve_mem[(i << 1) + 1] + raddr - 1;
if (ranged_conflict(addr, end, &raddr, &rend))
return 0;
}
/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_MEM && tmp != idx; tmp++) {
- if (dev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
- taddr = &dev->res.mem_resource[tmp].start;
- tend = &dev->res.mem_resource[tmp].end;
+ for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
+ if (tres != res && tres->flags & IORESOURCE_MEM) {
+ taddr = &tres->start;
+ tend = &tres->end;
if (ranged_conflict(addr, end, taddr, tend))
return 0;
}
@@ -313,13 +342,14 @@
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_MEM; tmp++) {
- if (tdev->res.mem_resource[tmp].flags & IORESOURCE_MEM) {
- if (cannot_compare
- (tdev->res.mem_resource[tmp].flags))
+ for (i = 0;
+ (tres = pnp_get_resource(tdev, IORESOURCE_MEM, i));
+ i++) {
+ if (tres->flags & IORESOURCE_MEM) {
+ if (cannot_compare(tres->flags))
continue;
- taddr = &tdev->res.mem_resource[tmp].start;
- tend = &tdev->res.mem_resource[tmp].end;
+ taddr = &tres->start;
+ tend = &tres->end;
if (ranged_conflict(addr, end, taddr, tend))
return 0;
}
@@ -334,14 +364,17 @@
return IRQ_HANDLED;
}
-int pnp_check_irq(struct pnp_dev *dev, int idx)
+int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
{
- int tmp;
+ int i;
struct pnp_dev *tdev;
- resource_size_t *irq = &dev->res.irq_resource[idx].start;
+ struct resource *tres;
+ resource_size_t *irq;
+
+ irq = &res->start;
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.irq_resource[idx].flags))
+ if (cannot_compare(res->flags))
return 1;
/* check if the resource is valid */
@@ -349,15 +382,15 @@
return 0;
/* check if the resource is reserved */
- for (tmp = 0; tmp < 16; tmp++) {
- if (pnp_reserve_irq[tmp] == *irq)
+ for (i = 0; i < 16; i++) {
+ if (pnp_reserve_irq[i] == *irq)
return 0;
}
/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_IRQ && tmp != idx; tmp++) {
- if (dev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
- if (dev->res.irq_resource[tmp].start == *irq)
+ for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_IRQ, i)); i++) {
+ if (tres != res && tres->flags & IORESOURCE_IRQ) {
+ if (tres->start == *irq)
return 0;
}
}
@@ -388,12 +421,13 @@
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_IRQ; tmp++) {
- if (tdev->res.irq_resource[tmp].flags & IORESOURCE_IRQ) {
- if (cannot_compare
- (tdev->res.irq_resource[tmp].flags))
+ for (i = 0;
+ (tres = pnp_get_resource(tdev, IORESOURCE_IRQ, i));
+ i++) {
+ if (tres->flags & IORESOURCE_IRQ) {
+ if (cannot_compare(tres->flags))
continue;
- if ((tdev->res.irq_resource[tmp].start == *irq))
+ if (tres->start == *irq)
return 0;
}
}
@@ -402,15 +436,18 @@
return 1;
}
-int pnp_check_dma(struct pnp_dev *dev, int idx)
+int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
{
#ifndef CONFIG_IA64
- int tmp;
+ int i;
struct pnp_dev *tdev;
- resource_size_t *dma = &dev->res.dma_resource[idx].start;
+ struct resource *tres;
+ resource_size_t *dma;
+
+ dma = &res->start;
/* if the resource doesn't exist, don't complain about it */
- if (cannot_compare(dev->res.dma_resource[idx].flags))
+ if (cannot_compare(res->flags))
return 1;
/* check if the resource is valid */
@@ -418,15 +455,15 @@
return 0;
/* check if the resource is reserved */
- for (tmp = 0; tmp < 8; tmp++) {
- if (pnp_reserve_dma[tmp] == *dma)
+ for (i = 0; i < 8; i++) {
+ if (pnp_reserve_dma[i] == *dma)
return 0;
}
/* check for internal conflicts */
- for (tmp = 0; tmp < PNP_MAX_DMA && tmp != idx; tmp++) {
- if (dev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
- if (dev->res.dma_resource[tmp].start == *dma)
+ for (i = 0; (tres = pnp_get_resource(dev, IORESOURCE_DMA, i)); i++) {
+ if (tres != res && tres->flags & IORESOURCE_DMA) {
+ if (tres->start == *dma)
return 0;
}
}
@@ -443,12 +480,13 @@
pnp_for_each_dev(tdev) {
if (tdev == dev)
continue;
- for (tmp = 0; tmp < PNP_MAX_DMA; tmp++) {
- if (tdev->res.dma_resource[tmp].flags & IORESOURCE_DMA) {
- if (cannot_compare
- (tdev->res.dma_resource[tmp].flags))
+ for (i = 0;
+ (tres = pnp_get_resource(tdev, IORESOURCE_DMA, i));
+ i++) {
+ if (tres->flags & IORESOURCE_DMA) {
+ if (cannot_compare(tres->flags))
continue;
- if ((tdev->res.dma_resource[tmp].start == *dma))
+ if (tres->start == *dma)
return 0;
}
}
@@ -461,6 +499,193 @@
#endif
}
+struct pnp_resource *pnp_get_pnp_resource(struct pnp_dev *dev,
+ unsigned int type, unsigned int num)
+{
+ struct pnp_resource_table *res = dev->res;
+
+ switch (type) {
+ case IORESOURCE_IO:
+ if (num >= PNP_MAX_PORT)
+ return NULL;
+ return &res->port[num];
+ case IORESOURCE_MEM:
+ if (num >= PNP_MAX_MEM)
+ return NULL;
+ return &res->mem[num];
+ case IORESOURCE_IRQ:
+ if (num >= PNP_MAX_IRQ)
+ return NULL;
+ return &res->irq[num];
+ case IORESOURCE_DMA:
+ if (num >= PNP_MAX_DMA)
+ return NULL;
+ return &res->dma[num];
+ }
+ return NULL;
+}
+
+struct resource *pnp_get_resource(struct pnp_dev *dev,
+ unsigned int type, unsigned int num)
+{
+ struct pnp_resource *pnp_res;
+
+ pnp_res = pnp_get_pnp_resource(dev, type, num);
+ if (pnp_res)
+ return &pnp_res->res;
+
+ return NULL;
+}
+EXPORT_SYMBOL(pnp_get_resource);
+
+static struct pnp_resource *pnp_new_resource(struct pnp_dev *dev, int type)
+{
+ struct pnp_resource *pnp_res;
+ int i;
+
+ switch (type) {
+ case IORESOURCE_IO:
+ for (i = 0; i < PNP_MAX_PORT; i++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IO, i);
+ if (pnp_res && !pnp_resource_valid(&pnp_res->res))
+ return pnp_res;
+ }
+ break;
+ case IORESOURCE_MEM:
+ for (i = 0; i < PNP_MAX_MEM; i++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_MEM, i);
+ if (pnp_res && !pnp_resource_valid(&pnp_res->res))
+ return pnp_res;
+ }
+ break;
+ case IORESOURCE_IRQ:
+ for (i = 0; i < PNP_MAX_IRQ; i++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_IRQ, i);
+ if (pnp_res && !pnp_resource_valid(&pnp_res->res))
+ return pnp_res;
+ }
+ break;
+ case IORESOURCE_DMA:
+ for (i = 0; i < PNP_MAX_DMA; i++) {
+ pnp_res = pnp_get_pnp_resource(dev, IORESOURCE_DMA, i);
+ if (pnp_res && !pnp_resource_valid(&pnp_res->res))
+ return pnp_res;
+ }
+ break;
+ }
+ return NULL;
+}
+
+struct pnp_resource *pnp_add_irq_resource(struct pnp_dev *dev, int irq,
+ int flags)
+{
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ static unsigned char warned;
+
+ pnp_res = pnp_new_resource(dev, IORESOURCE_IRQ);
+ if (!pnp_res) {
+ if (!warned) {
+ dev_err(&dev->dev, "can't add resource for IRQ %d\n",
+ irq);
+ warned = 1;
+ }
+ return NULL;
+ }
+
+ res = &pnp_res->res;
+ res->flags = IORESOURCE_IRQ | flags;
+ res->start = irq;
+ res->end = irq;
+
+ dev_dbg(&dev->dev, " add irq %d flags %#x\n", irq, flags);
+ return pnp_res;
+}
+
+struct pnp_resource *pnp_add_dma_resource(struct pnp_dev *dev, int dma,
+ int flags)
+{
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ static unsigned char warned;
+
+ pnp_res = pnp_new_resource(dev, IORESOURCE_DMA);
+ if (!pnp_res) {
+ if (!warned) {
+ dev_err(&dev->dev, "can't add resource for DMA %d\n",
+ dma);
+ warned = 1;
+ }
+ return NULL;
+ }
+
+ res = &pnp_res->res;
+ res->flags = IORESOURCE_DMA | flags;
+ res->start = dma;
+ res->end = dma;
+
+ dev_dbg(&dev->dev, " add dma %d flags %#x\n", dma, flags);
+ return pnp_res;
+}
+
+struct pnp_resource *pnp_add_io_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end, int flags)
+{
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ static unsigned char warned;
+
+ pnp_res = pnp_new_resource(dev, IORESOURCE_IO);
+ if (!pnp_res) {
+ if (!warned) {
+ dev_err(&dev->dev, "can't add resource for IO "
+ "%#llx-%#llx\n",(unsigned long long) start,
+ (unsigned long long) end);
+ warned = 1;
+ }
+ return NULL;
+ }
+
+ res = &pnp_res->res;
+ res->flags = IORESOURCE_IO | flags;
+ res->start = start;
+ res->end = end;
+
+ dev_dbg(&dev->dev, " add io %#llx-%#llx flags %#x\n",
+ (unsigned long long) start, (unsigned long long) end, flags);
+ return pnp_res;
+}
+
+struct pnp_resource *pnp_add_mem_resource(struct pnp_dev *dev,
+ resource_size_t start,
+ resource_size_t end, int flags)
+{
+ struct pnp_resource *pnp_res;
+ struct resource *res;
+ static unsigned char warned;
+
+ pnp_res = pnp_new_resource(dev, IORESOURCE_MEM);
+ if (!pnp_res) {
+ if (!warned) {
+ dev_err(&dev->dev, "can't add resource for MEM "
+ "%#llx-%#llx\n",(unsigned long long) start,
+ (unsigned long long) end);
+ warned = 1;
+ }
+ return NULL;
+ }
+
+ res = &pnp_res->res;
+ res->flags = IORESOURCE_MEM | flags;
+ res->start = start;
+ res->end = end;
+
+ dev_dbg(&dev->dev, " add mem %#llx-%#llx flags %#x\n",
+ (unsigned long long) start, (unsigned long long) end, flags);
+ return pnp_res;
+}
+
/* format is: pnp_reserve_irq=irq1[,irq2] .... */
static int __init pnp_setup_reserve_irq(char *str)
{
diff --git a/drivers/pnp/support.c b/drivers/pnp/support.c
index 13c608f..3eba85e 100644
--- a/drivers/pnp/support.c
+++ b/drivers/pnp/support.c
@@ -25,3 +25,66 @@
}
EXPORT_SYMBOL(pnp_is_active);
+
+/*
+ * Functionally similar to acpi_ex_eisa_id_to_string(), but that's
+ * buried in the ACPI CA, and we can't depend on it being present.
+ */
+void pnp_eisa_id_to_string(u32 id, char *str)
+{
+ id = be32_to_cpu(id);
+
+ /*
+ * According to the specs, the first three characters are five-bit
+ * compressed ASCII, and the left-over high order bit should be zero.
+ * However, the Linux ISAPNP code historically used six bits for the
+ * first character, and there seem to be IDs that depend on that,
+ * e.g., "nEC8241" in the Linux 8250_pnp serial driver and the
+ * FreeBSD sys/pc98/cbus/sio_cbus.c driver.
+ */
+ str[0] = 'A' + ((id >> 26) & 0x3f) - 1;
+ str[1] = 'A' + ((id >> 21) & 0x1f) - 1;
+ str[2] = 'A' + ((id >> 16) & 0x1f) - 1;
+ str[3] = hex_asc((id >> 12) & 0xf);
+ str[4] = hex_asc((id >> 8) & 0xf);
+ str[5] = hex_asc((id >> 4) & 0xf);
+ str[6] = hex_asc((id >> 0) & 0xf);
+ str[7] = '\0';
+}
+
+void dbg_pnp_show_resources(struct pnp_dev *dev, char *desc)
+{
+#ifdef DEBUG
+ struct resource *res;
+ int i;
+
+ dev_dbg(&dev->dev, "current resources: %s\n", desc);
+
+ for (i = 0; i < PNP_MAX_IRQ; i++) {
+ res = pnp_get_resource(dev, IORESOURCE_IRQ, i);
+ if (res && !(res->flags & IORESOURCE_UNSET))
+ dev_dbg(&dev->dev, " irq %lld flags %#lx\n",
+ (unsigned long long) res->start, res->flags);
+ }
+ for (i = 0; i < PNP_MAX_DMA; i++) {
+ res = pnp_get_resource(dev, IORESOURCE_DMA, i);
+ if (res && !(res->flags & IORESOURCE_UNSET))
+ dev_dbg(&dev->dev, " dma %lld flags %#lx\n",
+ (unsigned long long) res->start, res->flags);
+ }
+ for (i = 0; i < PNP_MAX_PORT; i++) {
+ res = pnp_get_resource(dev, IORESOURCE_IO, i);
+ if (res && !(res->flags & IORESOURCE_UNSET))
+ dev_dbg(&dev->dev, " io %#llx-%#llx flags %#lx\n",
+ (unsigned long long) res->start,
+ (unsigned long long) res->end, res->flags);
+ }
+ for (i = 0; i < PNP_MAX_MEM; i++) {
+ res = pnp_get_resource(dev, IORESOURCE_MEM, i);
+ if (res && !(res->flags & IORESOURCE_UNSET))
+ dev_dbg(&dev->dev, " mem %#llx-%#llx flags %#lx\n",
+ (unsigned long long) res->start,
+ (unsigned long long) res->end, res->flags);
+ }
+#endif
+}
diff --git a/drivers/pnp/system.c b/drivers/pnp/system.c
index 55c4563..9c2496d 100644
--- a/drivers/pnp/system.c
+++ b/drivers/pnp/system.c
@@ -56,14 +56,15 @@
static void reserve_resources_of_dev(struct pnp_dev *dev)
{
+ struct resource *res;
int i;
- for (i = 0; i < PNP_MAX_PORT; i++) {
- if (!pnp_port_valid(dev, i))
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_IO, i)); i++) {
+ if (res->flags & IORESOURCE_UNSET)
continue;
- if (pnp_port_start(dev, i) == 0)
+ if (res->start == 0)
continue; /* disabled */
- if (pnp_port_start(dev, i) < 0x100)
+ if (res->start < 0x100)
/*
* Below 0x100 is only standard PC hardware
* (pics, kbd, timer, dma, ...)
@@ -73,19 +74,17 @@
* So, do nothing
*/
continue;
- if (pnp_port_end(dev, i) < pnp_port_start(dev, i))
+ if (res->end < res->start)
continue; /* invalid */
- reserve_range(dev, pnp_port_start(dev, i),
- pnp_port_end(dev, i), 1);
+ reserve_range(dev, res->start, res->end, 1);
}
- for (i = 0; i < PNP_MAX_MEM; i++) {
- if (!pnp_mem_valid(dev, i))
+ for (i = 0; (res = pnp_get_resource(dev, IORESOURCE_MEM, i)); i++) {
+ if (res->flags & IORESOURCE_UNSET)
continue;
- reserve_range(dev, pnp_mem_start(dev, i),
- pnp_mem_end(dev, i), 0);
+ reserve_range(dev, res->start, res->end, 0);
}
}
diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c
index bdb9b72..71be36f 100644
--- a/drivers/power/ds2760_battery.c
+++ b/drivers/power/ds2760_battery.c
@@ -262,7 +262,7 @@
struct ds2760_device_info, monitor_work.work);
const int interval = HZ * 60;
- dev_dbg(di->dev, "%s\n", __FUNCTION__);
+ dev_dbg(di->dev, "%s\n", __func__);
ds2760_battery_update_status(di);
queue_delayed_work(di->monitor_wqueue, &di->monitor_work, interval);
@@ -275,7 +275,7 @@
{
struct ds2760_device_info *di = to_ds2760_device_info(psy);
- dev_dbg(di->dev, "%s\n", __FUNCTION__);
+ dev_dbg(di->dev, "%s\n", __func__);
cancel_delayed_work(&di->monitor_work);
queue_delayed_work(di->monitor_wqueue, &di->monitor_work, HZ/10);
diff --git a/drivers/power/olpc_battery.c b/drivers/power/olpc_battery.c
index af7a231..ab1e828 100644
--- a/drivers/power/olpc_battery.c
+++ b/drivers/power/olpc_battery.c
@@ -315,7 +315,6 @@
if (ret)
goto battery_failed;
- olpc_register_battery_callback(&olpc_battery_trigger_uevent);
goto success;
battery_failed:
@@ -328,7 +327,6 @@
static void __exit olpc_bat_exit(void)
{
- olpc_deregister_battery_callback();
power_supply_unregister(&olpc_bat);
power_supply_unregister(&olpc_ac);
platform_device_unregister(bat_pdev);
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 03d6a38..138dd76 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -39,7 +39,7 @@
struct power_supply *psy = container_of(work, struct power_supply,
changed_work);
- dev_dbg(psy->dev, "%s\n", __FUNCTION__);
+ dev_dbg(psy->dev, "%s\n", __func__);
class_for_each_device(power_supply_class, psy,
__power_supply_changed_work);
@@ -51,7 +51,7 @@
void power_supply_changed(struct power_supply *psy)
{
- dev_dbg(psy->dev, "%s\n", __FUNCTION__);
+ dev_dbg(psy->dev, "%s\n", __func__);
schedule_work(&psy->changed_work);
}
@@ -82,7 +82,7 @@
error = class_for_each_device(power_supply_class, psy,
__power_supply_am_i_supplied);
- dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, error);
+ dev_dbg(psy->dev, "%s %d\n", __func__, error);
return error;
}
diff --git a/drivers/power/power_supply_leds.c b/drivers/power/power_supply_leds.c
index fa3034f..2dece40 100644
--- a/drivers/power/power_supply_leds.c
+++ b/drivers/power/power_supply_leds.c
@@ -24,7 +24,7 @@
if (psy->get_property(psy, POWER_SUPPLY_PROP_STATUS, &status))
return;
- dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, status.intval);
+ dev_dbg(psy->dev, "%s %d\n", __func__, status.intval);
switch (status.intval) {
case POWER_SUPPLY_STATUS_FULL:
@@ -101,7 +101,7 @@
if (psy->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online))
return;
- dev_dbg(psy->dev, "%s %d\n", __FUNCTION__, online.intval);
+ dev_dbg(psy->dev, "%s %d\n", __func__, online.intval);
if (online.intval)
led_trigger_event(psy->online_trig, LED_FULL);
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index 4f28045..8624f55 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -419,7 +419,7 @@
return -ENOMEM;
rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE);
- if (unlikely(IS_ERR(rtc))) {
+ if (IS_ERR(rtc)) {
ret = PTR_ERR(rtc->rtc_dev);
goto err;
}
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index dcdc142..d060a06 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -854,11 +854,12 @@
* don't define the IRQ. It should always be safe to
* hardcode it in these cases
*/
- return cmos_do_probe(&pnp->dev, &pnp->res.port_resource[0], 8);
+ return cmos_do_probe(&pnp->dev,
+ pnp_get_resource(pnp, IORESOURCE_IO, 0), 8);
else
return cmos_do_probe(&pnp->dev,
- &pnp->res.port_resource[0],
- pnp->res.irq_resource[0].start);
+ pnp_get_resource(pnp, IORESOURCE_IO, 0),
+ pnp_irq(pnp, 0));
}
static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index f389a28..bbf97e6 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -99,45 +99,38 @@
};
struct chip_desc {
- char name[9];
unsigned nvram56:1;
unsigned alarm:1;
- enum ds_type type;
};
-static const struct chip_desc chips[] = { {
- .name = "ds1307",
- .type = ds_1307,
+static const struct chip_desc chips[] = {
+[ds_1307] = {
.nvram56 = 1,
-}, {
- .name = "ds1337",
- .type = ds_1337,
+},
+[ds_1337] = {
.alarm = 1,
-}, {
- .name = "ds1338",
- .type = ds_1338,
+},
+[ds_1338] = {
.nvram56 = 1,
-}, {
- .name = "ds1339",
- .type = ds_1339,
+},
+[ds_1339] = {
.alarm = 1,
-}, {
- .name = "ds1340",
- .type = ds_1340,
-}, {
- .name = "m41t00",
- .type = m41t00,
+},
+[ds_1340] = {
+},
+[m41t00] = {
}, };
-static inline const struct chip_desc *find_chip(const char *s)
-{
- unsigned i;
-
- for (i = 0; i < ARRAY_SIZE(chips); i++)
- if (strnicmp(s, chips[i].name, sizeof chips[i].name) == 0)
- return &chips[i];
- return NULL;
-}
+static const struct i2c_device_id ds1307_id[] = {
+ { "ds1307", ds_1307 },
+ { "ds1337", ds_1337 },
+ { "ds1338", ds_1338 },
+ { "ds1339", ds_1339 },
+ { "ds1340", ds_1340 },
+ { "m41t00", m41t00 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1307_id);
static int ds1307_get_time(struct device *dev, struct rtc_time *t)
{
@@ -326,21 +319,15 @@
static struct i2c_driver ds1307_driver;
-static int __devinit ds1307_probe(struct i2c_client *client)
+static int __devinit ds1307_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ds1307 *ds1307;
int err = -ENODEV;
int tmp;
- const struct chip_desc *chip;
+ const struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- chip = find_chip(client->name);
- if (!chip) {
- dev_err(&client->dev, "unknown chip type '%s'\n",
- client->name);
- return -ENODEV;
- }
-
if (!i2c_check_functionality(adapter,
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EIO;
@@ -361,7 +348,7 @@
ds1307->msg[1].len = sizeof(ds1307->regs);
ds1307->msg[1].buf = ds1307->regs;
- ds1307->type = chip->type;
+ ds1307->type = id->driver_data;
switch (ds1307->type) {
case ds_1337:
@@ -550,6 +537,7 @@
},
.probe = ds1307_probe,
.remove = __devexit_p(ds1307_remove),
+ .id_table = ds1307_id,
};
static int __init ds1307_init(void)
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 45bda18..fa2d2f8 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -41,6 +41,12 @@
#define DS1374_REG_SR_AF 0x01 /* Alarm Flag */
#define DS1374_REG_TCR 0x09 /* Trickle Charge */
+static const struct i2c_device_id ds1374_id[] = {
+ { "rtc-ds1374", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ds1374_id);
+
struct ds1374 {
struct i2c_client *client;
struct rtc_device *rtc;
@@ -355,7 +361,8 @@
.ioctl = ds1374_ioctl,
};
-static int ds1374_probe(struct i2c_client *client)
+static int ds1374_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ds1374 *ds1374;
int ret;
@@ -429,6 +436,7 @@
},
.probe = ds1374_probe,
.remove = __devexit_p(ds1374_remove),
+ .id_table = ds1374_id,
};
static int __init ds1374_init(void)
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index fb15e3f..fbb90b1 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -490,7 +490,7 @@
}
static int
-isl1208_probe(struct i2c_client *client)
+isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int rc = 0;
struct rtc_device *rtc;
@@ -545,12 +545,19 @@
return 0;
}
+static const struct i2c_device_id isl1208_id[] = {
+ { "isl1208", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, isl1208_id);
+
static struct i2c_driver isl1208_driver = {
.driver = {
.name = "rtc-isl1208",
},
.probe = isl1208_probe,
.remove = isl1208_remove,
+ .id_table = isl1208_id,
};
static int __init
diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c
index 1cb33ca..316bfaa 100644
--- a/drivers/rtc/rtc-m41t80.c
+++ b/drivers/rtc/rtc-m41t80.c
@@ -60,48 +60,21 @@
#define DRV_VERSION "0.05"
-struct m41t80_chip_info {
- const char *name;
- u8 features;
+static const struct i2c_device_id m41t80_id[] = {
+ { "m41t80", 0 },
+ { "m41t81", M41T80_FEATURE_HT },
+ { "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
+ { }
};
-
-static const struct m41t80_chip_info m41t80_chip_info_tbl[] = {
- {
- .name = "m41t80",
- .features = 0,
- },
- {
- .name = "m41t81",
- .features = M41T80_FEATURE_HT,
- },
- {
- .name = "m41t81s",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41t82",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41t83",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41st84",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41st85",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
- {
- .name = "m41st87",
- .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL,
- },
-};
+MODULE_DEVICE_TABLE(i2c, m41t80_id);
struct m41t80_data {
- const struct m41t80_chip_info *chip;
+ u8 features;
struct rtc_device *rtc;
};
@@ -208,7 +181,7 @@
struct m41t80_data *clientdata = i2c_get_clientdata(client);
u8 reg;
- if (clientdata->chip->features & M41T80_FEATURE_BL) {
+ if (clientdata->features & M41T80_FEATURE_BL) {
reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
seq_printf(seq, "battery\t\t: %s\n",
(reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok");
@@ -756,12 +729,12 @@
*
*****************************************************************************
*/
-static int m41t80_probe(struct i2c_client *client)
+static int m41t80_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- int i, rc = 0;
+ int rc = 0;
struct rtc_device *rtc = NULL;
struct rtc_time tm;
- const struct m41t80_chip_info *chip;
struct m41t80_data *clientdata = NULL;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C
@@ -773,19 +746,6 @@
dev_info(&client->dev,
"chip found, driver version " DRV_VERSION "\n");
- chip = NULL;
- for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) {
- if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) {
- chip = &m41t80_chip_info_tbl[i];
- break;
- }
- }
- if (!chip) {
- dev_err(&client->dev, "%s is not supported\n", client->name);
- rc = -ENODEV;
- goto exit;
- }
-
clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL);
if (!clientdata) {
rc = -ENOMEM;
@@ -801,7 +761,7 @@
}
clientdata->rtc = rtc;
- clientdata->chip = chip;
+ clientdata->features = id->driver_data;
i2c_set_clientdata(client, clientdata);
/* Make sure HT (Halt Update) bit is cleared */
@@ -810,7 +770,7 @@
goto ht_err;
if (rc & M41T80_ALHOUR_HT) {
- if (chip->features & M41T80_FEATURE_HT) {
+ if (clientdata->features & M41T80_FEATURE_HT) {
m41t80_get_datetime(client, &tm);
dev_info(&client->dev, "HT bit was set!\n");
dev_info(&client->dev,
@@ -842,7 +802,7 @@
goto exit;
#ifdef CONFIG_RTC_DRV_M41T80_WDT
- if (chip->features & M41T80_FEATURE_HT) {
+ if (clientdata->features & M41T80_FEATURE_HT) {
rc = misc_register(&wdt_dev);
if (rc)
goto exit;
@@ -878,7 +838,7 @@
struct rtc_device *rtc = clientdata->rtc;
#ifdef CONFIG_RTC_DRV_M41T80_WDT
- if (clientdata->chip->features & M41T80_FEATURE_HT) {
+ if (clientdata->features & M41T80_FEATURE_HT) {
misc_deregister(&wdt_dev);
unregister_reboot_notifier(&wdt_notifier);
}
@@ -896,6 +856,7 @@
},
.probe = m41t80_probe,
.remove = m41t80_remove,
+ .id_table = m41t80_id,
};
static int __init m41t80_rtc_init(void)
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index a41681d..0fc4c36 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -246,7 +246,8 @@
.set_time = pcf8563_rtc_set_time,
};
-static int pcf8563_probe(struct i2c_client *client)
+static int pcf8563_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct pcf8563 *pcf8563;
@@ -299,12 +300,19 @@
return 0;
}
+static const struct i2c_device_id pcf8563_id[] = {
+ { "pcf8563", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf8563_id);
+
static struct i2c_driver pcf8563_driver = {
.driver = {
.name = "rtc-pcf8563",
},
.probe = pcf8563_probe,
.remove = pcf8563_remove,
+ .id_table = pcf8563_id,
};
static int __init pcf8563_init(void)
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index 8d300e6..0c6257a 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -108,12 +108,10 @@
if (rtc->id == 0) {
struct proc_dir_entry *ent;
- ent = create_proc_entry("driver/rtc", 0, NULL);
- if (ent) {
- ent->proc_fops = &rtc_proc_fops;
+ ent = proc_create_data("driver/rtc", 0, NULL,
+ &rtc_proc_fops, rtc);
+ if (ent)
ent->owner = rtc->owner;
- ent->data = rtc;
- }
}
}
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 7e63074..56caf6b 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -69,6 +69,15 @@
rtc_rv5c387a,
};
+static const struct i2c_device_id rs5c372_id[] = {
+ { "rs5c372a", rtc_rs5c372a },
+ { "rs5c372b", rtc_rs5c372b },
+ { "rv5c386", rtc_rv5c386 },
+ { "rv5c387a", rtc_rv5c387a },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rs5c372_id);
+
/* REVISIT: this assumes that:
* - we're in the 21st century, so it's safe to ignore the century
* bit for rv5c38[67] (REG_MONTH bit 7);
@@ -494,7 +503,8 @@
static struct i2c_driver rs5c372_driver;
-static int rs5c372_probe(struct i2c_client *client)
+static int rs5c372_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int err = 0;
struct rs5c372 *rs5c372;
@@ -514,6 +524,7 @@
rs5c372->client = client;
i2c_set_clientdata(client, rs5c372);
+ rs5c372->type = id->driver_data;
/* we read registers 0x0f then 0x00-0x0f; skip the first one */
rs5c372->regs = &rs5c372->buf[1];
@@ -522,19 +533,6 @@
if (err < 0)
goto exit_kfree;
- if (strcmp(client->name, "rs5c372a") == 0)
- rs5c372->type = rtc_rs5c372a;
- else if (strcmp(client->name, "rs5c372b") == 0)
- rs5c372->type = rtc_rs5c372b;
- else if (strcmp(client->name, "rv5c386") == 0)
- rs5c372->type = rtc_rv5c386;
- else if (strcmp(client->name, "rv5c387a") == 0)
- rs5c372->type = rtc_rv5c387a;
- else {
- rs5c372->type = rtc_rs5c372b;
- dev_warn(&client->dev, "assuming rs5c372b\n");
- }
-
/* clock may be set for am/pm or 24 hr time */
switch (rs5c372->type) {
case rtc_rs5c372a:
@@ -651,6 +649,7 @@
},
.probe = rs5c372_probe,
.remove = rs5c372_remove,
+ .id_table = rs5c372_id,
};
static __init int rs5c372_init(void)
diff --git a/drivers/rtc/rtc-s35390a.c b/drivers/rtc/rtc-s35390a.c
index e8abc90..29f47ba 100644
--- a/drivers/rtc/rtc-s35390a.c
+++ b/drivers/rtc/rtc-s35390a.c
@@ -34,6 +34,12 @@
#define S35390A_FLAG_RESET 0x80
#define S35390A_FLAG_TEST 0x01
+static const struct i2c_device_id s35390a_id[] = {
+ { "s35390a", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, s35390a_id);
+
struct s35390a {
struct i2c_client *client[8];
struct rtc_device *rtc;
@@ -195,7 +201,8 @@
static struct i2c_driver s35390a_driver;
-static int s35390a_probe(struct i2c_client *client)
+static int s35390a_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int err;
unsigned int i;
@@ -296,6 +303,7 @@
},
.probe = s35390a_probe,
.remove = s35390a_remove,
+ .id_table = s35390a_id,
};
static int __init s35390a_rtc_init(void)
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 095282f..eaf5594 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -494,7 +494,8 @@
}
-static int x1205_probe(struct i2c_client *client)
+static int x1205_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
int err = 0;
unsigned char sr;
@@ -552,12 +553,19 @@
return 0;
}
+static const struct i2c_device_id x1205_id[] = {
+ { "x1205", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, x1205_id);
+
static struct i2c_driver x1205_driver = {
.driver = {
.name = "rtc-x1205",
},
.probe = x1205_probe,
.remove = x1205_remove,
+ .id_table = x1205_id,
};
static int __init x1205_init(void)
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 556063e..03c0e40 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -157,6 +157,7 @@
}
static const struct file_operations dasd_devices_file_ops = {
+ .owner = THIS_MODULE,
.open = dasd_devices_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -311,17 +312,16 @@
int
dasd_proc_init(void)
{
- dasd_proc_root_entry = proc_mkdir("dasd", &proc_root);
+ dasd_proc_root_entry = proc_mkdir("dasd", NULL);
if (!dasd_proc_root_entry)
goto out_nodasd;
dasd_proc_root_entry->owner = THIS_MODULE;
- dasd_devices_entry = create_proc_entry("devices",
- S_IFREG | S_IRUGO | S_IWUSR,
- dasd_proc_root_entry);
+ dasd_devices_entry = proc_create("devices",
+ S_IFREG | S_IRUGO | S_IWUSR,
+ dasd_proc_root_entry,
+ &dasd_devices_file_ops);
if (!dasd_devices_entry)
goto out_nodevices;
- dasd_devices_entry->proc_fops = &dasd_devices_file_ops;
- dasd_devices_entry->owner = THIS_MODULE;
dasd_statistics_entry = create_proc_entry("statistics",
S_IFREG | S_IRUGO | S_IWUSR,
dasd_proc_root_entry);
@@ -335,7 +335,7 @@
out_nostatistics:
remove_proc_entry("devices", dasd_proc_root_entry);
out_nodevices:
- remove_proc_entry("dasd", &proc_root);
+ remove_proc_entry("dasd", NULL);
out_nodasd:
return -ENOENT;
}
@@ -345,5 +345,5 @@
{
remove_proc_entry("devices", dasd_proc_root_entry);
remove_proc_entry("statistics", dasd_proc_root_entry);
- remove_proc_entry("dasd", &proc_root);
+ remove_proc_entry("dasd", NULL);
}
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 0e1f35c..3e5653c 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -982,15 +982,16 @@
/*
* Put character routine for 3215 ttys
*/
-static void
+static int
tty3215_put_char(struct tty_struct *tty, unsigned char ch)
{
struct raw3215_info *raw;
if (!tty)
- return;
+ return 0;
raw = (struct raw3215_info *) tty->driver_data;
raw3215_putchar(raw, ch);
+ return 1;
}
static void
diff --git a/drivers/s390/char/sclp_config.c b/drivers/s390/char/sclp_config.c
index b8f35bc..9e784d5 100644
--- a/drivers/s390/char/sclp_config.c
+++ b/drivers/s390/char/sclp_config.c
@@ -10,6 +10,7 @@
#include <linux/cpu.h>
#include <linux/sysdev.h>
#include <linux/workqueue.h>
+#include <asm/smp.h>
#include "sclp.h"
#define TAG "sclp_config: "
@@ -19,9 +20,11 @@
u8 ev_qualifier;
} __attribute__((packed));
+#define EV_QUAL_CPU_CHANGE 1
#define EV_QUAL_CAP_CHANGE 3
static struct work_struct sclp_cpu_capability_work;
+static struct work_struct sclp_cpu_change_work;
static void sclp_cpu_capability_notify(struct work_struct *work)
{
@@ -37,13 +40,24 @@
put_online_cpus();
}
+static void sclp_cpu_change_notify(struct work_struct *work)
+{
+ smp_rescan_cpus();
+}
+
static void sclp_conf_receiver_fn(struct evbuf_header *evbuf)
{
struct conf_mgm_data *cdata;
cdata = (struct conf_mgm_data *)(evbuf + 1);
- if (cdata->ev_qualifier == EV_QUAL_CAP_CHANGE)
+ switch (cdata->ev_qualifier) {
+ case EV_QUAL_CPU_CHANGE:
+ schedule_work(&sclp_cpu_change_work);
+ break;
+ case EV_QUAL_CAP_CHANGE:
schedule_work(&sclp_cpu_capability_work);
+ break;
+ }
}
static struct sclp_register sclp_conf_register =
@@ -57,6 +71,7 @@
int rc;
INIT_WORK(&sclp_cpu_capability_work, sclp_cpu_capability_notify);
+ INIT_WORK(&sclp_cpu_change_work, sclp_cpu_change_notify);
rc = sclp_register(&sclp_conf_register);
if (rc) {
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index e3b3d39..40b1152 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -412,14 +412,14 @@
* - including previous characters from sclp_tty_put_char() and strings from
* sclp_write() without final '\n' - will be written.
*/
-static void
+static int
sclp_tty_put_char(struct tty_struct *tty, unsigned char ch)
{
sclp_tty_chars[sclp_tty_chars_count++] = ch;
if (ch == '\n' || sclp_tty_chars_count >= SCLP_TTY_BUF_SIZE) {
sclp_tty_write_string(sclp_tty_chars, sclp_tty_chars_count);
sclp_tty_chars_count = 0;
- }
+ } return 1;
}
/*
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index ed50759..35707c0 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -524,11 +524,15 @@
* NOTE: include/linux/tty_driver.h specifies that a character should be
* ignored if there is no room in the queue. This driver implements a different
* semantic in that it will block when there is no more room left.
+ *
+ * FIXME: putchar can currently be called from BH and other non blocking
+ * handlers so this semantic isn't a good idea.
*/
-static void
+static int
sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch)
{
__sclp_vt220_write(&ch, 1, 0, 0, 1);
+ return 1;
}
/*
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index c9b96d5..e7c888c 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -111,6 +111,7 @@
static const struct file_operations tape_proc_ops =
{
+ .owner = THIS_MODULE,
.open = tape_proc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -124,14 +125,12 @@
tape_proc_init(void)
{
tape_proc_devices =
- create_proc_entry ("tapedevices", S_IFREG | S_IRUGO | S_IWUSR,
- &proc_root);
+ proc_create("tapedevices", S_IFREG | S_IRUGO | S_IWUSR, NULL,
+ &tape_proc_ops);
if (tape_proc_devices == NULL) {
PRINT_WARN("tape: Cannot register procfs entry tapedevices\n");
return;
}
- tape_proc_devices->proc_fops = &tape_proc_ops;
- tape_proc_devices->owner = THIS_MODULE;
}
/*
@@ -141,5 +140,5 @@
tape_proc_cleanup(void)
{
if (tape_proc_devices != NULL)
- remove_proc_entry ("tapedevices", &proc_root);
+ remove_proc_entry ("tapedevices", NULL);
}
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 70b1980a..c1f2ade 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -965,7 +965,7 @@
* Insert character into the screen at the current position with the
* current color and highlight. This function does NOT do cursor movement.
*/
-static void
+static int
tty3270_put_character(struct tty3270 *tp, char ch)
{
struct tty3270_line *line;
@@ -986,6 +986,7 @@
cell->character = tp->view.ascebc[(unsigned int) ch];
cell->highlight = tp->highlight;
cell->f_color = tp->f_color;
+ return 1;
}
/*
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index e8597ec..40ef948 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -374,13 +374,10 @@
{
struct proc_dir_entry *entry;
- entry = create_proc_entry ("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR,
- &proc_root);
+ entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL,
+ &cio_ignore_proc_fops);
if (!entry)
return -ENOENT;
-
- entry->proc_fops = &cio_ignore_proc_fops;
-
return 0;
}
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index fe1ad17..26a930e 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -152,44 +152,89 @@
return 0;
}
+static int __get_next_bus_id(const char **buf, char *bus_id)
+{
+ int rc, len;
+ char *start, *end;
+
+ start = (char *)*buf;
+ end = strchr(start, ',');
+ if (!end) {
+ /* Last entry. Strip trailing newline, if applicable. */
+ end = strchr(start, '\n');
+ if (end)
+ *end = '\0';
+ len = strlen(start) + 1;
+ } else {
+ len = end - start + 1;
+ end++;
+ }
+ if (len < BUS_ID_SIZE) {
+ strlcpy(bus_id, start, len);
+ rc = 0;
+ } else
+ rc = -EINVAL;
+ *buf = end;
+ return rc;
+}
+
+static int __is_valid_bus_id(char bus_id[BUS_ID_SIZE])
+{
+ int cssid, ssid, devno;
+
+ /* Must be of form %x.%x.%04x */
+ if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3)
+ return 0;
+ return 1;
+}
+
/**
- * ccwgroup_create() - create and register a ccw group device
+ * ccwgroup_create_from_string() - create and register a ccw group device
* @root: parent device for the new device
* @creator_id: identifier of creating driver
* @cdrv: ccw driver of slave devices
- * @argc: number of slave devices
- * @argv: bus ids of slave devices
+ * @num_devices: number of slave devices
+ * @buf: buffer containing comma separated bus ids of slave devices
*
* Create and register a new ccw group device as a child of @root. Slave
- * devices are obtained from the list of bus ids given in @argv[] and must all
+ * devices are obtained from the list of bus ids given in @buf and must all
* belong to @cdrv.
* Returns:
* %0 on success and an error code on failure.
* Context:
* non-atomic
*/
-int ccwgroup_create(struct device *root, unsigned int creator_id,
- struct ccw_driver *cdrv, int argc, char *argv[])
+int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
+ struct ccw_driver *cdrv, int num_devices,
+ const char *buf)
{
struct ccwgroup_device *gdev;
- int i;
- int rc;
+ int rc, i;
+ char tmp_bus_id[BUS_ID_SIZE];
+ const char *curr_buf;
- if (argc > 256) /* disallow dumb users */
- return -EINVAL;
-
- gdev = kzalloc(sizeof(*gdev) + argc*sizeof(gdev->cdev[0]), GFP_KERNEL);
+ gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]),
+ GFP_KERNEL);
if (!gdev)
return -ENOMEM;
atomic_set(&gdev->onoff, 0);
mutex_init(&gdev->reg_mutex);
mutex_lock(&gdev->reg_mutex);
- for (i = 0; i < argc; i++) {
- gdev->cdev[i] = get_ccwdev_by_busid(cdrv, argv[i]);
-
- /* all devices have to be of the same type in
- * order to be grouped */
+ curr_buf = buf;
+ for (i = 0; i < num_devices && curr_buf; i++) {
+ rc = __get_next_bus_id(&curr_buf, tmp_bus_id);
+ if (rc != 0)
+ goto error;
+ if (!__is_valid_bus_id(tmp_bus_id)) {
+ rc = -EINVAL;
+ goto error;
+ }
+ gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id);
+ /*
+ * All devices have to be of the same type in
+ * order to be grouped.
+ */
if (!gdev->cdev[i]
|| gdev->cdev[i]->id.driver_info !=
gdev->cdev[0]->id.driver_info) {
@@ -203,9 +248,18 @@
}
dev_set_drvdata(&gdev->cdev[i]->dev, gdev);
}
-
+ /* Check for sufficient number of bus ids. */
+ if (i < num_devices && !curr_buf) {
+ rc = -EINVAL;
+ goto error;
+ }
+ /* Check for trailing stuff. */
+ if (i == num_devices && strlen(curr_buf) > 0) {
+ rc = -EINVAL;
+ goto error;
+ }
gdev->creator_id = creator_id;
- gdev->count = argc;
+ gdev->count = num_devices;
gdev->dev.bus = &ccwgroup_bus_type;
gdev->dev.parent = root;
gdev->dev.release = ccwgroup_release;
@@ -233,7 +287,7 @@
device_remove_file(&gdev->dev, &dev_attr_ungroup);
device_unregister(&gdev->dev);
error:
- for (i = 0; i < argc; i++)
+ for (i = 0; i < num_devices; i++)
if (gdev->cdev[i]) {
if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev)
dev_set_drvdata(&gdev->cdev[i]->dev, NULL);
@@ -243,6 +297,7 @@
put_device(&gdev->dev);
return rc;
}
+EXPORT_SYMBOL(ccwgroup_create_from_string);
static int __init
init_ccwgroup (void)
@@ -318,7 +373,7 @@
{
struct ccwgroup_device *gdev;
struct ccwgroup_driver *gdrv;
- unsigned int value;
+ unsigned long value;
int ret;
gdev = to_ccwgroupdev(dev);
@@ -329,7 +384,9 @@
if (!try_module_get(gdrv->owner))
return -EINVAL;
- value = simple_strtoul(buf, NULL, 0);
+ ret = strict_strtoul(buf, 0, &value);
+ if (ret)
+ goto out;
ret = count;
if (value == 1)
ccwgroup_set_online(gdev);
@@ -337,6 +394,7 @@
ccwgroup_set_offline(gdev);
else
ret = -EINVAL;
+out:
module_put(gdrv->owner);
return ret;
}
@@ -518,6 +576,5 @@
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ccwgroup_driver_register);
EXPORT_SYMBOL(ccwgroup_driver_unregister);
-EXPORT_SYMBOL(ccwgroup_create);
EXPORT_SYMBOL(ccwgroup_probe_ccwdev);
EXPORT_SYMBOL(ccwgroup_remove_ccwdev);
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 23ffcc4..08a5781 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -407,8 +407,7 @@
/*
* Enable subchannel.
*/
-int cio_enable_subchannel(struct subchannel *sch, unsigned int isc,
- u32 intparm)
+int cio_enable_subchannel(struct subchannel *sch, u32 intparm)
{
char dbf_txt[15];
int ccode;
@@ -426,7 +425,7 @@
for (retry = 5, ret = 0; retry > 0; retry--) {
sch->schib.pmcw.ena = 1;
- sch->schib.pmcw.isc = isc;
+ sch->schib.pmcw.isc = sch->isc;
sch->schib.pmcw.intparm = intparm;
ret = cio_modify(sch);
if (ret == -ENODEV)
@@ -600,6 +599,7 @@
else
sch->opm = chp_get_sch_opm(sch);
sch->lpm = sch->schib.pmcw.pam & sch->opm;
+ sch->isc = 3;
CIO_DEBUG(KERN_INFO, 0,
"Detected device %04x on subchannel 0.%x.%04X"
@@ -610,13 +610,11 @@
/*
* We now have to initially ...
- * ... set "interruption subclass"
* ... enable "concurrent sense"
* ... enable "multipath mode" if more than one
* CHPID is available. This is done regardless
* whether multiple paths are available for us.
*/
- sch->schib.pmcw.isc = 3; /* could be smth. else */
sch->schib.pmcw.csense = 1; /* concurrent sense */
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
@@ -812,6 +810,7 @@
* enable console I/O-interrupt subclass 7
*/
ctl_set_bit(6, 24);
+ console_subchannel.isc = 7;
console_subchannel.schib.pmcw.isc = 7;
console_subchannel.schib.pmcw.intparm =
(u32)(addr_t)&console_subchannel;
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 08f2235..3c75412 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -74,6 +74,7 @@
__u8 lpm; /* logical path mask */
__u8 opm; /* operational path mask */
struct schib schib; /* subchannel information block */
+ int isc; /* desired interruption subclass */
struct chsc_ssd_info ssd_info; /* subchannel description */
struct device dev; /* entry in device tree */
struct css_driver *driver;
@@ -85,7 +86,7 @@
#define to_subchannel(n) container_of(n, struct subchannel, dev)
extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
-extern int cio_enable_subchannel(struct subchannel *, unsigned int, u32);
+extern int cio_enable_subchannel(struct subchannel *, u32);
extern int cio_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *);
extern int cio_clear (struct subchannel *);
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c
index f4c132a..2808b68 100644
--- a/drivers/s390/cio/cmf.c
+++ b/drivers/s390/cio/cmf.c
@@ -1219,16 +1219,21 @@
{
struct ccw_device *cdev;
int ret;
+ unsigned long val;
+
+ ret = strict_strtoul(buf, 16, &val);
+ if (ret)
+ return ret;
cdev = to_ccwdev(dev);
- switch (buf[0]) {
- case '0':
+ switch (val) {
+ case 0:
ret = disable_cmf(cdev);
if (ret)
dev_info(&cdev->dev, "disable_cmf failed (%d)\n", ret);
break;
- case '1':
+ case 1:
ret = enable_cmf(cdev);
if (ret && ret != -EBUSY)
dev_info(&cdev->dev, "enable_cmf failed (%d)\n", ret);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index c1afab5..595e327 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -705,13 +705,17 @@
{
struct channel_subsystem *css = to_css(dev);
int ret;
+ unsigned long val;
+ ret = strict_strtoul(buf, 16, &val);
+ if (ret)
+ return ret;
mutex_lock(&css->mutex);
- switch (buf[0]) {
- case '0':
+ switch (val) {
+ case 0:
ret = css->cm_enabled ? chsc_secm(css, 0) : 0;
break;
- case '1':
+ case 1:
ret = css->cm_enabled ? 0 : chsc_secm(css, 1);
break;
default:
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index e0c7adb..abfd601 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -512,8 +512,8 @@
const char *buf, size_t count)
{
struct ccw_device *cdev = to_ccwdev(dev);
- int i, force;
- char *tmp;
+ int force, ret;
+ unsigned long i;
if (atomic_cmpxchg(&cdev->private->onoff, 0, 1) != 0)
return -EAGAIN;
@@ -525,25 +525,30 @@
if (!strncmp(buf, "force\n", count)) {
force = 1;
i = 1;
+ ret = 0;
} else {
force = 0;
- i = simple_strtoul(buf, &tmp, 16);
+ ret = strict_strtoul(buf, 16, &i);
}
-
+ if (ret)
+ goto out;
switch (i) {
case 0:
online_store_handle_offline(cdev);
+ ret = count;
break;
case 1:
online_store_handle_online(cdev, force);
+ ret = count;
break;
default:
- count = -EINVAL;
+ ret = -EINVAL;
}
+out:
if (cdev->drv)
module_put(cdev->drv->owner);
atomic_set(&cdev->private->onoff, 0);
- return count;
+ return ret;
}
static ssize_t
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 4b92c84..99403b0 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -555,8 +555,7 @@
(cdev->private->state != DEV_STATE_BOXED))
return -EINVAL;
sch = to_subchannel(cdev->dev.parent);
- ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
- (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
if (ret != 0)
/* Couldn't enable the subchannel for i/o. Sick device. */
return ret;
@@ -667,8 +666,7 @@
sch = to_subchannel(cdev->dev.parent);
if (css_init_done && !get_device(&cdev->dev))
return -ENODEV;
- ret = cio_enable_subchannel(sch, sch->schib.pmcw.isc,
- (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
if (ret != 0) {
/* Couldn't enable the subchannel for i/o. Sick device. */
if (ret == -ENODEV)
@@ -1048,8 +1046,7 @@
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
- if (cio_enable_subchannel(sch, sch->schib.pmcw.isc,
- (u32)(addr_t)sch) != 0)
+ if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0)
/* Couldn't enable the subchannel for i/o. Sick device. */
return;
@@ -1082,7 +1079,6 @@
*/
sch->lpm = sch->schib.pmcw.pam & sch->opm;
/* Re-set some bits in the pmcw that were lost. */
- sch->schib.pmcw.isc = 3;
sch->schib.pmcw.csense = 1;
sch->schib.pmcw.ena = 0;
if ((sch->lpm & (sch->lpm - 1)) != 0)
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index a1718a0..f308ad5 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -508,7 +508,7 @@
return -ENOMEM;
}
spin_lock_irqsave(sch->lock, flags);
- ret = cio_enable_subchannel(sch, 3, (u32)(addr_t)sch);
+ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch);
if (ret)
goto out_unlock;
/*
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index 10aa1e7..445cf36 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -3632,7 +3632,7 @@
{
proc_perf_file_registration=0;
qdio_perf_proc_file=create_proc_entry(QDIO_PERF,
- S_IFREG|0444,&proc_root);
+ S_IFREG|0444,NULL);
if (qdio_perf_proc_file) {
qdio_perf_proc_file->read_proc=&qdio_perf_procfile_read;
} else proc_perf_file_registration=-1;
@@ -3647,7 +3647,7 @@
qdio_remove_procfs_entry(void)
{
if (!proc_perf_file_registration) /* means if it went ok earlier */
- remove_proc_entry(QDIO_PERF,&proc_root);
+ remove_proc_entry(QDIO_PERF,NULL);
}
/**
@@ -3663,11 +3663,11 @@
static ssize_t
qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count)
{
- char *tmp;
- int i;
+ unsigned long i;
+ int ret;
- i = simple_strtoul(buf, &tmp, 16);
- if ((i == 0) || (i == 1)) {
+ ret = strict_strtoul(buf, 16, &i);
+ if (!ret && ((i == 0) || (i == 1))) {
if (i == qdio_performance_stats)
return count;
qdio_performance_stats = i;
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index bbef376..47a7e62 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -17,6 +17,7 @@
#include <linux/virtio_config.h>
#include <linux/interrupt.h>
#include <linux/virtio_ring.h>
+#include <linux/pfn.h>
#include <asm/io.h>
#include <asm/kvm_para.h>
#include <asm/kvm_virtio.h>
@@ -180,11 +181,10 @@
config = kvm_vq_config(kdev->desc)+index;
- if (add_shared_memory(config->address,
- vring_size(config->num, PAGE_SIZE))) {
- err = -ENOMEM;
+ err = vmem_add_mapping(config->address,
+ vring_size(config->num, PAGE_SIZE));
+ if (err)
goto out;
- }
vq = vring_new_virtqueue(config->num, vdev, (void *) config->address,
kvm_notify, callback);
@@ -202,8 +202,8 @@
vq->priv = config;
return vq;
unmap:
- remove_shared_memory(config->address, vring_size(config->num,
- PAGE_SIZE));
+ vmem_remove_mapping(config->address,
+ vring_size(config->num, PAGE_SIZE));
out:
return ERR_PTR(err);
}
@@ -213,8 +213,8 @@
struct kvm_vqconfig *config = vq->priv;
vring_del_virtqueue(vq);
- remove_shared_memory(config->address,
- vring_size(config->num, PAGE_SIZE));
+ vmem_remove_mapping(config->address,
+ vring_size(config->num, PAGE_SIZE));
}
/*
@@ -318,12 +318,13 @@
return rc;
}
- if (add_shared_memory((max_pfn) << PAGE_SHIFT, PAGE_SIZE)) {
+ rc = vmem_add_mapping(PFN_PHYS(max_pfn), PAGE_SIZE);
+ if (rc) {
device_unregister(&kvm_root);
- return -ENOMEM;
+ return rc;
}
- kvm_devices = (void *) (max_pfn << PAGE_SHIFT);
+ kvm_devices = (void *) PFN_PHYS(max_pfn);
ctl_set_bit(0, 9);
register_external_interrupt(0x2603, kvm_extint_handler);
diff --git a/drivers/s390/net/cu3088.c b/drivers/s390/net/cu3088.c
index 76728ae..8e76973 100644
--- a/drivers/s390/net/cu3088.c
+++ b/drivers/s390/net/cu3088.c
@@ -62,30 +62,14 @@
static ssize_t
group_write(struct device_driver *drv, const char *buf, size_t count)
{
- const char *start, *end;
- char bus_ids[2][BUS_ID_SIZE], *argv[2];
- int i;
int ret;
struct ccwgroup_driver *cdrv;
cdrv = to_ccwgroupdrv(drv);
if (!cdrv)
return -EINVAL;
- start = buf;
- for (i=0; i<2; i++) {
- static const char delim[] = {',', '\n'};
- int len;
-
- if (!(end = strchr(start, delim[i])))
- return -EINVAL;
- len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start + 1);
- strlcpy (bus_ids[i], start, len);
- argv[i] = bus_ids[i];
- start = end + 1;
- }
-
- ret = ccwgroup_create(cu3088_root_dev, cdrv->driver_id,
- &cu3088_driver, 2, argv);
+ ret = ccwgroup_create_from_string(cu3088_root_dev, cdrv->driver_id,
+ &cu3088_driver, 2, buf);
return (ret == 0) ? count : ret;
}
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index f51ed99..dd22f4b 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -1793,7 +1793,8 @@
skb->protocol = card->lan_type_trans(skb, card->dev);
card->stats.rx_bytes += skb_len;
card->stats.rx_packets++;
- *((__u32 *)skb->cb) = ++card->pkt_seq;
+ if (skb->protocol == htons(ETH_P_802_2))
+ *((__u32 *)skb->cb) = ++card->pkt_seq;
netif_rx(skb);
}
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 8f876f6..e4ba6a0 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1313,8 +1313,6 @@
* and throw away packet.
*/
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
- if (!in_atomic())
- fsm_event(privptr->fsm, DEV_EVENT_START, dev);
dev_kfree_skb(skb);
privptr->stats.tx_dropped++;
privptr->stats.tx_errors++;
@@ -2147,6 +2145,7 @@
if (rc)
goto out_dbf;
IUCV_DBF_TEXT(trace, 3, __func__);
+ netiucv_driver.groups = netiucv_drv_attr_groups;
rc = driver_register(&netiucv_driver);
if (rc) {
PRINT_ERR("NETIUCV: failed to register driver.\n");
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 66f4f12..699ac11 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -72,22 +72,7 @@
debug_sprintf_event(qeth_dbf[QETH_DBF_MSG].id, level, text)
#define QETH_DBF_TEXT_(name, level, text...) \
- do { \
- if (qeth_dbf_passes(qeth_dbf[QETH_DBF_##name].id, level)) { \
- char *dbf_txt_buf = \
- get_cpu_var(QETH_DBF_TXT_BUF); \
- sprintf(dbf_txt_buf, text); \
- debug_text_event(qeth_dbf[QETH_DBF_##name].id, \
- level, dbf_txt_buf); \
- put_cpu_var(QETH_DBF_TXT_BUF); \
- } \
- } while (0)
-
-/* Allow to sort out low debug levels early to avoid wasted sprints */
-static inline int qeth_dbf_passes(debug_info_t *dbf_grp, int level)
-{
- return (level <= dbf_grp->level);
-}
+ qeth_dbf_longtext(QETH_DBF_##name, level, text)
/**
* some more debug stuff
@@ -773,27 +758,6 @@
return (int) (get_clock() >> 12);
}
-static inline void *qeth_push_skb(struct qeth_card *card, struct sk_buff *skb,
- int size)
-{
- void *hdr;
-
- hdr = (void *) skb_push(skb, size);
- /*
- * sanity check, the Linux memory allocation scheme should
- * never present us cases like this one (the qdio header size plus
- * the first 40 bytes of the paket cross a 4k boundary)
- */
- if ((((unsigned long) hdr) & (~(PAGE_SIZE - 1))) !=
- (((unsigned long) hdr + size +
- QETH_IP_HEADER_SIZE) & (~(PAGE_SIZE - 1)))) {
- PRINT_ERR("Misaligned packet on interface %s. Discarded.",
- QETH_CARD_IFNAME(card));
- return NULL;
- }
- return hdr;
-}
-
static inline int qeth_get_ip_version(struct sk_buff *skb)
{
switch (skb->protocol) {
@@ -806,6 +770,12 @@
}
}
+static inline void qeth_put_buffer_pool_entry(struct qeth_card *card,
+ struct qeth_buffer_pool_entry *entry)
+{
+ list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
+}
+
struct qeth_eddp_context;
extern struct ccwgroup_driver qeth_l2_ccwgroup_driver;
extern struct ccwgroup_driver qeth_l3_ccwgroup_driver;
@@ -843,8 +813,6 @@
int qeth_query_setadapterparms(struct qeth_card *);
int qeth_check_qdio_errors(struct qdio_buffer *, unsigned int,
unsigned int, const char *);
-void qeth_put_buffer_pool_entry(struct qeth_card *,
- struct qeth_buffer_pool_entry *);
void qeth_queue_input_buffer(struct qeth_card *, int);
struct sk_buff *qeth_core_get_next_skb(struct qeth_card *,
struct qdio_buffer *, struct qdio_buffer_element **, int *,
@@ -880,8 +848,6 @@
void *reply_param);
int qeth_get_cast_type(struct qeth_card *, struct sk_buff *);
int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
-struct sk_buff *qeth_prepare_skb(struct qeth_card *, struct sk_buff *,
- struct qeth_hdr **);
int qeth_get_elements_no(struct qeth_card *, void *, struct sk_buff *, int);
int qeth_do_send_packet_fast(struct qeth_card *, struct qeth_qdio_out_q *,
struct sk_buff *, struct qeth_hdr *, int,
@@ -894,6 +860,8 @@
struct ethtool_stats *, u64 *);
void qeth_core_get_strings(struct net_device *, u32, u8 *);
void qeth_core_get_drvinfo(struct net_device *, struct ethtool_drvinfo *);
+void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...);
+int qeth_core_ethtool_get_settings(struct net_device *, struct ethtool_cmd *);
/* exports for OSN */
int qeth_osn_assist(struct net_device *, void *, int);
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c
index 055f5c3..436bf1f 100644
--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -26,9 +26,6 @@
#include "qeth_core.h"
#include "qeth_core_offl.h"
-static DEFINE_PER_CPU(char[256], qeth_core_dbf_txt_buf);
-#define QETH_DBF_TXT_BUF qeth_core_dbf_txt_buf
-
struct qeth_dbf_info qeth_dbf[QETH_DBF_INFOS] = {
/* define dbf - Name, Pages, Areas, Maxlen, Level, View, Handle */
/* N P A M L V H */
@@ -2255,14 +2252,6 @@
}
EXPORT_SYMBOL_GPL(qeth_print_status_message);
-void qeth_put_buffer_pool_entry(struct qeth_card *card,
- struct qeth_buffer_pool_entry *entry)
-{
- QETH_DBF_TEXT(TRACE, 6, "ptbfplen");
- list_add_tail(&entry->list, &card->qdio.in_buf_pool.entry_list);
-}
-EXPORT_SYMBOL_GPL(qeth_put_buffer_pool_entry);
-
static void qeth_initialize_working_pool_list(struct qeth_card *card)
{
struct qeth_buffer_pool_entry *entry;
@@ -2603,7 +2592,6 @@
int rc;
int newcount = 0;
- QETH_DBF_TEXT(TRACE, 6, "queinbuf");
count = (index < queue->next_buf_to_init)?
card->qdio.in_buf_pool.buf_count -
(queue->next_buf_to_init - index) :
@@ -2792,8 +2780,6 @@
int i;
unsigned int qdio_flags;
- QETH_DBF_TEXT(TRACE, 6, "flushbuf");
-
for (i = index; i < index + count; ++i) {
buf = &queue->bufs[i % QDIO_MAX_BUFFERS_PER_Q];
buf->buffer->element[buf->next_element_to_fill - 1].flags |=
@@ -3037,49 +3023,6 @@
}
EXPORT_SYMBOL_GPL(qeth_get_priority_queue);
-static void __qeth_free_new_skb(struct sk_buff *orig_skb,
- struct sk_buff *new_skb)
-{
- if (orig_skb != new_skb)
- dev_kfree_skb_any(new_skb);
-}
-
-static inline struct sk_buff *qeth_realloc_headroom(struct qeth_card *card,
- struct sk_buff *skb, int size)
-{
- struct sk_buff *new_skb = skb;
-
- if (skb_headroom(skb) >= size)
- return skb;
- new_skb = skb_realloc_headroom(skb, size);
- if (!new_skb)
- PRINT_ERR("Could not realloc headroom for qeth_hdr "
- "on interface %s", QETH_CARD_IFNAME(card));
- return new_skb;
-}
-
-struct sk_buff *qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
- struct qeth_hdr **hdr)
-{
- struct sk_buff *new_skb;
-
- QETH_DBF_TEXT(TRACE, 6, "prepskb");
-
- new_skb = qeth_realloc_headroom(card, skb,
- sizeof(struct qeth_hdr));
- if (!new_skb)
- return NULL;
-
- *hdr = ((struct qeth_hdr *)qeth_push_skb(card, new_skb,
- sizeof(struct qeth_hdr)));
- if (*hdr == NULL) {
- __qeth_free_new_skb(skb, new_skb);
- return NULL;
- }
- return new_skb;
-}
-EXPORT_SYMBOL_GPL(qeth_prepare_skb);
-
int qeth_get_elements_no(struct qeth_card *card, void *hdr,
struct sk_buff *skb, int elems)
{
@@ -3100,8 +3043,8 @@
}
EXPORT_SYMBOL_GPL(qeth_get_elements_no);
-static void __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
- int is_tso, int *next_element_to_fill)
+static inline void __qeth_fill_buffer(struct sk_buff *skb,
+ struct qdio_buffer *buffer, int is_tso, int *next_element_to_fill)
{
int length = skb->len;
int length_here;
@@ -3143,15 +3086,13 @@
*next_element_to_fill = element;
}
-static int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
+static inline int qeth_fill_buffer(struct qeth_qdio_out_q *queue,
struct qeth_qdio_out_buffer *buf, struct sk_buff *skb)
{
struct qdio_buffer *buffer;
struct qeth_hdr_tso *hdr;
int flush_cnt = 0, hdr_len, large_send = 0;
- QETH_DBF_TEXT(TRACE, 6, "qdfillbf");
-
buffer = buf->buffer;
atomic_inc(&skb->users);
skb_queue_tail(&buf->skb_list, skb);
@@ -3210,8 +3151,6 @@
int flush_cnt = 0;
int index;
- QETH_DBF_TEXT(TRACE, 6, "dosndpfa");
-
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
@@ -3263,8 +3202,6 @@
int tmp;
int rc = 0;
- QETH_DBF_TEXT(TRACE, 6, "dosndpkt");
-
/* spin until we get the queue ... */
while (atomic_cmpxchg(&queue->state, QETH_OUT_Q_UNLOCKED,
QETH_OUT_Q_LOCKED) != QETH_OUT_Q_UNLOCKED);
@@ -3827,27 +3764,8 @@
static int qeth_core_driver_group(const char *buf, struct device *root_dev,
unsigned long driver_id)
{
- const char *start, *end;
- char bus_ids[3][BUS_ID_SIZE], *argv[3];
- int i;
-
- start = buf;
- for (i = 0; i < 3; i++) {
- static const char delim[] = { ',', ',', '\n' };
- int len;
-
- end = strchr(start, delim[i]);
- if (!end)
- return -EINVAL;
- len = min_t(ptrdiff_t, BUS_ID_SIZE, end - start);
- strncpy(bus_ids[i], start, len);
- bus_ids[i][len] = '\0';
- start = end + 1;
- argv[i] = bus_ids[i];
- }
-
- return (ccwgroup_create(root_dev, driver_id,
- &qeth_ccw_driver, 3, argv));
+ return ccwgroup_create_from_string(root_dev, driver_id,
+ &qeth_ccw_driver, 3, buf);
}
int qeth_core_hardsetup_card(struct qeth_card *card)
@@ -3885,8 +3803,9 @@
QETH_DBF_TEXT_(SETUP, 2, "2err%d", rc);
return rc;
}
-
- mpno = QETH_MAX_PORTNO;
+ mpno = qdio_get_ssqd_pct(CARD_DDEV(card));
+ if (mpno)
+ mpno = min(mpno - 1, QETH_MAX_PORTNO);
if (card->info.portno > mpno) {
PRINT_ERR("Device %s does not offer port number %d \n.",
CARD_BUS_ID(card), card->info.portno);
@@ -3980,7 +3899,6 @@
int use_rx_sg = 0;
int frag = 0;
- QETH_DBF_TEXT(TRACE, 6, "nextskb");
/* qeth_hdr must not cross element boundaries */
if (element->length < offset + sizeof(struct qeth_hdr)) {
if (qeth_is_last_sbale(element))
@@ -4086,6 +4004,18 @@
}
}
+void qeth_dbf_longtext(enum qeth_dbf_names dbf_nix, int level, char *text, ...)
+{
+ char dbf_txt_buf[32];
+
+ if (level > (qeth_dbf[dbf_nix].id)->level)
+ return;
+ snprintf(dbf_txt_buf, sizeof(dbf_txt_buf), text);
+ debug_text_event(qeth_dbf[dbf_nix].id, level, dbf_txt_buf);
+
+}
+EXPORT_SYMBOL_GPL(qeth_dbf_longtext);
+
static int qeth_register_dbf_views(void)
{
int ret;
@@ -4433,6 +4363,96 @@
}
EXPORT_SYMBOL_GPL(qeth_core_get_drvinfo);
+int qeth_core_ethtool_get_settings(struct net_device *netdev,
+ struct ethtool_cmd *ecmd)
+{
+ struct qeth_card *card = netdev_priv(netdev);
+ enum qeth_link_types link_type;
+
+ if ((card->info.type == QETH_CARD_TYPE_IQD) || (card->info.guestlan))
+ link_type = QETH_LINK_TYPE_10GBIT_ETH;
+ else
+ link_type = card->info.link_type;
+
+ ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->supported = SUPPORTED_Autoneg;
+ ecmd->advertising = ADVERTISED_Autoneg;
+ ecmd->duplex = DUPLEX_FULL;
+ ecmd->autoneg = AUTONEG_ENABLE;
+
+ switch (link_type) {
+ case QETH_LINK_TYPE_FAST_ETH:
+ case QETH_LINK_TYPE_LANE_ETH100:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_TP;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_TP;
+ ecmd->speed = SPEED_100;
+ ecmd->port = PORT_TP;
+ break;
+
+ case QETH_LINK_TYPE_GBIT_ETH:
+ case QETH_LINK_TYPE_LANE_ETH1000:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE;
+ ecmd->speed = SPEED_1000;
+ ecmd->port = PORT_FIBRE;
+ break;
+
+ case QETH_LINK_TYPE_10GBIT_ETH:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_100baseT_Half |
+ SUPPORTED_100baseT_Full |
+ SUPPORTED_1000baseT_Half |
+ SUPPORTED_1000baseT_Full |
+ SUPPORTED_10000baseT_Full |
+ SUPPORTED_FIBRE;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Half |
+ ADVERTISED_1000baseT_Full |
+ ADVERTISED_10000baseT_Full |
+ ADVERTISED_FIBRE;
+ ecmd->speed = SPEED_10000;
+ ecmd->port = PORT_FIBRE;
+ break;
+
+ default:
+ ecmd->supported |= SUPPORTED_10baseT_Half |
+ SUPPORTED_10baseT_Full |
+ SUPPORTED_TP;
+ ecmd->advertising |= ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_TP;
+ ecmd->speed = SPEED_10;
+ ecmd->port = PORT_TP;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qeth_core_ethtool_get_settings);
+
static int __init qeth_core_init(void)
{
int rc;
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index 3921d1631..86ec50d 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -22,9 +22,6 @@
#include "qeth_core.h"
#include "qeth_core_offl.h"
-#define QETH_DBF_TXT_BUF qeth_l2_dbf_txt_buf
-static DEFINE_PER_CPU(char[256], qeth_l2_dbf_txt_buf);
-
static int qeth_l2_set_offline(struct ccwgroup_device *);
static int qeth_l2_stop(struct net_device *);
static int qeth_l2_send_delmac(struct qeth_card *, __u8 *);
@@ -635,8 +632,6 @@
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
- QETH_DBF_TEXT(TRACE, 6, "l2xmit");
-
if ((card->state != CARD_STATE_UP) || !card->lan_online) {
card->stats.tx_carrier_errors++;
goto tx_drop;
@@ -658,9 +653,12 @@
if (card->info.type == QETH_CARD_TYPE_OSN)
hdr = (struct qeth_hdr *)skb->data;
else {
- new_skb = qeth_prepare_skb(card, skb, &hdr);
+ /* create a clone with writeable headroom */
+ new_skb = skb_realloc_headroom(skb, sizeof(struct qeth_hdr));
if (!new_skb)
goto tx_drop;
+ hdr = (struct qeth_hdr *)skb_push(new_skb,
+ sizeof(struct qeth_hdr));
qeth_l2_fill_header(card, hdr, new_skb, ipv, cast_type);
}
@@ -747,7 +745,6 @@
int index;
int i;
- QETH_DBF_TEXT(TRACE, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
if (card->options.performance_stats) {
@@ -852,6 +849,22 @@
return;
}
+static int qeth_l2_ethtool_set_tso(struct net_device *dev, u32 data)
+{
+ struct qeth_card *card = netdev_priv(dev);
+
+ if (data) {
+ if (card->options.large_send == QETH_LARGE_SEND_NO) {
+ card->options.large_send = QETH_LARGE_SEND_EDDP;
+ dev->features |= NETIF_F_TSO;
+ }
+ } else {
+ dev->features &= ~NETIF_F_TSO;
+ card->options.large_send = QETH_LARGE_SEND_NO;
+ }
+ return 0;
+}
+
static struct ethtool_ops qeth_l2_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_tx_csum = ethtool_op_get_tx_csum,
@@ -859,11 +872,12 @@
.get_sg = ethtool_op_get_sg,
.set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso,
- .set_tso = ethtool_op_set_tso,
+ .set_tso = qeth_l2_ethtool_set_tso,
.get_strings = qeth_core_get_strings,
.get_ethtool_stats = qeth_core_get_ethtool_stats,
.get_stats_count = qeth_core_get_stats_count,
.get_drvinfo = qeth_core_get_drvinfo,
+ .get_settings = qeth_core_ethtool_get_settings,
};
static struct ethtool_ops qeth_l2_osn_ops = {
diff --git a/drivers/s390/net/qeth_l3.h b/drivers/s390/net/qeth_l3.h
index 1be3535..9f143c8 100644
--- a/drivers/s390/net/qeth_l3.h
+++ b/drivers/s390/net/qeth_l3.h
@@ -13,9 +13,6 @@
#include "qeth_core.h"
-#define QETH_DBF_TXT_BUF qeth_l3_dbf_txt_buf
-DECLARE_PER_CPU(char[256], qeth_l3_dbf_txt_buf);
-
struct qeth_ipaddr {
struct list_head entry;
enum qeth_ip_types type;
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index e1bfe56..94a8ead 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -28,8 +28,6 @@
#include "qeth_l3.h"
#include "qeth_core_offl.h"
-DEFINE_PER_CPU(char[256], qeth_l3_dbf_txt_buf);
-
static int qeth_l3_set_offline(struct ccwgroup_device *);
static int qeth_l3_recover(void *);
static int qeth_l3_stop(struct net_device *);
@@ -2093,6 +2091,11 @@
(card->state == CARD_STATE_UP)) {
if (recovery_mode)
qeth_l3_stop(card->dev);
+ else {
+ rtnl_lock();
+ dev_close(card->dev);
+ rtnl_unlock();
+ }
if (!card->use_hard_stop) {
rc = qeth_send_stoplan(card);
if (rc)
@@ -2559,8 +2562,6 @@
static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
struct sk_buff *skb, int ipv, int cast_type)
{
- QETH_DBF_TEXT(TRACE, 6, "fillhdr");
-
memset(hdr, 0, sizeof(struct qeth_hdr));
hdr->hdr.l3.id = QETH_HEADER_TYPE_LAYER3;
hdr->hdr.l3.ext_flags = 0;
@@ -2570,9 +2571,10 @@
* v6 uses passthrough, v4 sets the tag in the QDIO header.
*/
if (card->vlangrp && vlan_tx_tag_present(skb)) {
- hdr->hdr.l3.ext_flags = (ipv == 4) ?
- QETH_HDR_EXT_VLAN_FRAME :
- QETH_HDR_EXT_INCLUDE_VLAN_TAG;
+ if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD))
+ hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME;
+ else
+ hdr->hdr.l3.ext_flags = QETH_HDR_EXT_INCLUDE_VLAN_TAG;
hdr->hdr.l3.vlan_id = vlan_tx_tag_get(skb);
}
@@ -2638,8 +2640,6 @@
enum qeth_large_send_types large_send = QETH_LARGE_SEND_NO;
struct qeth_eddp_context *ctx = NULL;
- QETH_DBF_TEXT(TRACE, 6, "l3xmit");
-
if ((card->info.type == QETH_CARD_TYPE_IQD) &&
(skb->protocol != htons(ETH_P_IPV6)) &&
(skb->protocol != htons(ETH_P_IP)))
@@ -2890,6 +2890,7 @@
.get_ethtool_stats = qeth_core_get_ethtool_stats,
.get_stats_count = qeth_core_get_stats_count,
.get_drvinfo = qeth_core_get_drvinfo,
+ .get_settings = qeth_core_ethtool_get_settings,
};
/*
@@ -2982,7 +2983,6 @@
int index;
int i;
- QETH_DBF_TEXT(TRACE, 6, "qdinput");
card = (struct qeth_card *) card_ptr;
net_dev = card->dev;
if (card->options.performance_stats) {
@@ -3140,9 +3140,15 @@
netif_carrier_on(card->dev);
qeth_set_allowed_threads(card, 0xffffffff, 0);
- if ((recover_flag == CARD_STATE_RECOVER) && recovery_mode) {
+ if (recover_flag == CARD_STATE_RECOVER) {
+ if (recovery_mode)
qeth_l3_open(card->dev);
- qeth_l3_set_multicast_list(card->dev);
+ else {
+ rtnl_lock();
+ dev_open(card->dev);
+ rtnl_unlock();
+ }
+ qeth_l3_set_multicast_list(card->dev);
}
/* let user_space know that device is online */
kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);
diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c
index 37b85c6..c8bad67 100644
--- a/drivers/s390/scsi/zfcp_dbf.c
+++ b/drivers/s390/scsi/zfcp_dbf.c
@@ -1055,7 +1055,7 @@
rec->scsi_result = scsi_cmnd->result;
rec->scsi_cmnd = (unsigned long)scsi_cmnd;
rec->scsi_serial = scsi_cmnd->serial_number;
- memcpy(rec->scsi_opcode, &scsi_cmnd->cmnd,
+ memcpy(rec->scsi_opcode, scsi_cmnd->cmnd,
min((int)scsi_cmnd->cmd_len,
ZFCP_DBF_SCSI_OPCODE));
rec->scsi_retries = scsi_cmnd->retries;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 9af2330..b2ea4ea 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -4014,7 +4014,7 @@
ZFCP_LOG_TRACE("scpnt->result =0x%x, command was:\n",
scpnt->result);
ZFCP_HEX_DUMP(ZFCP_LOG_LEVEL_TRACE,
- (void *) &scpnt->cmnd, scpnt->cmd_len);
+ scpnt->cmnd, scpnt->cmd_len);
ZFCP_LOG_TRACE("%i bytes sense data provided by FCP\n",
fcp_rsp_iu->fcp_sns_len);
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index a4e7581..2357034 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -637,7 +637,7 @@
break;
default:
printk("%s: %s: invalid watchdog id: %i\n",
- WD_OBPNAME, __FUNCTION__, whichdog);
+ WD_OBPNAME, __func__, whichdog);
return(1);
}
if(0 != misc_register(whichmisc))
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 44d2ef9..383f32c 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -393,13 +393,13 @@
err = request_irq(driver->irq, uctrl_interrupt, 0, "uctrl", driver);
if (err) {
printk("%s: unable to register irq %d\n",
- __FUNCTION__, driver->irq);
+ __func__, driver->irq);
return err;
}
if (misc_register(&uctrl_dev)) {
printk("%s: unable to get misc minor %d\n",
- __FUNCTION__, uctrl_dev.minor);
+ __func__, uctrl_dev.minor);
free_irq(driver->irq, driver);
return -ENODEV;
}
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index f4c4fe9..f5a9add 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -599,7 +599,7 @@
(struct NCR_700_command_slot *)SCp->host_scribble;
dma_unmap_single(hostdata->dev, slot->pCmd,
- sizeof(SCp->cmnd), DMA_TO_DEVICE);
+ MAX_COMMAND_SIZE, DMA_TO_DEVICE);
if (slot->flags == NCR_700_FLAG_AUTOSENSE) {
char *cmnd = NCR_700_get_sense_cmnd(SCp->device);
#ifdef NCR_700_DEBUG
@@ -1004,7 +1004,7 @@
* here */
NCR_700_unmap(hostdata, SCp, slot);
dma_unmap_single(hostdata->dev, slot->pCmd,
- sizeof(SCp->cmnd),
+ MAX_COMMAND_SIZE,
DMA_TO_DEVICE);
cmnd[0] = REQUEST_SENSE;
@@ -1901,7 +1901,7 @@
}
slot->resume_offset = 0;
slot->pCmd = dma_map_single(hostdata->dev, SCp->cmnd,
- sizeof(SCp->cmnd), DMA_TO_DEVICE);
+ MAX_COMMAND_SIZE, DMA_TO_DEVICE);
NCR_700_start_command(SCp);
return 0;
}
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 99c57b0..46d7e40 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -504,10 +504,9 @@
source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
source "drivers/scsi/aic94xx/Kconfig"
-# All the I2O code and drivers do not seem to be 64bit safe.
config SCSI_DPT_I2O
tristate "Adaptec I2O RAID support "
- depends on !64BIT && SCSI && PCI && VIRT_TO_BUS
+ depends on SCSI && PCI && VIRT_TO_BUS
help
This driver supports all of Adaptec's I2O based RAID controllers as
well as the DPT SmartRaid V cards. This is an Adaptec maintained
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index 792b2e8..ced3eeb 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -895,7 +895,7 @@
} else {
scb->tag_msg = 0; /* No tag support */
}
- memcpy(&scb->cdb[0], &cmd->cmnd, scb->cdb_len);
+ memcpy(scb->cdb, cmd->cmnd, scb->cdb_len);
}
/**
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 460d402..aa4e77c 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -498,6 +498,11 @@
(le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
(le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
fsa_dev_ptr->valid = 1;
+ /* sense_key holds the current state of the spin-up */
+ if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY))
+ fsa_dev_ptr->sense_data.sense_key = NOT_READY;
+ else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY)
+ fsa_dev_ptr->sense_data.sense_key = NO_SENSE;
fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol);
fsa_dev_ptr->size
= ((u64)le32_to_cpu(dresp->mnt[0].capacity)) +
@@ -1509,20 +1514,35 @@
scsi_dma_unmap(scsicmd);
readreply = (struct aac_read_reply *)fib_data(fibptr);
- if (le32_to_cpu(readreply->status) == ST_OK)
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
- else {
+ switch (le32_to_cpu(readreply->status)) {
+ case ST_OK:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
+ dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE;
+ break;
+ case ST_NOT_READY:
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY,
+ SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0);
+ memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+ min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
+ SCSI_SENSE_BUFFERSIZE));
+ break;
+ default:
#ifdef AAC_DETAILED_STATUS_INFO
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;
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
set_sense(&dev->fsa_dev[cid].sense_data,
HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE,
ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0);
memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data),
SCSI_SENSE_BUFFERSIZE));
+ break;
}
aac_fib_complete(fibptr);
aac_fib_free(fibptr);
@@ -1863,6 +1883,84 @@
return SCSI_MLQUEUE_HOST_BUSY;
}
+static void aac_start_stop_callback(void *context, struct fib *fibptr)
+{
+ struct scsi_cmnd *scsicmd = context;
+
+ if (!aac_valid_context(scsicmd, fibptr))
+ return;
+
+ BUG_ON(fibptr == NULL);
+
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+ aac_fib_complete(fibptr);
+ aac_fib_free(fibptr);
+ scsicmd->scsi_done(scsicmd);
+}
+
+static int aac_start_stop(struct scsi_cmnd *scsicmd)
+{
+ int status;
+ struct fib *cmd_fibcontext;
+ struct aac_power_management *pmcmd;
+ struct scsi_device *sdev = scsicmd->device;
+ struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+
+ if (!(aac->supplement_adapter_info.SupportedOptions2 &
+ AAC_OPTION_POWER_MANAGEMENT)) {
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+ }
+
+ if (aac->in_reset)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ /*
+ * Allocate and initialize a Fib
+ */
+ cmd_fibcontext = aac_fib_alloc(aac);
+ if (!cmd_fibcontext)
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ aac_fib_init(cmd_fibcontext);
+
+ pmcmd = fib_data(cmd_fibcontext);
+ pmcmd->command = cpu_to_le32(VM_ContainerConfig);
+ pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT);
+ /* Eject bit ignored, not relevant */
+ pmcmd->sub = (scsicmd->cmnd[4] & 1) ?
+ cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT);
+ pmcmd->cid = cpu_to_le32(sdev_id(sdev));
+ pmcmd->parm = (scsicmd->cmnd[1] & 1) ?
+ cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0;
+
+ /*
+ * Now send the Fib to the adapter
+ */
+ status = aac_fib_send(ContainerCommand,
+ cmd_fibcontext,
+ sizeof(struct aac_power_management),
+ FsaNormal,
+ 0, 1,
+ (fib_callback)aac_start_stop_callback,
+ (void *)scsicmd);
+
+ /*
+ * Check that the command queued to the controller
+ */
+ if (status == -EINPROGRESS) {
+ scsicmd->SCp.phase = AAC_OWNER_FIRMWARE;
+ return 0;
+ }
+
+ aac_fib_complete(cmd_fibcontext);
+ aac_fib_free(cmd_fibcontext);
+ return SCSI_MLQUEUE_HOST_BUSY;
+}
+
/**
* aac_scsi_cmd() - Process SCSI command
* @scsicmd: SCSI command block
@@ -1899,7 +1997,9 @@
* If the target container doesn't exist, it may have
* been newly created
*/
- if ((fsa_dev_ptr[cid].valid & 1) == 0) {
+ if (((fsa_dev_ptr[cid].valid & 1) == 0) ||
+ (fsa_dev_ptr[cid].sense_data.sense_key ==
+ NOT_READY)) {
switch (scsicmd->cmnd[0]) {
case SERVICE_ACTION_IN:
if (!(dev->raw_io_interface) ||
@@ -2091,8 +2191,8 @@
scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp));
/* Do not cache partition table for arrays */
scsicmd->device->removable = 1;
-
- scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
return 0;
@@ -2187,15 +2287,32 @@
* These commands are all No-Ops
*/
case TEST_UNIT_READY:
+ if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) {
+ scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 |
+ SAM_STAT_CHECK_CONDITION;
+ set_sense(&dev->fsa_dev[cid].sense_data,
+ NOT_READY, SENCODE_BECOMING_READY,
+ ASENCODE_BECOMING_READY, 0, 0);
+ memcpy(scsicmd->sense_buffer,
+ &dev->fsa_dev[cid].sense_data,
+ min_t(size_t,
+ sizeof(dev->fsa_dev[cid].sense_data),
+ SCSI_SENSE_BUFFERSIZE));
+ scsicmd->scsi_done(scsicmd);
+ return 0;
+ }
+ /* FALLTHRU */
case RESERVE:
case RELEASE:
case REZERO_UNIT:
case REASSIGN_BLOCKS:
case SEEK_10:
- case START_STOP:
scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
scsicmd->scsi_done(scsicmd);
return 0;
+
+ case START_STOP:
+ return aac_start_stop(scsicmd);
}
switch (scsicmd->cmnd[0])
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
index 113ca9c..73916ad 100644
--- a/drivers/scsi/aacraid/aacraid.h
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -12,7 +12,7 @@
*----------------------------------------------------------------------------*/
#ifndef AAC_DRIVER_BUILD
-# define AAC_DRIVER_BUILD 2455
+# define AAC_DRIVER_BUILD 2456
# define AAC_DRIVER_BRANCH "-ms"
#endif
#define MAXIMUM_NUM_CONTAINERS 32
@@ -34,8 +34,8 @@
#define CONTAINER_TO_ID(cont) (cont)
#define CONTAINER_TO_LUN(cont) (0)
-#define aac_phys_to_logical(x) (x+1)
-#define aac_logical_to_phys(x) (x?x-1:0)
+#define aac_phys_to_logical(x) ((x)+1)
+#define aac_logical_to_phys(x) ((x)?(x)-1:0)
/* #define AAC_DETAILED_STATUS_INFO */
@@ -424,6 +424,8 @@
*/
__le32 InitFlags; /* flags for supported features */
#define INITFLAGS_NEW_COMM_SUPPORTED 0x00000001
+#define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010
+#define INITFLAGS_DRIVER_SUPPORTS_PM 0x00000020
__le32 MaxIoCommands; /* max outstanding commands */
__le32 MaxIoSize; /* largest I/O command */
__le32 MaxFibSize; /* largest FIB to adapter */
@@ -867,8 +869,10 @@
};
#define AAC_FEATURE_FALCON cpu_to_le32(0x00000010)
#define AAC_FEATURE_JBOD cpu_to_le32(0x08000000)
-#define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001)
-#define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002)
+/* SupportedOptions2 */
+#define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001)
+#define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002)
+#define AAC_OPTION_POWER_MANAGEMENT cpu_to_le32(0x00000004)
#define AAC_SIS_VERSION_V3 3
#define AAC_SIS_SLOT_UNKNOWN 0xFF
@@ -1148,6 +1152,7 @@
#define ST_DQUOT 69
#define ST_STALE 70
#define ST_REMOTE 71
+#define ST_NOT_READY 72
#define ST_BADHANDLE 10001
#define ST_NOT_SYNC 10002
#define ST_BAD_COOKIE 10003
@@ -1269,6 +1274,18 @@
u8 data[16];
};
+#define CT_POWER_MANAGEMENT 245
+#define CT_PM_START_UNIT 2
+#define CT_PM_STOP_UNIT 3
+#define CT_PM_UNIT_IMMEDIATE 1
+struct aac_power_management {
+ __le32 command; /* VM_ContainerConfig */
+ __le32 type; /* CT_POWER_MANAGEMENT */
+ __le32 sub; /* CT_PM_* */
+ __le32 cid;
+ __le32 parm; /* CT_PM_sub_* */
+};
+
#define CT_PAUSE_IO 65
#define CT_RELEASE_IO 66
struct aac_pause {
@@ -1536,6 +1553,7 @@
#define FSCS_NOTCLEAN 0x0001 /* fsck is necessary before mounting */
#define FSCS_READONLY 0x0002 /* possible result of broken mirror */
#define FSCS_HIDDEN 0x0004 /* should be ignored - set during a clear */
+#define FSCS_NOT_READY 0x0008 /* Array spinning up to fulfil request */
struct aac_query_mount {
__le32 command;
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
index 294a802..cbac063 100644
--- a/drivers/scsi/aacraid/comminit.c
+++ b/drivers/scsi/aacraid/comminit.c
@@ -97,6 +97,8 @@
init->InitFlags = cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED);
dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n"));
}
+ init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME |
+ INITFLAGS_DRIVER_SUPPORTS_PM);
init->MaxIoCommands = cpu_to_le32(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB);
init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9);
init->MaxFibSize = cpu_to_le32(dev->max_fib_size);
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
index ef67816..289304a 100644
--- a/drivers/scsi/aacraid/commsup.c
+++ b/drivers/scsi/aacraid/commsup.c
@@ -515,7 +515,7 @@
}
udelay(5);
}
- } else if (down_interruptible(&fibptr->event_wait) == 0) {
+ } else if (down_interruptible(&fibptr->event_wait)) {
fibptr->done = 2;
up(&fibptr->event_wait);
}
@@ -906,15 +906,22 @@
case AifEnAddJBOD:
case AifEnDeleteJBOD:
container = le32_to_cpu(((__le32 *)aifcmd->data)[1]);
- if ((container >> 28))
+ if ((container >> 28)) {
+ container = (u32)-1;
break;
+ }
channel = (container >> 24) & 0xF;
- if (channel >= dev->maximum_num_channels)
+ if (channel >= dev->maximum_num_channels) {
+ container = (u32)-1;
break;
+ }
id = container & 0xFFFF;
- if (id >= dev->maximum_num_physicals)
+ if (id >= dev->maximum_num_physicals) {
+ container = (u32)-1;
break;
+ }
lun = (container >> 16) & 0xFF;
+ container = (u32)-1;
channel = aac_phys_to_logical(channel);
device_config_needed =
(((__le32 *)aifcmd->data)[0] ==
@@ -933,13 +940,18 @@
case EM_DRIVE_REMOVAL:
container = le32_to_cpu(
((__le32 *)aifcmd->data)[2]);
- if ((container >> 28))
+ if ((container >> 28)) {
+ container = (u32)-1;
break;
+ }
channel = (container >> 24) & 0xF;
- if (channel >= dev->maximum_num_channels)
+ if (channel >= dev->maximum_num_channels) {
+ container = (u32)-1;
break;
+ }
id = container & 0xFFFF;
lun = (container >> 16) & 0xFF;
+ container = (u32)-1;
if (id >= dev->maximum_num_physicals) {
/* legacy dev_t ? */
if ((0x2000 <= id) || lun || channel ||
@@ -1025,9 +1037,10 @@
break;
}
+ container = 0;
+retry_next:
if (device_config_needed == NOTHING)
- for (container = 0; container < dev->maximum_num_containers;
- ++container) {
+ for (; container < dev->maximum_num_containers; ++container) {
if ((dev->fsa_dev[container].config_waiting_on == 0) &&
(dev->fsa_dev[container].config_needed != NOTHING) &&
time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) {
@@ -1110,6 +1123,11 @@
}
if (device_config_needed == ADD)
scsi_add_device(dev->scsi_host_ptr, channel, id, lun);
+ if (channel == CONTAINER_CHANNEL) {
+ container++;
+ device_config_needed = NOTHING;
+ goto retry_next;
+ }
}
static int _aac_reset_adapter(struct aac_dev *aac, int forced)
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index c109f63..1f7c836 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -401,6 +401,8 @@
static int aac_slave_configure(struct scsi_device *sdev)
{
struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata;
+ if (aac->jbod && (sdev->type == TYPE_DISK))
+ sdev->removable = 1;
if ((sdev->type == TYPE_DISK) &&
(sdev_channel(sdev) != CONTAINER_CHANNEL) &&
(!aac->jbod || sdev->inq_periph_qual) &&
@@ -809,6 +811,12 @@
"SAI_READ_CAPACITY_16\n");
if (dev->jbod)
len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n");
+ if (dev->supplement_adapter_info.SupportedOptions2 &
+ AAC_OPTION_POWER_MANAGEMENT)
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "SUPPORTED_POWER_MANAGEMENT\n");
+ if (dev->msi)
+ len += snprintf(buf + len, PAGE_SIZE - len, "PCI_HAS_MSI\n");
return len;
}
@@ -1106,7 +1114,7 @@
aac->pdev = pdev;
aac->name = aac_driver_template.name;
aac->id = shost->unique_id;
- aac->cardtype = index;
+ aac->cardtype = index;
INIT_LIST_HEAD(&aac->entry);
aac->fibs = kmalloc(sizeof(struct fib) * (shost->can_queue + AAC_NUM_MGT_FIB), GFP_KERNEL);
@@ -1146,19 +1154,19 @@
goto out_deinit;
/*
- * Lets override negotiations and drop the maximum SG limit to 34
- */
+ * Lets override negotiations and drop the maximum SG limit to 34
+ */
if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) &&
(shost->sg_tablesize > 34)) {
shost->sg_tablesize = 34;
shost->max_sectors = (shost->sg_tablesize * 8) + 112;
- }
+ }
- if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
+ if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) &&
(shost->sg_tablesize > 17)) {
shost->sg_tablesize = 17;
shost->max_sectors = (shost->sg_tablesize * 8) + 112;
- }
+ }
error = pci_set_dma_max_seg_size(pdev,
(aac->adapter_info.options & AAC_OPT_NEW_COMM) ?
@@ -1174,7 +1182,7 @@
else
aac->printf_enabled = 0;
- /*
+ /*
* max channel will be the physical channels plus 1 virtual channel
* all containers are on the virtual channel 0 (CONTAINER_CHANNEL)
* physical channels are address by their actual physical number+1
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index 90f5e0a..2a730c4 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -529,10 +529,10 @@
/* The first entry, 0, is used for dynamic ids, the rest for devices
* we know about.
*/
-static struct asd_pcidev_struct {
+static const struct asd_pcidev_struct {
const char * name;
int (*setup)(struct asd_ha_struct *asd_ha);
-} asd_pcidev_data[] = {
+} asd_pcidev_data[] __devinitconst = {
/* Id 0 is used for dynamic ids. */
{ .name = "Adaptec AIC-94xx SAS/SATA Host Adapter",
.setup = asd_aic9410_setup
@@ -735,7 +735,7 @@
static int __devinit asd_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id)
{
- struct asd_pcidev_struct *asd_dev;
+ const struct asd_pcidev_struct *asd_dev;
unsigned asd_id = (unsigned) id->driver_data;
struct asd_ha_struct *asd_ha;
struct Scsi_Host *shost;
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 403a7f2..9785d73 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -28,7 +28,6 @@
#define SERVICE_ACTION_OUT_12 0xa9
#define SERVICE_ACTION_IN_16 0x9e
#define SERVICE_ACTION_OUT_16 0x9f
-#define VARIABLE_LENGTH_CMD 0x7f
@@ -210,7 +209,7 @@
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
- len = cdbp[7] + 8;
+ len = scsi_varlen_cdb_length(cdbp);
if (len < 10) {
printk("short variable length command, "
"len=%d ext_len=%d", len, cdb_len);
@@ -300,7 +299,7 @@
cdb0 = cdbp[0];
switch(cdb0) {
case VARIABLE_LENGTH_CMD:
- len = cdbp[7] + 8;
+ len = scsi_varlen_cdb_length(cdbp);
if (len < 10) {
printk("short opcode=0x%x command, len=%d "
"ext_len=%d", cdb0, len, cdb_len);
@@ -335,10 +334,7 @@
int k, len;
print_opcode_name(cdb, 0);
- if (VARIABLE_LENGTH_CMD == cdb[0])
- len = cdb[7] + 8;
- else
- len = COMMAND_SIZE(cdb[0]);
+ len = scsi_command_size(cdb);
/* print out all bytes in cdb */
for (k = 0; k < len; ++k)
printk(" %02x", cdb[k]);
diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h
index cc784e8..f602367 100644
--- a/drivers/scsi/dpt/dpti_ioctl.h
+++ b/drivers/scsi/dpt/dpti_ioctl.h
@@ -89,7 +89,7 @@
int njobs; /* # of jobs sent to HA */
int qdepth; /* Controller queue depth. */
int wakebase; /* mpx wakeup base index. */
- uLONG SGsize; /* Scatter/Gather list size. */
+ uINT SGsize; /* Scatter/Gather list size. */
unsigned heads; /* heads for drives on cntlr. */
unsigned sectors; /* sectors for drives on cntlr. */
uCHAR do_drive32; /* Flag for Above 16 MB Ability */
@@ -97,8 +97,8 @@
char idPAL[4]; /* 4 Bytes Of The ID Pal */
uCHAR primary; /* 1 For Primary, 0 For Secondary */
uCHAR eataVersion; /* EATA Version */
- uLONG cpLength; /* EATA Command Packet Length */
- uLONG spLength; /* EATA Status Packet Length */
+ uINT cpLength; /* EATA Command Packet Length */
+ uINT spLength; /* EATA Status Packet Length */
uCHAR drqNum; /* DRQ Index (0,5,6,7) */
uCHAR flag1; /* EATA Flags 1 (Byte 9) */
uCHAR flag2; /* EATA Flags 2 (Byte 30) */
@@ -107,23 +107,23 @@
typedef struct {
uSHORT length; // Remaining length of this
uSHORT drvrHBAnum; // Relative HBA # used by the driver
- uLONG baseAddr; // Base I/O address
+ uINT baseAddr; // Base I/O address
uSHORT blinkState; // Blink LED state (0=Not in blink LED)
uCHAR pciBusNum; // PCI Bus # (Optional)
uCHAR pciDeviceNum; // PCI Device # (Optional)
uSHORT hbaFlags; // Miscellaneous HBA flags
uSHORT Interrupt; // Interrupt set for this device.
# if (defined(_DPT_ARC))
- uLONG baseLength;
+ uINT baseLength;
ADAPTER_OBJECT *AdapterObject;
LARGE_INTEGER DmaLogicalAddress;
PVOID DmaVirtualAddress;
LARGE_INTEGER ReplyLogicalAddress;
PVOID ReplyVirtualAddress;
# else
- uLONG reserved1; // Reserved for future expansion
- uLONG reserved2; // Reserved for future expansion
- uLONG reserved3; // Reserved for future expansion
+ uINT reserved1; // Reserved for future expansion
+ uINT reserved2; // Reserved for future expansion
+ uINT reserved3; // Reserved for future expansion
# endif
} drvrHBAinfo_S;
diff --git a/drivers/scsi/dpt/dptsig.h b/drivers/scsi/dpt/dptsig.h
index 94bc894..72c8992 100644
--- a/drivers/scsi/dpt/dptsig.h
+++ b/drivers/scsi/dpt/dptsig.h
@@ -33,11 +33,7 @@
/* to make sure we are talking the same size under all OS's */
typedef unsigned char sigBYTE;
typedef unsigned short sigWORD;
-#if (defined(_MULTI_DATAMODEL) && defined(sun) && !defined(_ILP32))
-typedef uint32_t sigLONG;
-#else
-typedef unsigned long sigLONG;
-#endif
+typedef unsigned int sigINT;
/*
* use sigWORDLittleEndian for:
@@ -300,7 +296,7 @@
sigBYTE dsFiletype; /* type of file */
sigBYTE dsFiletypeFlags; /* flags to specify load type, etc. */
sigBYTE dsOEM; /* OEM file was created for */
- sigLONG dsOS; /* which Operating systems */
+ sigINT dsOS; /* which Operating systems */
sigWORD dsCapabilities; /* RAID levels, etc. */
sigWORD dsDeviceSupp; /* Types of SCSI devices supported */
sigWORD dsAdapterSupp; /* DPT adapter families supported */
diff --git a/drivers/scsi/dpt/sys_info.h b/drivers/scsi/dpt/sys_info.h
index d23b70c..a90c4cb 100644
--- a/drivers/scsi/dpt/sys_info.h
+++ b/drivers/scsi/dpt/sys_info.h
@@ -145,8 +145,8 @@
uCHAR smartROMRevision;
uSHORT flags; /* See bit definitions above */
uSHORT conventionalMemSize; /* in KB */
- uLONG extendedMemSize; /* in KB */
- uLONG osType; /* Same as DPTSIG's definition */
+ uINT extendedMemSize; /* in KB */
+ uINT osType; /* Same as DPTSIG's definition */
uCHAR osMajorVersion;
uCHAR osMinorVersion; /* The OS version */
uCHAR osRevision;
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index ac92ac1..0fb5bf4 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -29,11 +29,6 @@
/*#define DEBUG 1 */
/*#define UARTDELAY 1 */
-/* On the real kernel ADDR32 should always be zero for 2.4. GFP_HIGH allocates
- high pages. Keep the macro around because of the broken unmerged ia64 tree */
-
-#define ADDR32 (0)
-
#include <linux/module.h>
MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn");
@@ -108,27 +103,28 @@
static DEFINE_MUTEX(adpt_configuration_lock);
-static struct i2o_sys_tbl *sys_tbl = NULL;
-static int sys_tbl_ind = 0;
-static int sys_tbl_len = 0;
+static struct i2o_sys_tbl *sys_tbl;
+static dma_addr_t sys_tbl_pa;
+static int sys_tbl_ind;
+static int sys_tbl_len;
static adpt_hba* hba_chain = NULL;
static int hba_count = 0;
+static struct class *adpt_sysfs_class;
+
+#ifdef CONFIG_COMPAT
+static long compat_adpt_ioctl(struct file *, unsigned int, unsigned long);
+#endif
+
static const struct file_operations adpt_fops = {
.ioctl = adpt_ioctl,
.open = adpt_open,
- .release = adpt_close
-};
-
-#ifdef REBOOT_NOTIFIER
-static struct notifier_block adpt_reboot_notifier =
-{
- adpt_reboot_event,
- NULL,
- 0
-};
+ .release = adpt_close,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_adpt_ioctl,
#endif
+};
/* Structures and definitions for synchronous message posting.
* See adpt_i2o_post_wait() for description
@@ -151,6 +147,21 @@
*============================================================================
*/
+static inline int dpt_dma64(adpt_hba *pHba)
+{
+ return (sizeof(dma_addr_t) > 4 && (pHba)->dma64);
+}
+
+static inline u32 dma_high(dma_addr_t addr)
+{
+ return upper_32_bits(addr);
+}
+
+static inline u32 dma_low(dma_addr_t addr)
+{
+ return (u32)addr;
+}
+
static u8 adpt_read_blink_led(adpt_hba* host)
{
if (host->FwDebugBLEDflag_P) {
@@ -178,8 +189,6 @@
struct pci_dev *pDev = NULL;
adpt_hba* pHba;
- adpt_init();
-
PINFO("Detecting Adaptec I2O RAID controllers...\n");
/* search for all Adatpec I2O RAID cards */
@@ -247,13 +256,29 @@
adpt_inquiry(pHba);
}
+ adpt_sysfs_class = class_create(THIS_MODULE, "dpt_i2o");
+ if (IS_ERR(adpt_sysfs_class)) {
+ printk(KERN_WARNING"dpti: unable to create dpt_i2o class\n");
+ adpt_sysfs_class = NULL;
+ }
+
for (pHba = hba_chain; pHba; pHba = pHba->next) {
- if( adpt_scsi_register(pHba,sht) < 0){
+ if (adpt_scsi_host_alloc(pHba, sht) < 0){
adpt_i2o_delete_hba(pHba);
continue;
}
pHba->initialized = TRUE;
pHba->state &= ~DPTI_STATE_RESET;
+ if (adpt_sysfs_class) {
+ struct device *dev = device_create(adpt_sysfs_class,
+ NULL, MKDEV(DPTI_I2O_MAJOR, pHba->unit),
+ "dpti%d", pHba->unit);
+ if (IS_ERR(dev)) {
+ printk(KERN_WARNING"dpti%d: unable to "
+ "create device in dpt_i2o class\n",
+ pHba->unit);
+ }
+ }
}
// Register our control device node
@@ -282,7 +307,7 @@
static void adpt_inquiry(adpt_hba* pHba)
{
- u32 msg[14];
+ u32 msg[17];
u32 *mptr;
u32 *lenptr;
int direction;
@@ -290,11 +315,12 @@
u32 len;
u32 reqlen;
u8* buf;
+ dma_addr_t addr;
u8 scb[16];
s32 rcode;
memset(msg, 0, sizeof(msg));
- buf = kmalloc(80,GFP_KERNEL|ADDR32);
+ buf = dma_alloc_coherent(&pHba->pDev->dev, 80, &addr, GFP_KERNEL);
if(!buf){
printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name);
return;
@@ -305,7 +331,10 @@
direction = 0x00000000;
scsidir =0x40000000; // DATA IN (iop<--dev)
- reqlen = 14; // SINGLE SGE
+ if (dpt_dma64(pHba))
+ reqlen = 17; // SINGLE SGE, 64 bit
+ else
+ reqlen = 14; // SINGLE SGE, 32 bit
/* Stick the headers on */
msg[0] = reqlen<<16 | SGL_OFFSET_12;
msg[1] = (0xff<<24|HOST_TID<<12|ADAPTER_TID);
@@ -338,8 +367,16 @@
/* Now fill in the SGList and command */
*lenptr = len;
- *mptr++ = 0xD0000000|direction|len;
- *mptr++ = virt_to_bus(buf);
+ if (dpt_dma64(pHba)) {
+ *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
+ *mptr++ = 1 << PAGE_SHIFT;
+ *mptr++ = 0xD0000000|direction|len;
+ *mptr++ = dma_low(addr);
+ *mptr++ = dma_high(addr);
+ } else {
+ *mptr++ = 0xD0000000|direction|len;
+ *mptr++ = addr;
+ }
// Send it on it's way
rcode = adpt_i2o_post_wait(pHba, msg, reqlen<<2, 120);
@@ -347,7 +384,7 @@
sprintf(pHba->detail, "Adaptec I2O RAID");
printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode);
if (rcode != -ETIME && rcode != -EINTR)
- kfree(buf);
+ dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
} else {
memset(pHba->detail, 0, sizeof(pHba->detail));
memcpy(&(pHba->detail), "Vendor: Adaptec ", 16);
@@ -356,7 +393,7 @@
memcpy(&(pHba->detail[40]), " FW: ", 4);
memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4);
pHba->detail[48] = '\0'; /* precautionary */
- kfree(buf);
+ dma_free_coherent(&pHba->pDev->dev, 80, buf, addr);
}
adpt_i2o_status_get(pHba);
return ;
@@ -632,6 +669,91 @@
return len;
}
+/*
+ * Turn a struct scsi_cmnd * into a unique 32 bit 'context'.
+ */
+static u32 adpt_cmd_to_context(struct scsi_cmnd *cmd)
+{
+ return (u32)cmd->serial_number;
+}
+
+/*
+ * Go from a u32 'context' to a struct scsi_cmnd * .
+ * This could probably be made more efficient.
+ */
+static struct scsi_cmnd *
+ adpt_cmd_from_context(adpt_hba * pHba, u32 context)
+{
+ struct scsi_cmnd * cmd;
+ struct scsi_device * d;
+
+ if (context == 0)
+ return NULL;
+
+ spin_unlock(pHba->host->host_lock);
+ shost_for_each_device(d, pHba->host) {
+ unsigned long flags;
+ spin_lock_irqsave(&d->list_lock, flags);
+ list_for_each_entry(cmd, &d->cmd_list, list) {
+ if (((u32)cmd->serial_number == context)) {
+ spin_unlock_irqrestore(&d->list_lock, flags);
+ scsi_device_put(d);
+ spin_lock(pHba->host->host_lock);
+ return cmd;
+ }
+ }
+ spin_unlock_irqrestore(&d->list_lock, flags);
+ }
+ spin_lock(pHba->host->host_lock);
+
+ return NULL;
+}
+
+/*
+ * Turn a pointer to ioctl reply data into an u32 'context'
+ */
+static u32 adpt_ioctl_to_context(adpt_hba * pHba, void *reply)
+{
+#if BITS_PER_LONG == 32
+ return (u32)(unsigned long)reply;
+#else
+ ulong flags = 0;
+ u32 nr, i;
+
+ spin_lock_irqsave(pHba->host->host_lock, flags);
+ nr = ARRAY_SIZE(pHba->ioctl_reply_context);
+ for (i = 0; i < nr; i++) {
+ if (pHba->ioctl_reply_context[i] == NULL) {
+ pHba->ioctl_reply_context[i] = reply;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(pHba->host->host_lock, flags);
+ if (i >= nr) {
+ kfree (reply);
+ printk(KERN_WARNING"%s: Too many outstanding "
+ "ioctl commands\n", pHba->name);
+ return (u32)-1;
+ }
+
+ return i;
+#endif
+}
+
+/*
+ * Go from an u32 'context' to a pointer to ioctl reply data.
+ */
+static void *adpt_ioctl_from_context(adpt_hba *pHba, u32 context)
+{
+#if BITS_PER_LONG == 32
+ return (void *)(unsigned long)context;
+#else
+ void *p = pHba->ioctl_reply_context[context];
+ pHba->ioctl_reply_context[context] = NULL;
+
+ return p;
+#endif
+}
/*===========================================================================
* Error Handling routines
@@ -660,7 +782,7 @@
msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|dptdevice->tid;
msg[2] = 0;
msg[3]= 0;
- msg[4] = (u32)cmd;
+ msg[4] = adpt_cmd_to_context(cmd);
if (pHba->host)
spin_lock_irq(pHba->host->host_lock);
rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER);
@@ -861,27 +983,6 @@
printk(KERN_INFO "Adaptec I2O controllers down.\n");
}
-/*
- * reboot/shutdown notification.
- *
- * - Quiesce each IOP in the system
- *
- */
-
-#ifdef REBOOT_NOTIFIER
-static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p)
-{
-
- if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
- return NOTIFY_DONE;
-
- adpt_i2o_sys_shutdown();
-
- return NOTIFY_DONE;
-}
-#endif
-
-
static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev)
{
@@ -893,6 +994,7 @@
u32 hba_map1_area_size = 0;
void __iomem *base_addr_virt = NULL;
void __iomem *msg_addr_virt = NULL;
+ int dma64 = 0;
int raptorFlag = FALSE;
@@ -906,9 +1008,21 @@
}
pci_set_master(pDev);
- if (pci_set_dma_mask(pDev, DMA_32BIT_MASK))
+
+ /*
+ * See if we should enable dma64 mode.
+ */
+ if (sizeof(dma_addr_t) > 4 &&
+ pci_set_dma_mask(pDev, DMA_64BIT_MASK) == 0) {
+ if (dma_get_required_mask(&pDev->dev) > DMA_32BIT_MASK)
+ dma64 = 1;
+ }
+ if (!dma64 && pci_set_dma_mask(pDev, DMA_32BIT_MASK) != 0)
return -EINVAL;
+ /* adapter only supports message blocks below 4GB */
+ pci_set_consistent_dma_mask(pDev, DMA_32BIT_MASK);
+
base_addr0_phys = pci_resource_start(pDev,0);
hba_map0_area_size = pci_resource_len(pDev,0);
@@ -929,6 +1043,25 @@
raptorFlag = TRUE;
}
+#if BITS_PER_LONG == 64
+ /*
+ * The original Adaptec 64 bit driver has this comment here:
+ * "x86_64 machines need more optimal mappings"
+ *
+ * I assume some HBAs report ridiculously large mappings
+ * and we need to limit them on platforms with IOMMUs.
+ */
+ if (raptorFlag == TRUE) {
+ if (hba_map0_area_size > 128)
+ hba_map0_area_size = 128;
+ if (hba_map1_area_size > 524288)
+ hba_map1_area_size = 524288;
+ } else {
+ if (hba_map0_area_size > 524288)
+ hba_map0_area_size = 524288;
+ }
+#endif
+
base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size);
if (!base_addr_virt) {
pci_release_regions(pDev);
@@ -991,16 +1124,22 @@
pHba->state = DPTI_STATE_RESET;
pHba->pDev = pDev;
pHba->devices = NULL;
+ pHba->dma64 = dma64;
// Initializing the spinlocks
spin_lock_init(&pHba->state_lock);
spin_lock_init(&adpt_post_wait_lock);
if(raptorFlag == 0){
- printk(KERN_INFO"Adaptec I2O RAID controller %d at %p size=%x irq=%d\n",
- hba_count-1, base_addr_virt, hba_map0_area_size, pDev->irq);
+ printk(KERN_INFO "Adaptec I2O RAID controller"
+ " %d at %p size=%x irq=%d%s\n",
+ hba_count-1, base_addr_virt,
+ hba_map0_area_size, pDev->irq,
+ dma64 ? " (64-bit DMA)" : "");
} else {
- printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d\n",hba_count-1, pDev->irq);
+ printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d%s\n",
+ hba_count-1, pDev->irq,
+ dma64 ? " (64-bit DMA)" : "");
printk(KERN_INFO" BAR0 %p - size= %x\n",base_addr_virt,hba_map0_area_size);
printk(KERN_INFO" BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size);
}
@@ -1053,10 +1192,26 @@
if(pHba->msg_addr_virt != pHba->base_addr_virt){
iounmap(pHba->msg_addr_virt);
}
- kfree(pHba->hrt);
- kfree(pHba->lct);
- kfree(pHba->status_block);
- kfree(pHba->reply_pool);
+ if(pHba->FwDebugBuffer_P)
+ iounmap(pHba->FwDebugBuffer_P);
+ if(pHba->hrt) {
+ dma_free_coherent(&pHba->pDev->dev,
+ pHba->hrt->num_entries * pHba->hrt->entry_len << 2,
+ pHba->hrt, pHba->hrt_pa);
+ }
+ if(pHba->lct) {
+ dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
+ pHba->lct, pHba->lct_pa);
+ }
+ if(pHba->status_block) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(i2o_status_block),
+ pHba->status_block, pHba->status_block_pa);
+ }
+ if(pHba->reply_pool) {
+ dma_free_coherent(&pHba->pDev->dev,
+ pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+ pHba->reply_pool, pHba->reply_pool_pa);
+ }
for(d = pHba->devices; d ; d = next){
next = d->next;
@@ -1075,23 +1230,19 @@
pci_dev_put(pHba->pDev);
kfree(pHba);
+ if (adpt_sysfs_class)
+ device_destroy(adpt_sysfs_class,
+ MKDEV(DPTI_I2O_MAJOR, pHba->unit));
+
if(hba_count <= 0){
unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER);
+ if (adpt_sysfs_class) {
+ class_destroy(adpt_sysfs_class);
+ adpt_sysfs_class = NULL;
+ }
}
}
-
-static int adpt_init(void)
-{
- printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
-#ifdef REBOOT_NOTIFIER
- register_reboot_notifier(&adpt_reboot_notifier);
-#endif
-
- return 0;
-}
-
-
static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun)
{
struct adpt_device* d;
@@ -1283,6 +1434,7 @@
{
u32 msg[8];
u8* status;
+ dma_addr_t addr;
u32 m = EMPTY_QUEUE ;
ulong timeout = jiffies + (TMOUT_IOPRESET*HZ);
@@ -1305,12 +1457,13 @@
schedule_timeout_uninterruptible(1);
} while (m == EMPTY_QUEUE);
- status = kzalloc(4, GFP_KERNEL|ADDR32);
+ status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
if(status == NULL) {
adpt_send_nop(pHba, m);
printk(KERN_ERR"IOP reset failed - no free memory.\n");
return -ENOMEM;
}
+ memset(status,0,4);
msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
@@ -1318,8 +1471,8 @@
msg[3]=0;
msg[4]=0;
msg[5]=0;
- msg[6]=virt_to_bus(status);
- msg[7]=0;
+ msg[6]=dma_low(addr);
+ msg[7]=dma_high(addr);
memcpy_toio(pHba->msg_addr_virt+m, msg, sizeof(msg));
wmb();
@@ -1329,7 +1482,10 @@
while(*status == 0){
if(time_after(jiffies,timeout)){
printk(KERN_WARNING"%s: IOP Reset Timeout\n",pHba->name);
- kfree(status);
+ /* We lose 4 bytes of "status" here, but we cannot
+ free these because controller may awake and corrupt
+ those bytes at any time */
+ /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
return -ETIMEDOUT;
}
rmb();
@@ -1348,6 +1504,10 @@
}
if(time_after(jiffies,timeout)){
printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name);
+ /* We lose 4 bytes of "status" here, but we
+ cannot free these because controller may
+ awake and corrupt those bytes at any time */
+ /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */
return -ETIMEDOUT;
}
schedule_timeout_uninterruptible(1);
@@ -1364,7 +1524,7 @@
PDEBUG("%s: Reset completed.\n", pHba->name);
}
- kfree(status);
+ dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
#ifdef UARTDELAY
// This delay is to allow someone attached to the card through the debug UART to
// set up the dump levels that they want before the rest of the initialization sequence
@@ -1636,6 +1796,7 @@
u32 i = 0;
u32 rcode = 0;
void *p = NULL;
+ dma_addr_t addr;
ulong flags = 0;
memset(&msg, 0, MAX_MESSAGE_SIZE*4);
@@ -1668,10 +1829,13 @@
}
sg_offset = (msg[0]>>4)&0xf;
msg[2] = 0x40000000; // IOCTL context
- msg[3] = (u32)reply;
+ msg[3] = adpt_ioctl_to_context(pHba, reply);
+ if (msg[3] == (u32)-1)
+ return -EBUSY;
+
memset(sg_list,0, sizeof(sg_list[0])*pHba->sg_tablesize);
if(sg_offset) {
- // TODO 64bit fix
+ // TODO add 64 bit API
struct sg_simple_element *sg = (struct sg_simple_element*) (msg+sg_offset);
sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
if (sg_count > pHba->sg_tablesize){
@@ -1690,7 +1854,7 @@
}
sg_size = sg[i].flag_count & 0xffffff;
/* Allocate memory for the transfer */
- p = kmalloc(sg_size, GFP_KERNEL|ADDR32);
+ p = dma_alloc_coherent(&pHba->pDev->dev, sg_size, &addr, GFP_KERNEL);
if(!p) {
printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
pHba->name,sg_size,i,sg_count);
@@ -1700,15 +1864,15 @@
sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame.
/* Copy in the user's SG buffer if necessary */
if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) {
- // TODO 64bit fix
- if (copy_from_user(p,(void __user *)sg[i].addr_bus, sg_size)) {
+ // sg_simple_element API is 32 bit
+ if (copy_from_user(p,(void __user *)(ulong)sg[i].addr_bus, sg_size)) {
printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i);
rcode = -EFAULT;
goto cleanup;
}
}
- //TODO 64bit fix
- sg[i].addr_bus = (u32)virt_to_bus(p);
+ /* sg_simple_element API is 32 bit, but addr < 4GB */
+ sg[i].addr_bus = addr;
}
}
@@ -1736,7 +1900,7 @@
if(sg_offset) {
/* Copy back the Scatter Gather buffers back to user space */
u32 j;
- // TODO 64bit fix
+ // TODO add 64 bit API
struct sg_simple_element* sg;
int sg_size;
@@ -1756,14 +1920,14 @@
}
sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
- // TODO 64bit fix
+ // TODO add 64 bit API
sg = (struct sg_simple_element*)(msg + sg_offset);
for (j = 0; j < sg_count; j++) {
/* Copy out the SG list to user's buffer if necessary */
if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) {
sg_size = sg[j].flag_count & 0xffffff;
- // TODO 64bit fix
- if (copy_to_user((void __user *)sg[j].addr_bus,sg_list[j], sg_size)) {
+ // sg_simple_element API is 32 bit
+ if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) {
printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus);
rcode = -EFAULT;
goto cleanup;
@@ -1787,12 +1951,17 @@
cleanup:
- if (rcode != -ETIME && rcode != -EINTR)
+ if (rcode != -ETIME && rcode != -EINTR) {
+ struct sg_simple_element *sg =
+ (struct sg_simple_element*) (msg +sg_offset);
kfree (reply);
- while(sg_index) {
- if(sg_list[--sg_index]) {
- if (rcode != -ETIME && rcode != -EINTR)
- kfree(sg_list[sg_index]);
+ while(sg_index) {
+ if(sg_list[--sg_index]) {
+ dma_free_coherent(&pHba->pDev->dev,
+ sg[sg_index].flag_count & 0xffffff,
+ sg_list[sg_index],
+ sg[sg_index].addr_bus);
+ }
}
}
return rcode;
@@ -1978,6 +2147,38 @@
return error;
}
+#ifdef CONFIG_COMPAT
+static long compat_adpt_ioctl(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode;
+ long ret;
+
+ inode = file->f_dentry->d_inode;
+
+ lock_kernel();
+
+ switch(cmd) {
+ case DPT_SIGNATURE:
+ case I2OUSRCMD:
+ case DPT_CTRLINFO:
+ case DPT_SYSINFO:
+ case DPT_BLINKLED:
+ case I2ORESETCMD:
+ case I2ORESCANCMD:
+ case (DPT_TARGET_BUSY & 0xFFFF):
+ case DPT_TARGET_BUSY:
+ ret = adpt_ioctl(inode, file, cmd, arg);
+ break;
+ default:
+ ret = -ENOIOCTLCMD;
+ }
+
+ unlock_kernel();
+
+ return ret;
+}
+#endif
static irqreturn_t adpt_isr(int irq, void *dev_id)
{
@@ -2009,7 +2210,16 @@
goto out;
}
}
- reply = bus_to_virt(m);
+ if (pHba->reply_pool_pa <= m &&
+ m < pHba->reply_pool_pa +
+ (pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4)) {
+ reply = (u8 *)pHba->reply_pool +
+ (m - pHba->reply_pool_pa);
+ } else {
+ /* Ick, we should *never* be here */
+ printk(KERN_ERR "dpti: reply frame not from pool\n");
+ reply = (u8 *)bus_to_virt(m);
+ }
if (readl(reply) & MSG_FAIL) {
u32 old_m = readl(reply+28);
@@ -2029,7 +2239,7 @@
}
context = readl(reply+8);
if(context & 0x40000000){ // IOCTL
- void *p = (void *)readl(reply+12);
+ void *p = adpt_ioctl_from_context(pHba, readl(reply+12));
if( p != NULL) {
memcpy_fromio(p, reply, REPLY_FRAME_SIZE * 4);
}
@@ -2043,15 +2253,17 @@
status = I2O_POST_WAIT_OK;
}
if(!(context & 0x40000000)) {
- cmd = (struct scsi_cmnd*) readl(reply+12);
+ cmd = adpt_cmd_from_context(pHba,
+ readl(reply+12));
if(cmd != NULL) {
printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context);
}
}
adpt_i2o_post_wait_complete(context, status);
} else { // SCSI message
- cmd = (struct scsi_cmnd*) readl(reply+12);
+ cmd = adpt_cmd_from_context (pHba, readl(reply+12));
if(cmd != NULL){
+ scsi_dma_unmap(cmd);
if(cmd->serial_number != 0) { // If not timedout
adpt_i2o_to_scsi(reply, cmd);
}
@@ -2072,6 +2284,7 @@
int i;
u32 msg[MAX_MESSAGE_SIZE];
u32* mptr;
+ u32* lptr;
u32 *lenptr;
int direction;
int scsidir;
@@ -2079,6 +2292,7 @@
u32 len;
u32 reqlen;
s32 rcode;
+ dma_addr_t addr;
memset(msg, 0 , sizeof(msg));
len = scsi_bufflen(cmd);
@@ -2118,7 +2332,7 @@
// I2O_CMD_SCSI_EXEC
msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid);
msg[2] = 0;
- msg[3] = (u32)cmd; /* We want the SCSI control block back */
+ msg[3] = adpt_cmd_to_context(cmd); /* Want SCSI control block back */
// Our cards use the transaction context as the tag for queueing
// Adaptec/DPT Private stuff
msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16);
@@ -2136,7 +2350,13 @@
memcpy(mptr, cmd->cmnd, cmd->cmd_len);
mptr+=4;
lenptr=mptr++; /* Remember me - fill in when we know */
- reqlen = 14; // SINGLE SGE
+ if (dpt_dma64(pHba)) {
+ reqlen = 16; // SINGLE SGE
+ *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */
+ *mptr++ = 1 << PAGE_SHIFT;
+ } else {
+ reqlen = 14; // SINGLE SGE
+ }
/* Now fill in the SGList and command */
nseg = scsi_dma_map(cmd);
@@ -2146,12 +2366,16 @@
len = 0;
scsi_for_each_sg(cmd, sg, nseg, i) {
+ lptr = mptr;
*mptr++ = direction|0x10000000|sg_dma_len(sg);
len+=sg_dma_len(sg);
- *mptr++ = sg_dma_address(sg);
+ addr = sg_dma_address(sg);
+ *mptr++ = dma_low(addr);
+ if (dpt_dma64(pHba))
+ *mptr++ = dma_high(addr);
/* Make this an end of list */
if (i == nseg - 1)
- mptr[-2] = direction|0xD0000000|sg_dma_len(sg);
+ *lptr = direction|0xD0000000|sg_dma_len(sg);
}
reqlen = mptr - msg;
*lenptr = len;
@@ -2177,13 +2401,13 @@
}
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
+static s32 adpt_scsi_host_alloc(adpt_hba* pHba, struct scsi_host_template *sht)
{
- struct Scsi_Host *host = NULL;
+ struct Scsi_Host *host;
- host = scsi_register(sht, sizeof(adpt_hba*));
+ host = scsi_host_alloc(sht, sizeof(adpt_hba*));
if (host == NULL) {
- printk ("%s: scsi_register returned NULL\n",pHba->name);
+ printk("%s: scsi_host_alloc returned NULL\n", pHba->name);
return -1;
}
host->hostdata[0] = (unsigned long)pHba;
@@ -2200,7 +2424,7 @@
host->max_lun = 256;
host->max_channel = pHba->top_scsi_channel + 1;
host->cmd_per_lun = 1;
- host->unique_id = (uint) pHba;
+ host->unique_id = (u32)sys_tbl_pa + pHba->unit;
host->sg_tablesize = pHba->sg_tablesize;
host->can_queue = pHba->post_fifo_size;
@@ -2640,11 +2864,10 @@
static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
{
u8 *status;
+ dma_addr_t addr;
u32 __iomem *msg = NULL;
int i;
ulong timeout = jiffies + TMOUT_INITOUTBOUND*HZ;
- u32* ptr;
- u32 outbound_frame; // This had to be a 32 bit address
u32 m;
do {
@@ -2663,13 +2886,14 @@
msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
- status = kzalloc(4, GFP_KERNEL|ADDR32);
+ status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL);
if (!status) {
adpt_send_nop(pHba, m);
printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n",
pHba->name);
return -ENOMEM;
}
+ memset(status, 0, 4);
writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]);
writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
@@ -2678,7 +2902,7 @@
writel(4096, &msg[4]); /* Host page frame size */
writel((REPLY_FRAME_SIZE)<<16|0x80, &msg[5]); /* Outbound msg frame size and Initcode */
writel(0xD0000004, &msg[6]); /* Simple SG LE, EOB */
- writel(virt_to_bus(status), &msg[7]);
+ writel((u32)addr, &msg[7]);
writel(m, pHba->post_port);
wmb();
@@ -2693,6 +2917,10 @@
rmb();
if(time_after(jiffies,timeout)){
printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name);
+ /* We lose 4 bytes of "status" here, but we
+ cannot free these because controller may
+ awake and corrupt those bytes at any time */
+ /* dma_free_coherent(&pHba->pDev->dev, 4, status, addr); */
return -ETIMEDOUT;
}
schedule_timeout_uninterruptible(1);
@@ -2701,25 +2929,30 @@
// If the command was successful, fill the fifo with our reply
// message packets
if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) {
- kfree(status);
+ dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
return -2;
}
- kfree(status);
+ dma_free_coherent(&pHba->pDev->dev, 4, status, addr);
- kfree(pHba->reply_pool);
+ if(pHba->reply_pool != NULL) {
+ dma_free_coherent(&pHba->pDev->dev,
+ pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+ pHba->reply_pool, pHba->reply_pool_pa);
+ }
- pHba->reply_pool = kzalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
+ pHba->reply_pool = dma_alloc_coherent(&pHba->pDev->dev,
+ pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4,
+ &pHba->reply_pool_pa, GFP_KERNEL);
if (!pHba->reply_pool) {
printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name);
return -ENOMEM;
}
+ memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4);
- ptr = pHba->reply_pool;
for(i = 0; i < pHba->reply_fifo_size; i++) {
- outbound_frame = (u32)virt_to_bus(ptr);
- writel(outbound_frame, pHba->reply_port);
+ writel(pHba->reply_pool_pa + (i * REPLY_FRAME_SIZE * 4),
+ pHba->reply_port);
wmb();
- ptr += REPLY_FRAME_SIZE;
}
adpt_i2o_status_get(pHba);
return 0;
@@ -2743,11 +2976,11 @@
u32 m;
u32 __iomem *msg;
u8 *status_block=NULL;
- ulong status_block_bus;
if(pHba->status_block == NULL) {
- pHba->status_block = (i2o_status_block*)
- kmalloc(sizeof(i2o_status_block),GFP_KERNEL|ADDR32);
+ pHba->status_block = dma_alloc_coherent(&pHba->pDev->dev,
+ sizeof(i2o_status_block),
+ &pHba->status_block_pa, GFP_KERNEL);
if(pHba->status_block == NULL) {
printk(KERN_ERR
"dpti%d: Get Status Block failed; Out of memory. \n",
@@ -2757,7 +2990,6 @@
}
memset(pHba->status_block, 0, sizeof(i2o_status_block));
status_block = (u8*)(pHba->status_block);
- status_block_bus = virt_to_bus(pHba->status_block);
timeout = jiffies+TMOUT_GETSTATUS*HZ;
do {
rmb();
@@ -2782,8 +3014,8 @@
writel(0, &msg[3]);
writel(0, &msg[4]);
writel(0, &msg[5]);
- writel(((u32)status_block_bus)&0xffffffff, &msg[6]);
- writel(0, &msg[7]);
+ writel( dma_low(pHba->status_block_pa), &msg[6]);
+ writel( dma_high(pHba->status_block_pa), &msg[7]);
writel(sizeof(i2o_status_block), &msg[8]); // 88 bytes
//post message
@@ -2812,7 +3044,17 @@
}
// Calculate the Scatter Gather list size
- pHba->sg_tablesize = (pHba->status_block->inbound_frame_size * 4 -40)/ sizeof(struct sg_simple_element);
+ if (dpt_dma64(pHba)) {
+ pHba->sg_tablesize
+ = ((pHba->status_block->inbound_frame_size * 4
+ - 14 * sizeof(u32))
+ / (sizeof(struct sg_simple_element) + sizeof(u32)));
+ } else {
+ pHba->sg_tablesize
+ = ((pHba->status_block->inbound_frame_size * 4
+ - 12 * sizeof(u32))
+ / sizeof(struct sg_simple_element));
+ }
if (pHba->sg_tablesize > SG_LIST_ELEMENTS) {
pHba->sg_tablesize = SG_LIST_ELEMENTS;
}
@@ -2863,7 +3105,9 @@
}
do {
if (pHba->lct == NULL) {
- pHba->lct = kmalloc(pHba->lct_size, GFP_KERNEL|ADDR32);
+ pHba->lct = dma_alloc_coherent(&pHba->pDev->dev,
+ pHba->lct_size, &pHba->lct_pa,
+ GFP_KERNEL);
if(pHba->lct == NULL) {
printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
pHba->name);
@@ -2879,7 +3123,7 @@
msg[4] = 0xFFFFFFFF; /* All devices */
msg[5] = 0x00000000; /* Report now */
msg[6] = 0xD0000000|pHba->lct_size;
- msg[7] = virt_to_bus(pHba->lct);
+ msg[7] = (u32)pHba->lct_pa;
if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 360))) {
printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n",
@@ -2890,7 +3134,8 @@
if ((pHba->lct->table_size << 2) > pHba->lct_size) {
pHba->lct_size = pHba->lct->table_size << 2;
- kfree(pHba->lct);
+ dma_free_coherent(&pHba->pDev->dev, pHba->lct_size,
+ pHba->lct, pHba->lct_pa);
pHba->lct = NULL;
}
} while (pHba->lct == NULL);
@@ -2901,13 +3146,19 @@
// I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO;
if(adpt_i2o_query_scalar(pHba, 0 , 0x8000, -1, buf, sizeof(buf))>=0) {
pHba->FwDebugBufferSize = buf[1];
- pHba->FwDebugBuffer_P = pHba->base_addr_virt + buf[0];
- pHba->FwDebugFlags_P = pHba->FwDebugBuffer_P + FW_DEBUG_FLAGS_OFFSET;
- pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P + FW_DEBUG_BLED_OFFSET;
- pHba->FwDebugBLEDflag_P = pHba->FwDebugBLEDvalue_P + 1;
- pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P + FW_DEBUG_STR_LENGTH_OFFSET;
- pHba->FwDebugBuffer_P += buf[2];
- pHba->FwDebugFlags = 0;
+ pHba->FwDebugBuffer_P = ioremap(pHba->base_addr_phys + buf[0],
+ pHba->FwDebugBufferSize);
+ if (pHba->FwDebugBuffer_P) {
+ pHba->FwDebugFlags_P = pHba->FwDebugBuffer_P +
+ FW_DEBUG_FLAGS_OFFSET;
+ pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P +
+ FW_DEBUG_BLED_OFFSET;
+ pHba->FwDebugBLEDflag_P = pHba->FwDebugBLEDvalue_P + 1;
+ pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P +
+ FW_DEBUG_STR_LENGTH_OFFSET;
+ pHba->FwDebugBuffer_P += buf[2];
+ pHba->FwDebugFlags = 0;
+ }
}
return 0;
@@ -2915,25 +3166,30 @@
static int adpt_i2o_build_sys_table(void)
{
- adpt_hba* pHba = NULL;
+ adpt_hba* pHba = hba_chain;
int count = 0;
+ if (sys_tbl)
+ dma_free_coherent(&pHba->pDev->dev, sys_tbl_len,
+ sys_tbl, sys_tbl_pa);
+
sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs
(hba_count) * sizeof(struct i2o_sys_tbl_entry);
- kfree(sys_tbl);
-
- sys_tbl = kzalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
+ sys_tbl = dma_alloc_coherent(&pHba->pDev->dev,
+ sys_tbl_len, &sys_tbl_pa, GFP_KERNEL);
if (!sys_tbl) {
printk(KERN_WARNING "SysTab Set failed. Out of memory.\n");
return -ENOMEM;
}
+ memset(sys_tbl, 0, sys_tbl_len);
sys_tbl->num_entries = hba_count;
sys_tbl->version = I2OVERSION;
sys_tbl->change_ind = sys_tbl_ind++;
for(pHba = hba_chain; pHba; pHba = pHba->next) {
+ u64 addr;
// Get updated Status Block so we have the latest information
if (adpt_i2o_status_get(pHba)) {
sys_tbl->num_entries--;
@@ -2949,8 +3205,9 @@
sys_tbl->iops[count].frame_size = pHba->status_block->inbound_frame_size;
sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
sys_tbl->iops[count].iop_capabilities = pHba->status_block->iop_capabilities;
- sys_tbl->iops[count].inbound_low = (u32)virt_to_bus(pHba->post_port);
- sys_tbl->iops[count].inbound_high = (u32)((u64)virt_to_bus(pHba->post_port)>>32);
+ addr = pHba->base_addr_phys + 0x40;
+ sys_tbl->iops[count].inbound_low = dma_low(addr);
+ sys_tbl->iops[count].inbound_high = dma_high(addr);
count++;
}
@@ -3086,7 +3343,8 @@
do {
if (pHba->hrt == NULL) {
- pHba->hrt=kmalloc(size, GFP_KERNEL|ADDR32);
+ pHba->hrt = dma_alloc_coherent(&pHba->pDev->dev,
+ size, &pHba->hrt_pa, GFP_KERNEL);
if (pHba->hrt == NULL) {
printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", pHba->name);
return -ENOMEM;
@@ -3098,7 +3356,7 @@
msg[2]= 0;
msg[3]= 0;
msg[4]= (0xD0000000 | size); /* Simple transaction */
- msg[5]= virt_to_bus(pHba->hrt); /* Dump it here */
+ msg[5]= (u32)pHba->hrt_pa; /* Dump it here */
if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg),20))) {
printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", pHba->name, ret);
@@ -3106,8 +3364,10 @@
}
if (pHba->hrt->num_entries * pHba->hrt->entry_len << 2 > size) {
- size = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
- kfree(pHba->hrt);
+ int newsize = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
+ dma_free_coherent(&pHba->pDev->dev, size,
+ pHba->hrt, pHba->hrt_pa);
+ size = newsize;
pHba->hrt = NULL;
}
} while(pHba->hrt == NULL);
@@ -3121,33 +3381,54 @@
int group, int field, void *buf, int buflen)
{
u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
- u8 *resblk;
+ u8 *opblk_va;
+ dma_addr_t opblk_pa;
+ u8 *resblk_va;
+ dma_addr_t resblk_pa;
int size;
/* 8 bytes for header */
- resblk = kmalloc(sizeof(u8) * (8+buflen), GFP_KERNEL|ADDR32);
- if (resblk == NULL) {
+ resblk_va = dma_alloc_coherent(&pHba->pDev->dev,
+ sizeof(u8) * (8 + buflen), &resblk_pa, GFP_KERNEL);
+ if (resblk_va == NULL) {
printk(KERN_CRIT "%s: query scalar failed; Out of memory.\n", pHba->name);
return -ENOMEM;
}
+ opblk_va = dma_alloc_coherent(&pHba->pDev->dev,
+ sizeof(opblk), &opblk_pa, GFP_KERNEL);
+ if (opblk_va == NULL) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
+ printk(KERN_CRIT "%s: query operatio failed; Out of memory.\n",
+ pHba->name);
+ return -ENOMEM;
+ }
if (field == -1) /* whole group */
opblk[4] = -1;
+ memcpy(opblk_va, opblk, sizeof(opblk));
size = adpt_i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, pHba, tid,
- opblk, sizeof(opblk), resblk, sizeof(u8)*(8+buflen));
+ opblk_va, opblk_pa, sizeof(opblk),
+ resblk_va, resblk_pa, sizeof(u8)*(8+buflen));
+ dma_free_coherent(&pHba->pDev->dev, sizeof(opblk), opblk_va, opblk_pa);
if (size == -ETIME) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
printk(KERN_WARNING "%s: issue params failed; Timed out.\n", pHba->name);
return -ETIME;
} else if (size == -EINTR) {
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
printk(KERN_WARNING "%s: issue params failed; Interrupted.\n", pHba->name);
return -EINTR;
}
- memcpy(buf, resblk+8, buflen); /* cut off header */
+ memcpy(buf, resblk_va+8, buflen); /* cut off header */
- kfree(resblk);
+ dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen),
+ resblk_va, resblk_pa);
if (size < 0)
return size;
@@ -3164,10 +3445,11 @@
* ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
*/
static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
- void *opblk, int oplen, void *resblk, int reslen)
+ void *opblk_va, dma_addr_t opblk_pa, int oplen,
+ void *resblk_va, dma_addr_t resblk_pa, int reslen)
{
u32 msg[9];
- u32 *res = (u32 *)resblk;
+ u32 *res = (u32 *)resblk_va;
int wait_status;
msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
@@ -3176,12 +3458,12 @@
msg[3] = 0;
msg[4] = 0;
msg[5] = 0x54000000 | oplen; /* OperationBlock */
- msg[6] = virt_to_bus(opblk);
+ msg[6] = (u32)opblk_pa;
msg[7] = 0xD0000000 | reslen; /* ResultBlock */
- msg[8] = virt_to_bus(resblk);
+ msg[8] = (u32)resblk_pa;
if ((wait_status = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 20))) {
- printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk);
+ printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk_va);
return wait_status; /* -DetailedStatus */
}
@@ -3284,7 +3566,7 @@
* Private i/o space declaration
*/
msg[6] = 0x54000000 | sys_tbl_len;
- msg[7] = virt_to_phys(sys_tbl);
+ msg[7] = (u32)sys_tbl_pa;
msg[8] = 0x54000000 | 0;
msg[9] = 0;
msg[10] = 0xD4000000 | 0;
@@ -3323,11 +3605,10 @@
#endif
static struct scsi_host_template driver_template = {
+ .module = THIS_MODULE,
.name = "dpt_i2o",
.proc_name = "dpt_i2o",
.proc_info = adpt_proc_info,
- .detect = adpt_detect,
- .release = adpt_release,
.info = adpt_info,
.queuecommand = adpt_queue,
.eh_abort_handler = adpt_abort,
@@ -3341,5 +3622,48 @@
.cmd_per_lun = 1,
.use_clustering = ENABLE_CLUSTERING,
};
-#include "scsi_module.c"
+
+static int __init adpt_init(void)
+{
+ int error;
+ adpt_hba *pHba, *next;
+
+ printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
+
+ error = adpt_detect(&driver_template);
+ if (error < 0)
+ return error;
+ if (hba_chain == NULL)
+ return -ENODEV;
+
+ for (pHba = hba_chain; pHba; pHba = pHba->next) {
+ error = scsi_add_host(pHba->host, &pHba->pDev->dev);
+ if (error)
+ goto fail;
+ scsi_scan_host(pHba->host);
+ }
+ return 0;
+fail:
+ for (pHba = hba_chain; pHba; pHba = next) {
+ next = pHba->next;
+ scsi_remove_host(pHba->host);
+ }
+ return error;
+}
+
+static void __exit adpt_exit(void)
+{
+ adpt_hba *pHba, *next;
+
+ for (pHba = hba_chain; pHba; pHba = pHba->next)
+ scsi_remove_host(pHba->host);
+ for (pHba = hba_chain; pHba; pHba = next) {
+ next = pHba->next;
+ adpt_release(pHba->host);
+ }
+}
+
+module_init(adpt_init);
+module_exit(adpt_exit);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index fd79068..924cd5a 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -84,7 +84,6 @@
#define PCI_DPT_DEVICE_ID (0xA501) // DPT PCI I2O Device ID
#define PCI_DPT_RAPTOR_DEVICE_ID (0xA511)
-//#define REBOOT_NOTIFIER 1
/* Debugging macro from Linux Device Drivers - Rubini */
#undef PDEBUG
#ifdef DEBUG
@@ -229,14 +228,19 @@
u32 post_fifo_size;
u32 reply_fifo_size;
u32* reply_pool;
+ dma_addr_t reply_pool_pa;
u32 sg_tablesize; // Scatter/Gather List Size.
u8 top_scsi_channel;
u8 top_scsi_id;
u8 top_scsi_lun;
+ u8 dma64;
i2o_status_block* status_block;
+ dma_addr_t status_block_pa;
i2o_hrt* hrt;
+ dma_addr_t hrt_pa;
i2o_lct* lct;
+ dma_addr_t lct_pa;
uint lct_size;
struct i2o_device* devices;
struct adpt_channel channel[MAX_CHANNEL];
@@ -249,6 +253,7 @@
void __iomem *FwDebugBLEDflag_P;// Virtual Addr Of FW Debug BLED
void __iomem *FwDebugBLEDvalue_P;// Virtual Addr Of FW Debug BLED
u32 FwDebugFlags;
+ u32 *ioctl_reply_context[4];
} adpt_hba;
struct sg_simple_element {
@@ -264,9 +269,6 @@
static int adpt_init(void);
static int adpt_i2o_build_sys_table(void);
static irqreturn_t adpt_isr(int irq, void *dev_id);
-#ifdef REBOOT_NOTIFIER
-static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p);
-#endif
static void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d);
static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid,
@@ -275,7 +277,8 @@
static const char *adpt_i2o_get_class_name(int class);
#endif
static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid,
- void *opblk, int oplen, void *resblk, int reslen);
+ void *opblk, dma_addr_t opblk_pa, int oplen,
+ void *resblk, dma_addr_t resblk_pa, int reslen);
static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout);
static int adpt_i2o_lct_get(adpt_hba* pHba);
static int adpt_i2o_parse_lct(adpt_hba* pHba);
@@ -289,7 +292,7 @@
static s32 adpt_i2o_hrt_get(adpt_hba* pHba);
static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* dptdevice);
static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd);
-static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht);
+static s32 adpt_scsi_host_alloc(adpt_hba* pHba,struct scsi_host_template * sht);
static s32 adpt_hba_reset(adpt_hba* pHba);
static s32 adpt_i2o_reset_hba(adpt_hba* pHba);
static s32 adpt_rescan(adpt_hba* pHba);
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index c6d6e7c..8e2e964 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -465,7 +465,7 @@
scp->request = (struct request *)&wait;
scp->timeout_per_command = timeout*HZ;
scp->cmd_len = 12;
- memcpy(scp->cmnd, cmnd, 12);
+ scp->cmnd = cmnd;
cmndinfo.priority = IOCTL_PRI;
cmndinfo.internal_cmd_str = gdtcmd;
cmndinfo.internal_command = 1;
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 5b7be1e..aaa48e0 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -763,9 +763,9 @@
scp,
host->host_no, scp->device->channel,
scp->device->id, scp->device->lun,
- *((u32 *)&scp->cmnd),
- *((u32 *)&scp->cmnd + 1),
- *((u32 *)&scp->cmnd + 2),
+ ((u32 *)scp->cmnd)[0],
+ ((u32 *)scp->cmnd)[1],
+ ((u32 *)scp->cmnd)[2],
_req->index, _req->req_virt);
scp->result = 0;
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 4a922c5..ccfd8ac 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -686,7 +686,7 @@
}
if (cmnd) {
- cmnd->result = rsp->status;
+ cmnd->result |= rsp->status;
if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
memcpy(cmnd->sense_buffer,
rsp->data,
@@ -730,6 +730,7 @@
u16 lun = lun_from_dev(cmnd->device);
u8 out_fmt, in_fmt;
+ cmnd->result = (DID_OK << 16);
evt_struct = get_event_struct(&hostdata->pool);
if (!evt_struct)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -738,7 +739,7 @@
srp_cmd = &evt_struct->iu.srp.cmd;
memset(srp_cmd, 0x00, SRP_MAX_IU_LEN);
srp_cmd->opcode = SRP_CMD;
- memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
+ memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb));
srp_cmd->lun = ((u64) lun) << 48;
if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) {
@@ -1347,6 +1348,8 @@
del_timer(&evt_struct->timer);
+ if (crq->status != VIOSRP_OK && evt_struct->cmnd)
+ evt_struct->cmnd->result = DID_ERROR << 16;
if (evt_struct->done)
evt_struct->done(evt_struct);
else
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
index 90f1a61..4c4aadb 100644
--- a/drivers/scsi/ibmvscsi/viosrp.h
+++ b/drivers/scsi/ibmvscsi/viosrp.h
@@ -59,6 +59,15 @@
VIOSRP_INLINE_FORMAT = 0x07
};
+enum viosrp_crq_status {
+ VIOSRP_OK = 0x0,
+ VIOSRP_NONRECOVERABLE_ERR = 0x1,
+ VIOSRP_VIOLATES_MAX_XFER = 0x2,
+ VIOSRP_PARTNER_PANIC = 0x3,
+ VIOSRP_DEVICE_BUSY = 0x8,
+ VIOSRP_ADAPTER_FAIL = 0x10
+};
+
struct viosrp_crq {
u8 valid; /* used by RPA */
u8 format; /* SCSI vs out-of-band */
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index dbae3fd..e3f7397 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -2590,7 +2590,7 @@
cblk->hastat = 0;
cblk->tastat = 0;
/* Command the command */
- memcpy(&cblk->cdb[0], &cmnd->cmnd, cmnd->cmd_len);
+ memcpy(cblk->cdb, cmnd->cmnd, cmnd->cmd_len);
/* Set up tags */
if (cmnd->device->tagged_supported) { /* Tag Support */
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index de5ae6a..999e91e 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -2791,7 +2791,7 @@
static struct device_attribute ipr_ioa_state_attr = {
.attr = {
- .name = "state",
+ .name = "online_state",
.mode = S_IRUGO | S_IWUSR,
},
.show = ipr_show_adapter_state,
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index b135a1e..18551aa 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -4996,7 +4996,7 @@
max_mbox_busy_wait = MBOX_BUSY_WAIT;
#ifdef CONFIG_PROC_FS
- mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
+ mega_proc_dir_entry = proc_mkdir("megaraid", NULL);
if (!mega_proc_dir_entry) {
printk(KERN_WARNING
"megaraid: failed to create megaraid root\n");
@@ -5005,7 +5005,7 @@
error = pci_register_driver(&megaraid_pci_driver);
if (error) {
#ifdef CONFIG_PROC_FS
- remove_proc_entry("megaraid", &proc_root);
+ remove_proc_entry("megaraid", NULL);
#endif
return error;
}
@@ -5035,7 +5035,7 @@
pci_unregister_driver(&megaraid_pci_driver);
#ifdef CONFIG_PROC_FS
- remove_proc_entry("megaraid", &proc_root);
+ remove_proc_entry("megaraid", NULL);
#endif
}
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 820f91f..70a0f11 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -3168,6 +3168,23 @@
uint8_t raw_mbox[sizeof(mbox_t)];
int rval;
+ /*
+ * Newer firmware on Dell CERC expect a different
+ * random deletion handling, so disable it.
+ */
+ if (adapter->pdev->vendor == PCI_VENDOR_ID_AMI &&
+ adapter->pdev->device == PCI_DEVICE_ID_AMI_MEGARAID3 &&
+ adapter->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
+ adapter->pdev->subsystem_device == PCI_SUBSYS_ID_CERC_ATA100_4CH &&
+ (adapter->fw_version[0] > '6' ||
+ (adapter->fw_version[0] == '6' &&
+ adapter->fw_version[2] > '6') ||
+ (adapter->fw_version[0] == '6'
+ && adapter->fw_version[2] == '6'
+ && adapter->fw_version[3] > '1'))) {
+ con_log(CL_DLEVEL1, ("megaraid: disable random deletion\n"));
+ return 0;
+ }
mbox = (mbox_t *)raw_mbox;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
index 626459d..c1d86d9 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.h
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -88,6 +88,7 @@
#define PCI_SUBSYS_ID_PERC3_QC 0x0471
#define PCI_SUBSYS_ID_PERC3_DC 0x0493
#define PCI_SUBSYS_ID_PERC3_SC 0x0475
+#define PCI_SUBSYS_ID_CERC_ATA100_4CH 0x0511
#define MBOX_MAX_SCSI_CMDS 128 // number of cmds reserved for kernel
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index b937e9c..7d84c8b 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.03.16-rc1
+ * Version : v00.00.03.20-rc1
*
* Authors:
* (email-id : megaraidlinux@lsi.com)
@@ -2650,12 +2650,13 @@
return;
}
+#ifdef CONFIG_PM
/**
* megasas_suspend - driver suspend entry point
* @pdev: PCI device structure
* @state: PCI power state to suspend routine
*/
-static int __devinit
+static int
megasas_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct Scsi_Host *host;
@@ -2687,7 +2688,7 @@
* megasas_resume- driver resume entry point
* @pdev: PCI device structure
*/
-static int __devinit
+static int
megasas_resume(struct pci_dev *pdev)
{
int rval;
@@ -2782,12 +2783,16 @@
return -ENODEV;
}
+#else
+#define megasas_suspend NULL
+#define megasas_resume NULL
+#endif
/**
* megasas_detach_one - PCI hot"un"plug entry point
* @pdev: PCI device structure
*/
-static void megasas_detach_one(struct pci_dev *pdev)
+static void __devexit megasas_detach_one(struct pci_dev *pdev)
{
int i;
struct Scsi_Host *host;
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 3a997eb..b0c41e6 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,9 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.03.16-rc1"
-#define MEGASAS_RELDATE "Nov. 07, 2007"
-#define MEGASAS_EXT_VERSION "Thu. Nov. 07 10:09:32 PDT 2007"
+#define MEGASAS_VERSION "00.00.03.20-rc1"
+#define MEGASAS_RELDATE "March 10, 2008"
+#define MEGASAS_EXT_VERSION "Mon. March 10 11:02:31 PDT 2008"
/*
* Device IDs
diff --git a/drivers/scsi/mvsas.c b/drivers/scsi/mvsas.c
index e55b903..1dd70d7 100644
--- a/drivers/scsi/mvsas.c
+++ b/drivers/scsi/mvsas.c
@@ -2822,7 +2822,9 @@
dev_printk(KERN_DEBUG, &pdev->dev,
"phy[%d] Get Attached Address 0x%llX ,"
" SAS Address 0x%llX\n",
- i, phy->att_dev_sas_addr, phy->dev_sas_addr);
+ i,
+ (unsigned long long)phy->att_dev_sas_addr,
+ (unsigned long long)phy->dev_sas_addr);
dev_printk(KERN_DEBUG, &pdev->dev,
"Rate = %x , type = %d\n",
sas_phy->linkrate, phy->phy_type);
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index ceab4f73..c57c94c 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -8222,7 +8222,7 @@
#ifdef DEBUG_WAITING_LIST
if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
#endif
- while (wcmd = waiting_list) {
+ while ((wcmd = waiting_list) != NULL) {
waiting_list = (struct scsi_cmnd *) wcmd->next_wcmd;
wcmd->next_wcmd = NULL;
if (sts == DID_OK) {
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 09ab3ea..fa06093 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -2858,7 +2858,7 @@
/* Load SCSI command packet. */
pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
- memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+ memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd));
/* dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
/* Set transfer direction. */
@@ -3127,7 +3127,7 @@
/* Load SCSI command packet. */
pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
- memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+ memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd));
/*dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
/* Set transfer direction. */
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 12d69d7..110e776 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -79,15 +79,6 @@
#define MIN_RESET_PERIOD (15*HZ)
/*
- * Macro to determine the size of SCSI command. This macro takes vendor
- * unique commands into account. SCSI commands in groups 6 and 7 are
- * vendor unique and we will depend upon the command length being
- * supplied correctly in cmd_len.
- */
-#define CDB_SIZE(cmd) (((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
- COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
-
-/*
* Note - the initial logging level can be set here to log events at boot time.
* After the system is up, you may enable logging via the /proc interface.
*/
@@ -469,6 +460,7 @@
cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask);
if (!cmd) {
scsi_put_host_cmd_pool(gfp_mask);
+ shost->cmd_pool = NULL;
return -ENOMEM;
}
list_add(&cmd->list, &shost->free_list);
@@ -481,6 +473,13 @@
*/
void scsi_destroy_command_freelist(struct Scsi_Host *shost)
{
+ /*
+ * If cmd_pool is NULL the free list was not initialized, so
+ * do not attempt to release resources.
+ */
+ if (!shost->cmd_pool)
+ return;
+
while (!list_empty(&shost->free_list)) {
struct scsi_cmnd *cmd;
@@ -701,9 +700,11 @@
* Before we queue this command, check if the command
* length exceeds what the host adapter can handle.
*/
- if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {
+ if (cmd->cmd_len > cmd->device->host->max_cmd_len) {
SCSI_LOG_MLQUEUE(3,
- printk("queuecommand : command too long.\n"));
+ printk("queuecommand : command too long. "
+ "cdb_size=%d host->max_cmd_len=%d\n",
+ cmd->cmd_len, cmd->device->host->max_cmd_len));
cmd->result = (DID_ABORT << 16);
scsi_done(cmd);
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 07103c3..f6600bf 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1773,7 +1773,7 @@
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
- set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags);
+ queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue);
return 0;
}
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index b8de041..a235802 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -449,37 +449,40 @@
}
#ifdef CONFIG_SCSI_PROC_FS
-/*
- * proc_scsi_dev_info_read: dump the scsi_dev_info_list via
- * /proc/scsi/device_info
- */
-static int proc_scsi_devinfo_read(char *buffer, char **start,
- off_t offset, int length)
+static int devinfo_seq_show(struct seq_file *m, void *v)
{
- struct scsi_dev_info_list *devinfo;
- int size, len = 0;
- off_t begin = 0;
- off_t pos = 0;
+ struct scsi_dev_info_list *devinfo =
+ list_entry(v, struct scsi_dev_info_list, dev_info_list);
- list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
- size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",
+ seq_printf(m, "'%.8s' '%.16s' 0x%x\n",
devinfo->vendor, devinfo->model, devinfo->flags);
- len += size;
- pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
- }
+ return 0;
+}
-stop_output:
- *start = buffer + (offset - begin); /* Start of wanted data */
- len -= (offset - begin); /* Start slop */
- if (len > length)
- len = length; /* Ending slop */
- return (len);
+static void * devinfo_seq_start(struct seq_file *m, loff_t *pos)
+{
+ return seq_list_start(&scsi_dev_info_list, *pos);
+}
+
+static void * devinfo_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ return seq_list_next(v, &scsi_dev_info_list, pos);
+}
+
+static void devinfo_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static const struct seq_operations scsi_devinfo_seq_ops = {
+ .start = devinfo_seq_start,
+ .next = devinfo_seq_next,
+ .stop = devinfo_seq_stop,
+ .show = devinfo_seq_show,
+};
+
+static int proc_scsi_devinfo_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &scsi_devinfo_seq_ops);
}
/*
@@ -489,11 +492,12 @@
* integer value of flag to the scsi device info list.
* To use, echo "vendor:model:flag" > /proc/scsi/device_info
*/
-static int proc_scsi_devinfo_write(struct file *file, const char __user *buf,
- unsigned long length, void *data)
+static ssize_t proc_scsi_devinfo_write(struct file *file,
+ const char __user *buf,
+ size_t length, loff_t *ppos)
{
char *buffer;
- int err = length;
+ ssize_t err = length;
if (!buf || length>PAGE_SIZE)
return -EINVAL;
@@ -517,6 +521,15 @@
free_page((unsigned long)buffer);
return err;
}
+
+static const struct file_operations scsi_devinfo_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_scsi_devinfo_open,
+ .read = seq_read,
+ .write = proc_scsi_devinfo_write,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
#endif /* CONFIG_SCSI_PROC_FS */
module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0);
@@ -577,15 +590,13 @@
}
#ifdef CONFIG_SCSI_PROC_FS
- p = create_proc_entry("scsi/device_info", 0, NULL);
+ p = proc_create("scsi/device_info", 0, NULL, &scsi_devinfo_proc_fops);
if (!p) {
error = -ENOMEM;
goto out;
}
p->owner = THIS_MODULE;
- p->get_info = proc_scsi_devinfo_read;
- p->write_proc = proc_scsi_devinfo_write;
#endif /* CONFIG_SCSI_PROC_FS */
out:
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 221f31e..eaf5a8a 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -626,7 +626,7 @@
* @scmd: SCSI command structure to hijack
* @ses: structure to save restore information
* @cmnd: CDB to send. Can be NULL if no new cmnd is needed
- * @cmnd_size: size in bytes of @cmnd
+ * @cmnd_size: size in bytes of @cmnd (must be <= BLK_MAX_CDB)
* @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored)
*
* This function is used to save a scsi command information before re-execution
@@ -648,12 +648,14 @@
* command.
*/
ses->cmd_len = scmd->cmd_len;
- memcpy(ses->cmnd, scmd->cmnd, sizeof(scmd->cmnd));
+ ses->cmnd = scmd->cmnd;
ses->data_direction = scmd->sc_data_direction;
ses->sdb = scmd->sdb;
ses->next_rq = scmd->request->next_rq;
ses->result = scmd->result;
+ scmd->cmnd = ses->eh_cmnd;
+ memset(scmd->cmnd, 0, BLK_MAX_CDB);
memset(&scmd->sdb, 0, sizeof(scmd->sdb));
scmd->request->next_rq = NULL;
@@ -665,14 +667,13 @@
scmd->sdb.table.sgl = &ses->sense_sgl;
scmd->sc_data_direction = DMA_FROM_DEVICE;
scmd->sdb.table.nents = 1;
- memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
scmd->cmnd[0] = REQUEST_SENSE;
scmd->cmnd[4] = scmd->sdb.length;
scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
} else {
scmd->sc_data_direction = DMA_NONE;
if (cmnd) {
- memset(scmd->cmnd, 0, sizeof(scmd->cmnd));
+ BUG_ON(cmnd_size > BLK_MAX_CDB);
memcpy(scmd->cmnd, cmnd, cmnd_size);
scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
}
@@ -705,7 +706,7 @@
* Restore original data
*/
scmd->cmd_len = ses->cmd_len;
- memcpy(scmd->cmnd, ses->cmnd, sizeof(scmd->cmnd));
+ scmd->cmnd = ses->cmnd;
scmd->sc_data_direction = ses->data_direction;
scmd->sdb = ses->sdb;
scmd->request->next_rq = ses->next_rq;
@@ -1771,11 +1772,12 @@
unsigned long flags;
int rtn;
+ blk_rq_init(NULL, &req);
scmd->request = &req;
memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
- memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
-
+ scmd->cmnd = req.cmd;
+
scmd->scsi_done = scsi_reset_provider_done_command;
memset(&scmd->sdb, 0, sizeof(scmd->sdb));
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 67f412b..a82d2fe 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -445,7 +445,7 @@
scsi_set_resid(cmd, 0);
memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
if (cmd->cmd_len == 0)
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+ cmd->cmd_len = scsi_command_size(cmd->cmnd);
}
void scsi_device_unbusy(struct scsi_device *sdev)
@@ -536,6 +536,9 @@
!shost->host_blocked && !shost->host_self_blocked &&
!((shost->can_queue > 0) &&
(shost->host_busy >= shost->can_queue))) {
+
+ int flagset;
+
/*
* As long as shost is accepting commands and we have
* starved queues, call blk_run_queue. scsi_request_fn
@@ -549,19 +552,20 @@
sdev = list_entry(shost->starved_list.next,
struct scsi_device, starved_entry);
list_del_init(&sdev->starved_entry);
- spin_unlock_irqrestore(shost->host_lock, flags);
+ spin_unlock(shost->host_lock);
+ spin_lock(sdev->request_queue->queue_lock);
+ flagset = test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) &&
+ !test_bit(QUEUE_FLAG_REENTER,
+ &sdev->request_queue->queue_flags);
+ if (flagset)
+ queue_flag_set(QUEUE_FLAG_REENTER, sdev->request_queue);
+ __blk_run_queue(sdev->request_queue);
+ if (flagset)
+ queue_flag_clear(QUEUE_FLAG_REENTER, sdev->request_queue);
+ spin_unlock(sdev->request_queue->queue_lock);
- if (test_bit(QUEUE_FLAG_REENTER, &q->queue_flags) &&
- !test_and_set_bit(QUEUE_FLAG_REENTER,
- &sdev->request_queue->queue_flags)) {
- blk_run_queue(sdev->request_queue);
- clear_bit(QUEUE_FLAG_REENTER,
- &sdev->request_queue->queue_flags);
- } else
- blk_run_queue(sdev->request_queue);
-
- spin_lock_irqsave(shost->host_lock, flags);
+ spin_lock(shost->host_lock);
if (unlikely(!list_empty(&sdev->starved_entry)))
/*
* sdev lost a race, and was put back on the
@@ -1090,6 +1094,8 @@
cmd->tag = req->tag;
cmd->request = req;
+ cmd->cmnd = req->cmd;
+
return cmd;
}
@@ -1127,8 +1133,6 @@
req->buffer = NULL;
}
- BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
- memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd));
cmd->cmd_len = req->cmd_len;
if (!req->data_len)
cmd->sc_data_direction = DMA_NONE;
@@ -1165,6 +1169,7 @@
if (unlikely(!cmd))
return BLKPREP_DEFER;
+ memset(cmd->cmnd, 0, BLK_MAX_CDB);
return scsi_init_io(cmd, GFP_ATOMIC);
}
EXPORT_SYMBOL(scsi_setup_fs_cmnd);
@@ -1585,8 +1590,9 @@
blk_queue_max_segment_size(q, dma_get_max_seg_size(dev));
+ /* New queue, no concurrency on queue_flags */
if (!shost->use_clustering)
- clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+ queue_flag_clear_unlocked(QUEUE_FLAG_CLUSTER, q);
/*
* set a reasonable default alignment on word boundaries: the
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 3a1c99d..e4a0d2f 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -413,6 +413,7 @@
}
static const struct file_operations proc_scsi_operations = {
+ .owner = THIS_MODULE,
.open = proc_scsi_open,
.read = seq_read,
.write = proc_scsi_write,
@@ -431,10 +432,9 @@
if (!proc_scsi)
goto err1;
- pde = create_proc_entry("scsi/scsi", 0, NULL);
+ pde = proc_create("scsi/scsi", 0, NULL, &proc_scsi_operations);
if (!pde)
goto err2;
- pde->proc_fops = &proc_scsi_operations;
return 0;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index fcd7455..a00eee6 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1828,7 +1828,7 @@
}
p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no);
- if (unlikely(IS_ERR(p)))
+ if (IS_ERR(p))
do_scan_async(data);
}
EXPORT_SYMBOL(scsi_scan_host);
diff --git a/drivers/scsi/scsi_tgt_lib.c b/drivers/scsi/scsi_tgt_lib.c
index ee8496a..257e097 100644
--- a/drivers/scsi/scsi_tgt_lib.c
+++ b/drivers/scsi/scsi_tgt_lib.c
@@ -107,6 +107,8 @@
cmd->jiffies_at_alloc = jiffies;
cmd->request = rq;
+ cmd->cmnd = rq->cmd;
+
rq->special = cmd;
rq->cmd_type = REQ_TYPE_SPECIAL;
rq->cmd_flags |= REQ_TYPE_BLOCK_PC;
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c
index 7899e3d..f4461d3 100644
--- a/drivers/scsi/scsi_transport_sas.c
+++ b/drivers/scsi/scsi_transport_sas.c
@@ -248,8 +248,7 @@
else
q->queuedata = shost;
- set_bit(QUEUE_FLAG_BIDI, &q->queue_flags);
-
+ queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q);
return 0;
}
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 3cea17d..01cefbb 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -860,7 +860,6 @@
static void sd_prepare_flush(struct request_queue *q, struct request *rq)
{
- memset(rq->cmd, 0, sizeof(rq->cmd));
rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = SD_TIMEOUT;
rq->cmd[0] = SYNCHRONIZE_CACHE;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 2029422..c9d7f72 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -2667,7 +2667,6 @@
{
int k, mask;
int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr);
- struct proc_dir_entry *pdep;
struct sg_proc_leaf * leaf;
sg_proc_sgp = proc_mkdir(sg_proc_sg_dirname, NULL);
@@ -2676,13 +2675,10 @@
for (k = 0; k < num_leaves; ++k) {
leaf = &sg_proc_leaf_arr[k];
mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO;
- pdep = create_proc_entry(leaf->name, mask, sg_proc_sgp);
- if (pdep) {
- leaf->fops->owner = THIS_MODULE,
- leaf->fops->read = seq_read,
- leaf->fops->llseek = seq_lseek,
- pdep->proc_fops = leaf->fops;
- }
+ leaf->fops->owner = THIS_MODULE;
+ leaf->fops->read = seq_read;
+ leaf->fops->llseek = seq_lseek;
+ proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops);
}
return 0;
}
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 640333b..329eb87 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -744,7 +744,8 @@
static int board_inquiry(unsigned int j) {
struct mscp *cpp;
dma_addr_t id_dma_addr;
- unsigned int time, limit = 0;
+ unsigned int limit = 0;
+ unsigned long time;
id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id,
sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL);
@@ -1392,7 +1393,8 @@
}
static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
- unsigned int i, j, time, k, c, limit = 0;
+ unsigned int i, j, k, c, limit = 0;
+ unsigned long time;
int arg_done = FALSE;
struct scsi_cmnd *SCpnt;
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 2b8a410..bbf5bc5 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -200,7 +200,7 @@
local_irq_restore(flags);
}
-static void rs_put_char(char ch)
+static int rs_put_char(char ch)
{
int flags, loops = 0;
@@ -214,6 +214,7 @@
UTX_TXDATA = ch;
udelay(5);
local_irq_restore(flags);
+ return 1;
}
static void rs_start(struct tty_struct *tty)
@@ -1017,18 +1018,6 @@
tty_wait_until_sent(tty, 0);
send_break(info, arg ? arg*(100) : 250);
return 0;
- case TIOCGSOFTCAR:
- error = put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long *) arg);
- if (error)
- return error;
- return 0;
- case TIOCSSOFTCAR:
- get_user(arg, (unsigned long *) arg);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCGSERIAL:
if (access_ok(VERIFY_WRITE, (void *) arg,
sizeof(struct serial_struct)))
@@ -1061,9 +1050,6 @@
{
struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
-
change_speed(info);
if ((old_termios->c_cflag & CRTSCTS) &&
@@ -1140,8 +1126,7 @@
uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index f594636..d9d4e95 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -995,10 +995,10 @@
volatile QUICC_BD *bdp;
if (serial_paranoia_check(info, tty->name, "rs_put_char"))
- return;
+ return 0;
if (!tty)
- return;
+ return 0;
bdp = info->tx_cur;
while (bdp->status & BD_SC_READY);
@@ -1016,6 +1016,7 @@
bdp++;
info->tx_cur = (QUICC_BD *)bdp;
+ return 1;
}
@@ -1246,7 +1247,7 @@
#ifdef modem_control
unsigned char control, status;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
@@ -1277,12 +1278,12 @@
ser_info_t *info = (ser_info_t *)tty->driver_data;
unsigned int arg;
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
+ if (serial_paranoia_check(info, tty->name, __func__))
return -ENODEV;
if (tty->flags & (1 << TTY_IO_ERROR))
return -EIO;
-
+ /* FIXME: locking on info->mcr */
if (set & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
if (set & TIOCM_DTR)
@@ -1436,18 +1437,6 @@
return retval;
end_break(info);
return 0;
- case TIOCGSOFTCAR:
- /* return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); */
- put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
- return 0;
- case TIOCSSOFTCAR:
- error = get_user(arg, (unsigned int *) arg);
- if (error)
- return error;
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
#ifdef maybe
case TIOCSERGETLSR: /* Get line status register */
return get_lsr_info(info, (unsigned int *) arg);
@@ -1665,8 +1654,7 @@
rs_360_wait_until_sent(tty, info->timeout);
}
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ rs_360_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
info->event = 0;
@@ -1717,6 +1705,7 @@
printk("jiff=%lu...", jiffies);
#endif
+ lock_kernel();
/* We go through the loop at least once because we can't tell
* exactly when the last character exits the shifter. There can
* be at least two characters waiting to be sent after the buffers
@@ -1745,6 +1734,7 @@
bdp--;
} while (bdp->status & BD_SC_READY);
current->state = TASK_RUNNING;
+ unlock_kernel();
#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
#endif
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index ea41f26..a1ca9b7 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -2271,7 +2271,8 @@
}
if (up->port.flags & UPF_IOREMAP) {
- up->port.membase = ioremap(up->port.mapbase, size);
+ up->port.membase = ioremap_nocache(up->port.mapbase,
+ size);
if (!up->port.membase) {
release_mem_region(up->port.mapbase, size);
ret = -ENOMEM;
diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c
index 38776e8..f279745 100644
--- a/drivers/serial/8250_early.c
+++ b/drivers/serial/8250_early.c
@@ -153,10 +153,10 @@
(void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE);
port->membase += port->mapbase & ~PAGE_MASK;
#else
- port->membase = ioremap(port->mapbase, 64);
+ port->membase = ioremap_nocache(port->mapbase, 64);
if (!port->membase) {
printk(KERN_ERR "%s: Couldn't ioremap 0x%llx\n",
- __FUNCTION__,
+ __func__,
(unsigned long long)port->mapbase);
return -ENOMEM;
}
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 6e57382..53fa19c 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -86,7 +86,7 @@
len = pci_resource_len(dev, bar);
if (!priv->remapped_bar[bar])
- priv->remapped_bar[bar] = ioremap(base, len);
+ priv->remapped_bar[bar] = ioremap_nocache(base, len);
if (!priv->remapped_bar[bar])
return -ENOMEM;
@@ -270,7 +270,7 @@
/*
* enable/disable interrupts
*/
- p = ioremap(pci_resource_start(dev, 0), 0x80);
+ p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
if (p == NULL)
return -ENOMEM;
writel(irq_config, p + 0x4c);
@@ -294,7 +294,7 @@
/*
* disable interrupts
*/
- p = ioremap(pci_resource_start(dev, 0), 0x80);
+ p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
if (p != NULL) {
writel(0, p + 0x4c);
@@ -341,7 +341,8 @@
{
u8 __iomem *p;
- p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+ p = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
if (p == NULL)
return -ENOMEM;
@@ -365,7 +366,8 @@
{
u8 __iomem *p;
- p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0));
+ p = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
/* FIXME: What if resource_len < OCT_REG_CR_OFF */
if (p != NULL)
writeb(0, p + OCT_REG_CR_OFF);
@@ -419,7 +421,7 @@
break;
}
- p = ioremap(pci_resource_start(dev, 0), 0x80);
+ p = ioremap_nocache(pci_resource_start(dev, 0), 0x80);
if (p == NULL)
return -ENOMEM;
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 34b809e..36acbcc 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -1355,4 +1355,47 @@
help
Support for Console on SC2681/SC2692 serial ports.
+config SERIAL_BFIN_SPORT
+ tristate "Blackfin SPORT emulate UART (EXPERIMENTAL)"
+ depends on BFIN && EXPERIMENTAL
+ select SERIAL_CORE
+ help
+ Enble support SPORT emulate UART on Blackfin series.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bfin_sport_uart.
+
+choice
+ prompt "Baud rate for Blackfin SPORT UART"
+ depends on SERIAL_BFIN_SPORT
+ default SERIAL_SPORT_BAUD_RATE_57600
+ help
+ Choose a baud rate for the SPORT UART, other uart settings are
+ 8 bit, 1 stop bit, no parity, no flow control.
+
+config SERIAL_SPORT_BAUD_RATE_115200
+ bool "115200"
+
+config SERIAL_SPORT_BAUD_RATE_57600
+ bool "57600"
+
+config SERIAL_SPORT_BAUD_RATE_38400
+ bool "38400"
+
+config SERIAL_SPORT_BAUD_RATE_19200
+ bool "19200"
+
+config SERIAL_SPORT_BAUD_RATE_9600
+ bool "9600"
+endchoice
+
+config SPORT_BAUD_RATE
+ int
+ depends on SERIAL_BFIN_SPORT
+ default 115200 if (SERIAL_SPORT_BAUD_RATE_115200)
+ default 57600 if (SERIAL_SPORT_BAUD_RATE_57600)
+ default 38400 if (SERIAL_SPORT_BAUD_RATE_38400)
+ default 19200 if (SERIAL_SPORT_BAUD_RATE_19200)
+ default 9600 if (SERIAL_SPORT_BAUD_RATE_9600)
+
endmenu
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index f02ff9f..0d9c09b 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -27,6 +27,7 @@
obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o
obj-$(CONFIG_SERIAL_SA1100) += sa1100.o
obj-$(CONFIG_SERIAL_BFIN) += bfin_5xx.o
+obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o
obj-$(CONFIG_SERIAL_S3C2410) += s3c2410.o
obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o
obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o
diff --git a/drivers/serial/bfin_5xx.c b/drivers/serial/bfin_5xx.c
index 5f55534..8a2f6a1 100644
--- a/drivers/serial/bfin_5xx.c
+++ b/drivers/serial/bfin_5xx.c
@@ -762,7 +762,7 @@
break;
default:
printk(KERN_ERR "%s: word lengh not supported\n",
- __FUNCTION__);
+ __func__);
}
if (termios->c_cflag & CSTOPB)
@@ -1029,7 +1029,7 @@
*baud = get_sclk() / (16*(dll | dlh << 8));
}
- pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __FUNCTION__, *baud, *parity, *bits);
+ pr_debug("%s:baud = %d, parity = %c, bits= %d\n", __func__, *baud, *parity, *bits);
}
#endif
diff --git a/drivers/serial/bfin_sport_uart.c b/drivers/serial/bfin_sport_uart.c
new file mode 100644
index 0000000..aca1240
--- /dev/null
+++ b/drivers/serial/bfin_sport_uart.c
@@ -0,0 +1,614 @@
+/*
+ * File: linux/drivers/serial/bfin_sport_uart.c
+ *
+ * Based on: drivers/serial/bfin_5xx.c by Aubrey Li.
+ * Author: Roy Huang <roy.huang@analog.com>
+ *
+ * Created: Nov 22, 2006
+ * Copyright: (c) 2006-2007 Analog Devices Inc.
+ * Description: this driver enable SPORTs on Blackfin emulate UART.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * This driver and the hardware supported are in term of EE-191 of ADI.
+ * http://www.analog.com/UploadedFiles/Application_Notes/399447663EE191.pdf
+ * This application note describe how to implement a UART on a Sharc DSP,
+ * but this driver is implemented on Blackfin Processor.
+ */
+
+/* After reset, there is a prelude of low level pulse when transmit data first
+ * time. No addtional pulse in following transmit.
+ * According to document:
+ * The SPORTs are ready to start transmitting or receiving data no later than
+ * three serial clock cycles after they are enabled in the SPORTx_TCR1 or
+ * SPORTx_RCR1 register. No serial clock cycles are lost from this point on.
+ * The first internal frame sync will occur one frame sync delay after the
+ * SPORTs are ready. External frame syncs can occur as soon as the SPORT is
+ * ready.
+ */
+
+/* Thanks to Axel Alatalo <axel@rubico.se> for fixing sport rx bug. Sometimes
+ * sport receives data incorrectly. The following is Axel's words.
+ * As EE-191, sport rx samples 3 times of the UART baudrate and takes the
+ * middle smaple of every 3 samples as the data bit. For a 8-N-1 UART setting,
+ * 30 samples will be required for a byte. If transmitter sends a 1/3 bit short
+ * byte due to buadrate drift, then the 30th sample of a byte, this sample is
+ * also the third sample of the stop bit, will happens on the immediately
+ * following start bit which will be thrown away and missed. Thus since parts
+ * of the startbit will be missed and the receiver will begin to drift, the
+ * effect accumulates over time until synchronization is lost.
+ * If only require 2 samples of the stopbit (by sampling in total 29 samples),
+ * then a to short byte as in the case above will be tolerated. Then the 1/3
+ * early startbit will trigger a framesync since the last read is complete
+ * after only 2/3 stopbit and framesync is active during the last 1/3 looking
+ * for a possible early startbit. */
+
+//#define DEBUG
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/platform_device.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial_core.h>
+
+#include <asm/delay.h>
+#include <asm/portmux.h>
+
+#include "bfin_sport_uart.h"
+
+unsigned short bfin_uart_pin_req_sport0[] =
+ {P_SPORT0_TFS, P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, \
+ P_SPORT0_DRPRI, P_SPORT0_RSCLK, P_SPORT0_DRSEC, P_SPORT0_DTSEC, 0};
+
+unsigned short bfin_uart_pin_req_sport1[] =
+ {P_SPORT1_TFS, P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, \
+ P_SPORT1_DRPRI, P_SPORT1_RSCLK, P_SPORT1_DRSEC, P_SPORT1_DTSEC, 0};
+
+#define DRV_NAME "bfin-sport-uart"
+
+struct sport_uart_port {
+ struct uart_port port;
+ char *name;
+
+ int tx_irq;
+ int rx_irq;
+ int err_irq;
+};
+
+static void sport_uart_tx_chars(struct sport_uart_port *up);
+static void sport_stop_tx(struct uart_port *port);
+
+static inline void tx_one_byte(struct sport_uart_port *up, unsigned int value)
+{
+ pr_debug("%s value:%x\n", __FUNCTION__, value);
+ /* Place a Start and Stop bit */
+ __asm__ volatile (
+ "R2 = b#01111111100;\n\t"
+ "R3 = b#10000000001;\n\t"
+ "%0 <<= 2;\n\t"
+ "%0 = %0 & R2;\n\t"
+ "%0 = %0 | R3;\n\t"
+ :"=r"(value)
+ :"0"(value)
+ :"R2", "R3");
+ pr_debug("%s value:%x\n", __FUNCTION__, value);
+
+ SPORT_PUT_TX(up, value);
+}
+
+static inline unsigned int rx_one_byte(struct sport_uart_port *up)
+{
+ unsigned int value, extract;
+
+ value = SPORT_GET_RX32(up);
+ pr_debug("%s value:%x\n", __FUNCTION__, value);
+
+ /* Extract 8 bits data */
+ __asm__ volatile (
+ "R5 = 0;\n\t"
+ "P0 = 8;\n\t"
+ "R1 = 0x1801(Z);\n\t"
+ "R3 = 0x0300(Z);\n\t"
+ "R4 = 0;\n\t"
+ "LSETUP(loop_s, loop_e) LC0 = P0;\nloop_s:\t"
+ "R2 = extract(%1, R1.L)(Z);\n\t"
+ "R2 <<= R4;\n\t"
+ "R5 = R5 | R2;\n\t"
+ "R1 = R1 - R3;\nloop_e:\t"
+ "R4 += 1;\n\t"
+ "%0 = R5;\n\t"
+ :"=r"(extract)
+ :"r"(value)
+ :"P0", "R1", "R2","R3","R4", "R5");
+
+ pr_debug(" extract:%x\n", extract);
+ return extract;
+}
+
+static int sport_uart_setup(struct sport_uart_port *up, int sclk, int baud_rate)
+{
+ int tclkdiv, tfsdiv, rclkdiv;
+
+ /* Set TCR1 and TCR2 */
+ SPORT_PUT_TCR1(up, (LTFS | ITFS | TFSR | TLSBIT | ITCLK));
+ SPORT_PUT_TCR2(up, 10);
+ pr_debug("%s TCR1:%x, TCR2:%x\n", __FUNCTION__, SPORT_GET_TCR1(up), SPORT_GET_TCR2(up));
+
+ /* Set RCR1 and RCR2 */
+ SPORT_PUT_RCR1(up, (RCKFE | LARFS | LRFS | RFSR | IRCLK));
+ SPORT_PUT_RCR2(up, 28);
+ pr_debug("%s RCR1:%x, RCR2:%x\n", __FUNCTION__, SPORT_GET_RCR1(up), SPORT_GET_RCR2(up));
+
+ tclkdiv = sclk/(2 * baud_rate) - 1;
+ tfsdiv = 12;
+ rclkdiv = sclk/(2 * baud_rate * 3) - 1;
+ SPORT_PUT_TCLKDIV(up, tclkdiv);
+ SPORT_PUT_TFSDIV(up, tfsdiv);
+ SPORT_PUT_RCLKDIV(up, rclkdiv);
+ SSYNC();
+ pr_debug("%s sclk:%d, baud_rate:%d, tclkdiv:%d, tfsdiv:%d, rclkdiv:%d\n",
+ __FUNCTION__, sclk, baud_rate, tclkdiv, tfsdiv, rclkdiv);
+
+ return 0;
+}
+
+static irqreturn_t sport_uart_rx_irq(int irq, void *dev_id)
+{
+ struct sport_uart_port *up = dev_id;
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned int ch;
+
+ do {
+ ch = rx_one_byte(up);
+ up->port.icount.rx++;
+
+ if (uart_handle_sysrq_char(&up->port, ch))
+ ;
+ else
+ tty_insert_flip_char(tty, ch, TTY_NORMAL);
+ } while (SPORT_GET_STAT(up) & RXNE);
+ tty_flip_buffer_push(tty);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_tx_irq(int irq, void *dev_id)
+{
+ sport_uart_tx_chars(dev_id);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sport_uart_err_irq(int irq, void *dev_id)
+{
+ struct sport_uart_port *up = dev_id;
+ struct tty_struct *tty = up->port.info->tty;
+ unsigned int stat = SPORT_GET_STAT(up);
+
+ /* Overflow in RX FIFO */
+ if (stat & ROVF) {
+ up->port.icount.overrun++;
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+ SPORT_PUT_STAT(up, ROVF); /* Clear ROVF bit */
+ }
+ /* These should not happen */
+ if (stat & (TOVF | TUVF | RUVF)) {
+ printk(KERN_ERR "SPORT Error:%s %s %s\n",
+ (stat & TOVF)?"TX overflow":"",
+ (stat & TUVF)?"TX underflow":"",
+ (stat & RUVF)?"RX underflow":"");
+ SPORT_PUT_TCR1(up, SPORT_GET_TCR1(up) & ~TSPEN);
+ SPORT_PUT_RCR1(up, SPORT_GET_RCR1(up) & ~RSPEN);
+ }
+ SSYNC();
+
+ return IRQ_HANDLED;
+}
+
+/* Reqeust IRQ, Setup clock */
+static int sport_startup(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ char buffer[20];
+ int retval;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ memset(buffer, 20, '\0');
+ snprintf(buffer, 20, "%s rx", up->name);
+ retval = request_irq(up->rx_irq, sport_uart_rx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
+ if (retval) {
+ printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ return retval;
+ }
+
+ snprintf(buffer, 20, "%s tx", up->name);
+ retval = request_irq(up->tx_irq, sport_uart_tx_irq, IRQF_SAMPLE_RANDOM, buffer, up);
+ if (retval) {
+ printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ goto fail1;
+ }
+
+ snprintf(buffer, 20, "%s err", up->name);
+ retval = request_irq(up->err_irq, sport_uart_err_irq, IRQF_SAMPLE_RANDOM, buffer, up);
+ if (retval) {
+ printk(KERN_ERR "Unable to request interrupt %s\n", buffer);
+ goto fail2;
+ }
+
+ if (port->line) {
+ if (peripheral_request_list(bfin_uart_pin_req_sport1, DRV_NAME))
+ goto fail3;
+ } else {
+ if (peripheral_request_list(bfin_uart_pin_req_sport0, DRV_NAME))
+ goto fail3;
+ }
+
+ sport_uart_setup(up, get_sclk(), port->uartclk);
+
+ /* Enable receive interrupt */
+ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) | RSPEN));
+ SSYNC();
+
+ return 0;
+
+
+fail3:
+ printk(KERN_ERR DRV_NAME
+ ": Requesting Peripherals failed\n");
+
+ free_irq(up->err_irq, up);
+fail2:
+ free_irq(up->tx_irq, up);
+fail1:
+ free_irq(up->rx_irq, up);
+
+ return retval;
+
+}
+
+static void sport_uart_tx_chars(struct sport_uart_port *up)
+{
+ struct circ_buf *xmit = &up->port.info->xmit;
+
+ if (SPORT_GET_STAT(up) & TXF)
+ return;
+
+ if (up->port.x_char) {
+ tx_one_byte(up, up->port.x_char);
+ up->port.icount.tx++;
+ up->port.x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+ sport_stop_tx(&up->port);
+ return;
+ }
+
+ while(!(SPORT_GET_STAT(up) & TXF) && !uart_circ_empty(xmit)) {
+ tx_one_byte(up, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE -1);
+ up->port.icount.tx++;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&up->port);
+}
+
+static unsigned int sport_tx_empty(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ unsigned int stat;
+
+ stat = SPORT_GET_STAT(up);
+ pr_debug("%s stat:%04x\n", __FUNCTION__, stat);
+ if (stat & TXHRE) {
+ return TIOCSER_TEMT;
+ } else
+ return 0;
+}
+
+static unsigned int sport_get_mctrl(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ return (TIOCM_CTS | TIOCM_CD | TIOCM_DSR);
+}
+
+static void sport_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static void sport_stop_tx(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+ unsigned int stat;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+
+ stat = SPORT_GET_STAT(up);
+ while(!(stat & TXHRE)) {
+ udelay(1);
+ stat = SPORT_GET_STAT(up);
+ }
+ /* Although the hold register is empty, last byte is still in shift
+ * register and not sent out yet. If baud rate is lower than default,
+ * delay should be longer. For example, if the baud rate is 9600,
+ * the delay must be at least 2ms by experience */
+ udelay(500);
+
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+ SSYNC();
+
+ return;
+}
+
+static void sport_start_tx(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ /* Write data into SPORT FIFO before enable SPROT to transmit */
+ sport_uart_tx_chars(up);
+
+ /* Enable transmit, then an interrupt will generated */
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) | TSPEN));
+ SSYNC();
+ pr_debug("%s exit\n", __FUNCTION__);
+}
+
+static void sport_stop_rx(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ /* Disable sport to stop rx */
+ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+ SSYNC();
+}
+
+static void sport_enable_ms(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static void sport_break_ctl(struct uart_port *port, int break_state)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static void sport_shutdown(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+
+ /* Disable sport */
+ SPORT_PUT_TCR1(up, (SPORT_GET_TCR1(up) & ~TSPEN));
+ SPORT_PUT_RCR1(up, (SPORT_GET_RCR1(up) & ~RSPEN));
+ SSYNC();
+
+ if (port->line) {
+ peripheral_free_list(bfin_uart_pin_req_sport1);
+ } else {
+ peripheral_free_list(bfin_uart_pin_req_sport0);
+ }
+
+ free_irq(up->rx_irq, up);
+ free_irq(up->tx_irq, up);
+ free_irq(up->err_irq, up);
+}
+
+static void sport_set_termios(struct uart_port *port,
+ struct termios *termios, struct termios *old)
+{
+ pr_debug("%s enter, c_cflag:%08x\n", __FUNCTION__, termios->c_cflag);
+ uart_update_timeout(port, CS8 ,port->uartclk);
+}
+
+static const char *sport_type(struct uart_port *port)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ return up->name;
+}
+
+static void sport_release_port(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+}
+
+static int sport_request_port(struct uart_port *port)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ return 0;
+}
+
+static void sport_config_port(struct uart_port *port, int flags)
+{
+ struct sport_uart_port *up = (struct sport_uart_port *)port;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ up->port.type = PORT_BFIN_SPORT;
+}
+
+static int sport_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ return 0;
+}
+
+struct uart_ops sport_uart_ops = {
+ .tx_empty = sport_tx_empty,
+ .set_mctrl = sport_set_mctrl,
+ .get_mctrl = sport_get_mctrl,
+ .stop_tx = sport_stop_tx,
+ .start_tx = sport_start_tx,
+ .stop_rx = sport_stop_rx,
+ .enable_ms = sport_enable_ms,
+ .break_ctl = sport_break_ctl,
+ .startup = sport_startup,
+ .shutdown = sport_shutdown,
+ .set_termios = sport_set_termios,
+ .type = sport_type,
+ .release_port = sport_release_port,
+ .request_port = sport_request_port,
+ .config_port = sport_config_port,
+ .verify_port = sport_verify_port,
+};
+
+static struct sport_uart_port sport_uart_ports[] = {
+ { /* SPORT 0 */
+ .name = "SPORT0",
+ .tx_irq = IRQ_SPORT0_TX,
+ .rx_irq = IRQ_SPORT0_RX,
+ .err_irq= IRQ_SPORT0_ERROR,
+ .port = {
+ .type = PORT_BFIN_SPORT,
+ .iotype = UPIO_MEM,
+ .membase = (void __iomem *)SPORT0_TCR1,
+ .mapbase = SPORT0_TCR1,
+ .irq = IRQ_SPORT0_RX,
+ .uartclk = CONFIG_SPORT_BAUD_RATE,
+ .fifosize = 8,
+ .ops = &sport_uart_ops,
+ .line = 0,
+ },
+ }, { /* SPORT 1 */
+ .name = "SPORT1",
+ .tx_irq = IRQ_SPORT1_TX,
+ .rx_irq = IRQ_SPORT1_RX,
+ .err_irq= IRQ_SPORT1_ERROR,
+ .port = {
+ .type = PORT_BFIN_SPORT,
+ .iotype = UPIO_MEM,
+ .membase = (void __iomem *)SPORT1_TCR1,
+ .mapbase = SPORT1_TCR1,
+ .irq = IRQ_SPORT1_RX,
+ .uartclk = CONFIG_SPORT_BAUD_RATE,
+ .fifosize = 8,
+ .ops = &sport_uart_ops,
+ .line = 1,
+ },
+ }
+};
+
+static struct uart_driver sport_uart_reg = {
+ .owner = THIS_MODULE,
+ .driver_name = "SPORT-UART",
+ .dev_name = "ttySS",
+ .major = 204,
+ .minor = 84,
+ .nr = ARRAY_SIZE(sport_uart_ports),
+ .cons = NULL,
+};
+
+static int sport_uart_suspend(struct platform_device *dev, pm_message_t state)
+{
+ struct sport_uart_port *sport = platform_get_drvdata(dev);
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ if (sport)
+ uart_suspend_port(&sport_uart_reg, &sport->port);
+
+ return 0;
+}
+
+static int sport_uart_resume(struct platform_device *dev)
+{
+ struct sport_uart_port *sport = platform_get_drvdata(dev);
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ if (sport)
+ uart_resume_port(&sport_uart_reg, &sport->port);
+
+ return 0;
+}
+
+static int sport_uart_probe(struct platform_device *dev)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ sport_uart_ports[dev->id].port.dev = &dev->dev;
+ uart_add_one_port(&sport_uart_reg, &sport_uart_ports[dev->id].port);
+ platform_set_drvdata(dev, &sport_uart_ports[dev->id]);
+
+ return 0;
+}
+
+static int sport_uart_remove(struct platform_device *dev)
+{
+ struct sport_uart_port *sport = platform_get_drvdata(dev);
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ platform_set_drvdata(dev, NULL);
+
+ if (sport)
+ uart_remove_one_port(&sport_uart_reg, &sport->port);
+
+ return 0;
+}
+
+static struct platform_driver sport_uart_driver = {
+ .probe = sport_uart_probe,
+ .remove = sport_uart_remove,
+ .suspend = sport_uart_suspend,
+ .resume = sport_uart_resume,
+ .driver = {
+ .name = DRV_NAME,
+ },
+};
+
+static int __init sport_uart_init(void)
+{
+ int ret;
+
+ pr_debug("%s enter\n", __FUNCTION__);
+ ret = uart_register_driver(&sport_uart_reg);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register %s:%d\n",
+ sport_uart_reg.driver_name, ret);
+ return ret;
+ }
+
+ ret = platform_driver_register(&sport_uart_driver);
+ if (ret != 0) {
+ printk(KERN_ERR "Failed to register sport uart driver:%d\n", ret);
+ uart_unregister_driver(&sport_uart_reg);
+ }
+
+
+ pr_debug("%s exit\n", __FUNCTION__);
+ return ret;
+}
+
+static void __exit sport_uart_exit(void)
+{
+ pr_debug("%s enter\n", __FUNCTION__);
+ platform_driver_unregister(&sport_uart_driver);
+ uart_unregister_driver(&sport_uart_reg);
+}
+
+module_init(sport_uart_init);
+module_exit(sport_uart_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/bfin_sport_uart.h b/drivers/serial/bfin_sport_uart.h
new file mode 100644
index 0000000..671d41c
--- /dev/null
+++ b/drivers/serial/bfin_sport_uart.h
@@ -0,0 +1,63 @@
+/*
+ * File: linux/drivers/serial/bfin_sport_uart.h
+ *
+ * Based on: include/asm-blackfin/mach-533/bfin_serial_5xx.h
+ * Author: Roy Huang <roy.huang>analog.com>
+ *
+ * Created: Nov 22, 2006
+ * Copyright: (C) Analog Device Inc.
+ * Description: this driver enable SPORTs on Blackfin emulate UART.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the 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, see the file COPYING, or write
+ * to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#define OFFSET_TCR1 0x00 /* Transmit Configuration 1 Register */
+#define OFFSET_TCR2 0x04 /* Transmit Configuration 2 Register */
+#define OFFSET_TCLKDIV 0x08 /* Transmit Serial Clock Divider Register */
+#define OFFSET_TFSDIV 0x0C /* Transmit Frame Sync Divider Register */
+#define OFFSET_TX 0x10 /* Transmit Data Register */
+#define OFFSET_RX 0x18 /* Receive Data Register */
+#define OFFSET_RCR1 0x20 /* Receive Configuration 1 Register */
+#define OFFSET_RCR2 0x24 /* Receive Configuration 2 Register */
+#define OFFSET_RCLKDIV 0x28 /* Receive Serial Clock Divider Register */
+#define OFFSET_RFSDIV 0x2c /* Receive Frame Sync Divider Register */
+#define OFFSET_STAT 0x30 /* Status Register */
+
+#define SPORT_GET_TCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR1))
+#define SPORT_GET_TCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_TCR2))
+#define SPORT_GET_TCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TCLKDIV))
+#define SPORT_GET_TFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_TFSDIV))
+#define SPORT_GET_TX(sport) bfin_read16(((sport)->port.membase + OFFSET_TX))
+#define SPORT_GET_RX(sport) bfin_read16(((sport)->port.membase + OFFSET_RX))
+#define SPORT_GET_RX32(sport) bfin_read32(((sport)->port.membase + OFFSET_RX))
+#define SPORT_GET_RCR1(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR1))
+#define SPORT_GET_RCR2(sport) bfin_read16(((sport)->port.membase + OFFSET_RCR2))
+#define SPORT_GET_RCLKDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RCLKDIV))
+#define SPORT_GET_RFSDIV(sport) bfin_read16(((sport)->port.membase + OFFSET_RFSDIV))
+#define SPORT_GET_STAT(sport) bfin_read16(((sport)->port.membase + OFFSET_STAT))
+
+#define SPORT_PUT_TCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR1), v)
+#define SPORT_PUT_TCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCR2), v)
+#define SPORT_PUT_TCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TCLKDIV), v)
+#define SPORT_PUT_TFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TFSDIV), v)
+#define SPORT_PUT_TX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_TX), v)
+#define SPORT_PUT_RX(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RX), v)
+#define SPORT_PUT_RCR1(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR1), v)
+#define SPORT_PUT_RCR2(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCR2), v)
+#define SPORT_PUT_RCLKDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RCLKDIV), v)
+#define SPORT_PUT_RFSDIV(sport, v) bfin_write16(((sport)->port.membase + OFFSET_RFSDIV), v)
+#define SPORT_PUT_STAT(sport, v) bfin_write16(((sport)->port.membase + OFFSET_STAT), v)
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index a638ba0..a19dc7e 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -1117,7 +1117,7 @@
line = cpm_uart_id2nr(idx);
if(line < 0) {
- printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx);
+ printk(KERN_ERR"%s(): port %d is not registered", __func__, idx);
return -EINVAL;
}
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index 88e7c1d..f9fa237 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -1788,7 +1788,7 @@
if (info->recv_cnt + recvl > 65536) {
printk(KERN_CRIT
- "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __FUNCTION__, recvl);
+ "%s: Too much pending incoming serial data! Dropping %u bytes.\n", __func__, recvl);
return 0;
}
@@ -1801,7 +1801,7 @@
append_recv_buffer(info, buffer);
if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
- panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr->buf = virt_to_phys(buffer->buffer);
@@ -1925,7 +1925,7 @@
/* Set up the receiving descriptors */
for (i = 0; i < SERIAL_RECV_DESCRIPTORS; i++) {
if (!(buffer = alloc_recv_buffer(SERIAL_DESCR_BUF_SIZE)))
- panic("%s: Failed to allocate memory for receive buffer!\n", __FUNCTION__);
+ panic("%s: Failed to allocate memory for receive buffer!\n", __func__);
descr[i].ctrl = d_int;
descr[i].buf = virt_to_phys(buffer->buffer);
@@ -3581,8 +3581,9 @@
unsigned int set, unsigned int clear)
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
+ unsigned long flags;
- lock_kernel();
+ local_irq_save(flags);
if (clear & TIOCM_RTS)
e100_rts(info, 0);
@@ -3604,7 +3605,7 @@
if (set & TIOCM_CD)
e100_cd_out(info, 1);
- unlock_kernel();
+ local_irq_restore(flags);
return 0;
}
@@ -3613,8 +3614,10 @@
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
unsigned int result;
+ unsigned long flags;
- lock_kernel();
+ local_irq_save(flags);
+
result =
(!E100_RTS_GET(info) ? TIOCM_RTS : 0)
| (!E100_DTR_GET(info) ? TIOCM_DTR : 0)
@@ -3623,7 +3626,7 @@
| (!E100_CD_GET(info) ? TIOCM_CAR : 0)
| (!E100_CTS_GET(info) ? TIOCM_CTS : 0);
- unlock_kernel();
+ local_irq_restore(flags);
#ifdef SERIAL_DEBUG_IO
printk(KERN_DEBUG "ser%i: modem state: %i 0x%08X\n",
@@ -3702,10 +3705,6 @@
{
struct e100_serial *info = (struct e100_serial *)tty->driver_data;
- if (tty->termios->c_cflag == old_termios->c_cflag &&
- tty->termios->c_iflag == old_termios->c_iflag)
- return;
-
change_speed(info);
/* Handle turning off CRTSCTS */
@@ -3808,10 +3807,8 @@
#endif
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
+ rs_flush_buffer(tty);
+ tty_ldisc_flush_buffer(tty);
tty->closing = 0;
info->event = 0;
info->tty = 0;
@@ -3885,6 +3882,7 @@
* Check R_DMA_CHx_STATUS bit 0-6=number of available bytes in FIFO
* R_DMA_CHx_HWSW bit 31-16=nbr of bytes left in DMA buffer (0=64k)
*/
+ lock_kernel();
orig_jiffies = jiffies;
while (info->xmit.head != info->xmit.tail || /* More in send queue */
(*info->ostatusadr & 0x007f) || /* more in FIFO */
@@ -3901,6 +3899,7 @@
curr_time_usec - info->last_tx_active_usec;
}
set_current_state(TASK_RUNNING);
+ unlock_kernel();
}
/*
@@ -4520,7 +4519,7 @@
if (request_irq(SERIAL_IRQ_NBR, ser_interrupt,
IRQF_SHARED | IRQF_DISABLED, "serial ", driver))
- panic("%s: Failed to request irq8", __FUNCTION__);
+ panic("%s: Failed to request irq8", __func__);
#endif
#endif /* CONFIG_SVINTO_SIM */
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
index 168073f..4f1af71 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/serial/ioc3_serial.c
@@ -52,7 +52,7 @@
#define DPRINT_CONFIG(_x...) ;
//#define DPRINT_CONFIG(_x...) printk _x
#define NOT_PROGRESS() ;
-//#define NOT_PROGRESS() printk("%s : fails %d\n", __FUNCTION__, __LINE__)
+//#define NOT_PROGRESS() printk("%s : fails %d\n", __func__, __LINE__)
/* number of characters we want to transmit to the lower level at a time */
#define MAX_CHARS 256
@@ -445,7 +445,7 @@
sbbr_h = &idd->vma->sbbr_h;
ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
DPRINT_CONFIG(("%s: ring_pci_addr 0x%p\n",
- __FUNCTION__, (void *)ring_pci_addr));
+ __func__, (void *)ring_pci_addr));
writel((unsigned int)((uint64_t) ring_pci_addr >> 32), sbbr_h);
writel((unsigned int)ring_pci_addr | BUF_SIZE_BIT, sbbr_l);
@@ -593,7 +593,7 @@
DPRINT_CONFIG(("%s: line %d baud %d byte_size %d stop %d parenb %d "
"parodd %d\n",
- __FUNCTION__, ((struct uart_port *)port->ip_port)->line,
+ __func__, ((struct uart_port *)port->ip_port)->line,
baud, byte_size, stop_bits, parenb, parodd));
if (set_baud(port, baud))
@@ -871,14 +871,14 @@
default:
case PROTO_RS232:
/* Clear the appropriate GIO pin */
- DPRINT_CONFIG(("%s: rs232\n", __FUNCTION__));
+ DPRINT_CONFIG(("%s: rs232\n", __func__));
writel(0, (&port->ip_idd->vma->gppr[0]
+ hooks->rs422_select_pin));
break;
case PROTO_RS422:
/* Set the appropriate GIO pin */
- DPRINT_CONFIG(("%s: rs422\n", __FUNCTION__));
+ DPRINT_CONFIG(("%s: rs422\n", __func__));
writel(1, (&port->ip_idd->vma->gppr[0]
+ hooks->rs422_select_pin));
break;
@@ -988,7 +988,7 @@
}
baud = uart_get_baud_rate(the_port, new_termios, old_termios,
MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
- DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __FUNCTION__, baud,
+ DPRINT_CONFIG(("%s: returned baud %d for line %d\n", __func__, baud,
the_port->line));
if (!the_port->fifosize)
@@ -1026,7 +1026,7 @@
DPRINT_CONFIG(("%s : port 0x%p line %d cflag 0%o "
"config_port(baud %d data %d stop %d penable %d "
" parity %d), notification 0x%x\n",
- __FUNCTION__, (void *)port, the_port->line, cflag, baud,
+ __func__, (void *)port, the_port->line, cflag, baud,
new_data, new_stop, new_parity_enable, new_parity,
the_port->ignore_status_mask));
@@ -1919,7 +1919,7 @@
struct pci_dev *pdev = idd->pdev;
DPRINT_CONFIG(("%s: attach pdev 0x%p - card_ptr 0x%p\n",
- __FUNCTION__, pdev, (void *)card_ptr));
+ __func__, pdev, (void *)card_ptr));
if (!card_ptr)
return -ENODEV;
@@ -1933,7 +1933,7 @@
port->ip_port = the_port;
DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p [%d/%d]\n",
- __FUNCTION__, (void *)the_port, (void *)port,
+ __func__, (void *)the_port, (void *)port,
phys_port, ii));
/* membase, iobase and mapbase just need to be non-0 */
@@ -1950,7 +1950,7 @@
if (uart_add_one_port(&ioc3_uart, the_port) < 0) {
printk(KERN_WARNING
"%s: unable to add port %d bus %d\n",
- __FUNCTION__, the_port->line, pdev->bus->number);
+ __func__, the_port->line, pdev->bus->number);
} else {
DPRINT_CONFIG(("IOC3 serial port %d irq %d bus %d\n",
the_port->line, the_port->irq, pdev->bus->number));
@@ -2017,7 +2017,7 @@
struct ioc3_port *ports[PORTS_PER_CARD];
int phys_port;
- DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, is, idd));
+ DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, is, idd));
card_ptr = kzalloc(sizeof(struct ioc3_card), GFP_KERNEL);
if (!card_ptr) {
@@ -2067,7 +2067,7 @@
DPRINT_CONFIG(("%s : Port A ip_serial_regs 0x%p "
"ip_uart_regs 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_serial_regs,
(void *)port->ip_uart_regs));
@@ -2082,7 +2082,7 @@
DPRINT_CONFIG(("%s : Port A ip_cpu_ringbuf 0x%p "
"ip_dma_ringbuf 0x%p, ip_inring 0x%p "
"ip_outring 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_cpu_ringbuf,
(void *)port->ip_dma_ringbuf,
(void *)port->ip_inring,
@@ -2094,7 +2094,7 @@
DPRINT_CONFIG(("%s : Port B ip_serial_regs 0x%p "
"ip_uart_regs 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_serial_regs,
(void *)port->ip_uart_regs));
@@ -2108,7 +2108,7 @@
DPRINT_CONFIG(("%s : Port B ip_cpu_ringbuf 0x%p "
"ip_dma_ringbuf 0x%p, ip_inring 0x%p "
"ip_outring 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_cpu_ringbuf,
(void *)port->ip_dma_ringbuf,
(void *)port->ip_inring,
@@ -2116,7 +2116,7 @@
}
DPRINT_CONFIG(("%s : port %d [addr 0x%p] card_ptr 0x%p",
- __FUNCTION__,
+ __func__,
phys_port, (void *)port, (void *)card_ptr));
DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
(void *)port->ip_serial_regs,
@@ -2127,7 +2127,7 @@
DPRINT_CONFIG(("%s: phys_port %d port 0x%p inring 0x%p "
"outring 0x%p\n",
- __FUNCTION__,
+ __func__,
phys_port, (void *)port,
(void *)port->ip_inring,
(void *)port->ip_outring));
@@ -2170,7 +2170,7 @@
if ((ret = uart_register_driver(&ioc3_uart)) < 0) {
printk(KERN_WARNING
"%s: Couldn't register IOC3 uart serial driver\n",
- __FUNCTION__);
+ __func__);
return ret;
}
ret = ioc3_register_submodule(&ioc3uart_submodule);
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index 0c17938..49b8a82 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -889,7 +889,7 @@
ring_pci_addr = (unsigned long __iomem)port->ip_dma_ringbuf;
DPRINT_CONFIG(("%s: ring_pci_addr 0x%lx\n",
- __FUNCTION__, ring_pci_addr));
+ __func__, ring_pci_addr));
writel((unsigned int)((uint64_t)ring_pci_addr >> 32), sbbr_h);
writel((unsigned int)ring_pci_addr | IOC4_BUF_SIZE_BIT, sbbr_l);
@@ -1028,7 +1028,7 @@
spin_lock_irqsave(&soft->is_ir_lock, flag);
printk ("%s : %d : mem 0x%p sio_ir 0x%x sio_ies 0x%x "
"other_ir 0x%x other_ies 0x%x mask 0x%x\n",
- __FUNCTION__, __LINE__,
+ __func__, __LINE__,
(void *)mem, readl(&mem->sio_ir.raw),
readl(&mem->sio_ies.raw),
readl(&mem->other_ir.raw),
@@ -1155,14 +1155,14 @@
(TOTAL_RING_BUF_SIZE - 1)) == 0));
DPRINT_CONFIG(("%s : ip_cpu_ringbuf 0x%p "
"ip_dma_ringbuf 0x%p\n",
- __FUNCTION__,
+ __func__,
(void *)port->ip_cpu_ringbuf,
(void *)port->ip_dma_ringbuf));
port->ip_inring = RING(port, RX_0_OR_2);
port->ip_outring = RING(port, TX_0_OR_2);
}
DPRINT_CONFIG(("%s : port %d [addr 0x%p] control 0x%p",
- __FUNCTION__,
+ __func__,
port_number, (void *)port, (void *)control));
DPRINT_CONFIG((" ip_serial_regs 0x%p ip_uart_regs 0x%p\n",
(void *)port->ip_serial_regs,
@@ -1173,7 +1173,7 @@
DPRINT_CONFIG(("%s: port_number %d port 0x%p inring 0x%p "
"outring 0x%p\n",
- __FUNCTION__,
+ __func__,
port_number, (void *)port,
(void *)port->ip_inring,
(void *)port->ip_outring));
@@ -1317,7 +1317,7 @@
int spiniter = 0;
DPRINT_CONFIG(("%s: baud %d byte_size %d stop %d parenb %d parodd %d\n",
- __FUNCTION__, baud, byte_size, stop_bits, parenb, parodd));
+ __func__, baud, byte_size, stop_bits, parenb, parodd));
if (set_baud(port, baud))
return 1;
@@ -1725,7 +1725,7 @@
}
baud = uart_get_baud_rate(the_port, new_termios, old_termios,
MIN_BAUD_SUPPORTED, MAX_BAUD_SUPPORTED);
- DPRINT_CONFIG(("%s: returned baud %d\n", __FUNCTION__, baud));
+ DPRINT_CONFIG(("%s: returned baud %d\n", __func__, baud));
/* default is 9600 */
if (!baud)
@@ -1765,7 +1765,7 @@
DPRINT_CONFIG(("%s : port 0x%p cflag 0%o "
"config_port(baud %d data %d stop %d p enable %d parity %d),"
" notification 0x%x\n",
- __FUNCTION__, (void *)port, cflag, baud, new_data, new_stop,
+ __func__, (void *)port, cflag, baud, new_data, new_stop,
new_parity_enable, new_parity, the_port->ignore_status_mask));
if ((config_port(port, baud, /* baud */
@@ -2715,7 +2715,7 @@
DPRINT_CONFIG(("%s: attach pdev 0x%p - control 0x%p\n",
- __FUNCTION__, pdev, (void *)control));
+ __func__, pdev, (void *)control));
if (!control)
return -ENODEV;
@@ -2734,7 +2734,7 @@
port->ip_all_ports[port_type_idx] = the_port;
DPRINT_CONFIG(("%s: attach the_port 0x%p / port 0x%p : type %s\n",
- __FUNCTION__, (void *)the_port,
+ __func__, (void *)the_port,
(void *)port,
port_type == PROTO_RS232 ? "rs232" : "rs422"));
@@ -2752,7 +2752,7 @@
if (uart_add_one_port(u_driver, the_port) < 0) {
printk(KERN_WARNING
"%s: unable to add port %d bus %d\n",
- __FUNCTION__, the_port->line, pdev->bus->number);
+ __func__, the_port->line, pdev->bus->number);
} else {
DPRINT_CONFIG(
("IOC4 serial port %d irq = %d, bus %d\n",
@@ -2777,7 +2777,7 @@
int ret = 0;
- DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __FUNCTION__, idd->idd_pdev,
+ DPRINT_CONFIG(("%s (0x%p, 0x%p)\n", __func__, idd->idd_pdev,
idd->idd_pci_id));
/* PCI-RT does not bring out serial connections.
@@ -2806,7 +2806,7 @@
goto out2;
}
DPRINT_CONFIG(("%s : mem 0x%p, serial 0x%p\n",
- __FUNCTION__, (void *)idd->idd_misc_regs,
+ __func__, (void *)idd->idd_misc_regs,
(void *)serial));
/* Get memory for the new card */
@@ -2858,7 +2858,7 @@
} else {
printk(KERN_WARNING
"%s : request_irq fails for IRQ 0x%x\n ",
- __FUNCTION__, idd->idd_pdev->irq);
+ __func__, idd->idd_pdev->irq);
}
ret = ioc4_attach_local(idd);
if (ret)
@@ -2911,13 +2911,13 @@
if ((ret = uart_register_driver(&ioc4_uart_rs232)) < 0) {
printk(KERN_WARNING
"%s: Couldn't register rs232 IOC4 serial driver\n",
- __FUNCTION__);
+ __func__);
return ret;
}
if ((ret = uart_register_driver(&ioc4_uart_rs422)) < 0) {
printk(KERN_WARNING
"%s: Couldn't register rs422 IOC4 serial driver\n",
- __FUNCTION__);
+ __func__);
return ret;
}
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
index 12c934a..8871aaa 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/serial/jsm/jsm.h
@@ -373,6 +373,7 @@
#define PCI_DEVICE_NEO_2DB9PRI_PCI_NAME "Neo 2 - DB9 Universal PCI - Powered Ring Indicator"
#define PCI_DEVICE_NEO_2RJ45_PCI_NAME "Neo 2 - RJ45 Universal PCI"
#define PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME "Neo 2 - RJ45 Universal PCI - Powered Ring Indicator"
+#define PCIE_DEVICE_NEO_IBM_PCI_NAME "Neo 4 - PCI Express - IBM"
/*
* Our Global Variables.
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index 6767ee3..338cf8a 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -82,7 +82,10 @@
/* store the info for the board we've found */
brd->boardnum = adapter_count++;
brd->pci_dev = pdev;
- brd->maxports = 2;
+ if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
+ brd->maxports = 4;
+ else
+ brd->maxports = 2;
spin_lock_init(&brd->bd_lock);
spin_lock_init(&brd->bd_intr_lock);
@@ -208,6 +211,7 @@
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
{ PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
diff --git a/drivers/serial/kgdboc.c b/drivers/serial/kgdboc.c
index 9cf0332..eadc1ab 100644
--- a/drivers/serial/kgdboc.c
+++ b/drivers/serial/kgdboc.c
@@ -96,12 +96,14 @@
static int kgdboc_get_char(void)
{
- return kgdb_tty_driver->poll_get_char(kgdb_tty_driver, kgdb_tty_line);
+ return kgdb_tty_driver->ops->poll_get_char(kgdb_tty_driver,
+ kgdb_tty_line);
}
static void kgdboc_put_char(u8 chr)
{
- kgdb_tty_driver->poll_put_char(kgdb_tty_driver, kgdb_tty_line, chr);
+ kgdb_tty_driver->ops->poll_put_char(kgdb_tty_driver,
+ kgdb_tty_line, chr);
}
static int param_set_kgdboc_var(const char *kmessage, struct kernel_param *kp)
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index ddd3aa5..43af40d 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -1072,18 +1072,6 @@
tty_wait_until_sent(tty, 0);
send_break(info, arg ? arg*(HZ/10) : HZ/4);
return 0;
- case TIOCGSOFTCAR:
- error = put_user(C_CLOCAL(tty) ? 1 : 0,
- (unsigned long *) arg);
- if (error)
- return error;
- return 0;
- case TIOCSSOFTCAR:
- get_user(arg, (unsigned long *) arg);
- tty->termios->c_cflag =
- ((tty->termios->c_cflag & ~CLOCAL) |
- (arg ? CLOCAL : 0));
- return 0;
case TIOCGSERIAL:
if (access_ok(VERIFY_WRITE, (void *) arg,
sizeof(struct serial_struct)))
@@ -1222,8 +1210,7 @@
} else
#endif
shutdown(info);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ mcfrs_flush_buffer(tty);
tty_ldisc_flush(tty);
tty->closing = 0;
@@ -1276,6 +1263,8 @@
* Note: we have to use pretty tight timings here to satisfy
* the NIST-PCTS.
*/
+ lock_kernel();
+
fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
char_time = fifo_time / 5;
if (char_time == 0)
@@ -1312,6 +1301,7 @@
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
+ unlock_kernel();
#else
/*
* For the other coldfire models, assume all data has been sent
@@ -1907,7 +1897,7 @@
* This is used for console output.
*/
-void mcfrs_put_char(char ch)
+int mcfrs_put_char(char ch)
{
volatile unsigned char *uartp;
unsigned long flags;
@@ -1931,7 +1921,7 @@
mcfrs_init_console(); /* try and get it back */
local_irq_restore(flags);
- return;
+ return 1;
}
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
index 3123ffe..81ac9bb 100644
--- a/drivers/serial/netx-serial.c
+++ b/drivers/serial/netx-serial.c
@@ -287,6 +287,7 @@
{
unsigned int val;
+ /* FIXME: Locking needed ? */
if (mctrl & TIOCM_RTS) {
val = readl(port->membase + UART_RTS_CR);
writel(val | RTS_CR_RTS, port->membase + UART_RTS_CR);
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 4ffa258..2b6a013 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -1022,6 +1022,7 @@
struct uart_port *port = &ourport->port;
struct s3c2410_uartcfg *cfg;
struct resource *res;
+ int ret;
dbg("s3c24xx_serial_init_port: port=%p, platdev=%p\n", port, platdev);
@@ -1064,9 +1065,11 @@
port->mapbase = res->start;
port->membase = S3C24XX_VA_UART + (res->start - S3C24XX_PA_UART);
- port->irq = platform_get_irq(platdev, 0);
- if (port->irq < 0)
+ ret = platform_get_irq(platdev, 0);
+ if (ret < 0)
port->irq = 0;
+ else
+ port->irq = ret;
ourport->clk = clk_get(&platdev->dev, "uart");
@@ -1093,13 +1096,13 @@
ourport = &s3c24xx_serial_ports[probe_index];
probe_index++;
- dbg("%s: initialising port %p...\n", __FUNCTION__, ourport);
+ dbg("%s: initialising port %p...\n", __func__, ourport);
ret = s3c24xx_serial_init_port(ourport, info, dev);
if (ret < 0)
goto probe_err;
- dbg("%s: adding port\n", __FUNCTION__);
+ dbg("%s: adding port\n", __func__);
uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
platform_set_drvdata(dev, &ourport->port);
@@ -1584,7 +1587,7 @@
unsigned long ucon = rd_regl(port, S3C2410_UCON);
dbg("%s: port=%p (%08lx), cfg=%p\n",
- __FUNCTION__, port, port->mapbase, cfg);
+ __func__, port, port->mapbase, cfg);
/* ensure we don't change the clock settings... */
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index 67b23389..62b3858 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -655,7 +655,7 @@
void __init sa1100_register_uart(int idx, int port)
{
if (idx >= NR_PORTS) {
- printk(KERN_ERR "%s: bad index number %d\n", __FUNCTION__, idx);
+ printk(KERN_ERR "%s: bad index number %d\n", __func__, idx);
return;
}
@@ -682,7 +682,7 @@
break;
default:
- printk(KERN_ERR "%s: bad port number %d\n", __FUNCTION__, port);
+ printk(KERN_ERR "%s: bad port number %d\n", __func__, port);
}
}
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 977ce82..1e2b9d8 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -422,6 +422,7 @@
EXPORT_SYMBOL(uart_get_divisor);
+/* FIXME: Consistent locking policy */
static void
uart_change_speed(struct uart_state *state, struct ktermios *old_termios)
{
@@ -454,27 +455,30 @@
port->ops->set_termios(port, termios, old_termios);
}
-static inline void
+static inline int
__uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c)
{
unsigned long flags;
+ int ret = 0;
if (!circ->buf)
- return;
+ return 0;
spin_lock_irqsave(&port->lock, flags);
if (uart_circ_chars_free(circ) != 0) {
circ->buf[circ->head] = c;
circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1);
+ ret = 1;
}
spin_unlock_irqrestore(&port->lock, flags);
+ return ret;
}
-static void uart_put_char(struct tty_struct *tty, unsigned char ch)
+static int uart_put_char(struct tty_struct *tty, unsigned char ch)
{
struct uart_state *state = tty->driver_data;
- __uart_put_char(state->port, &state->info->xmit, ch);
+ return __uart_put_char(state->port, &state->info->xmit, ch);
}
static void uart_flush_chars(struct tty_struct *tty)
@@ -528,15 +532,25 @@
static int uart_write_room(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ unsigned long flags;
+ int ret;
- return uart_circ_chars_free(&state->info->xmit);
+ spin_lock_irqsave(&state->port->lock, flags);
+ ret = uart_circ_chars_free(&state->info->xmit);
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ return ret;
}
static int uart_chars_in_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
+ unsigned long flags;
+ int ret;
- return uart_circ_chars_pending(&state->info->xmit);
+ spin_lock_irqsave(&state->port->lock, flags);
+ ret = uart_circ_chars_pending(&state->info->xmit);
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ return ret;
}
static void uart_flush_buffer(struct tty_struct *tty)
@@ -618,6 +632,11 @@
struct serial_struct tmp;
memset(&tmp, 0, sizeof(tmp));
+
+ /* Ensure the state we copy is consistent and no hardware changes
+ occur as we go */
+ mutex_lock(&state->mutex);
+
tmp.type = port->type;
tmp.line = port->line;
tmp.port = port->iobase;
@@ -637,6 +656,8 @@
tmp.iomem_reg_shift = port->regshift;
tmp.iomem_base = (void *)(unsigned long)port->mapbase;
+ mutex_unlock(&state->mutex);
+
if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
return -EFAULT;
return 0;
@@ -914,8 +935,6 @@
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->port;
- BUG_ON(!kernel_locked());
-
mutex_lock(&state->mutex);
if (port->type != PORT_UNKNOWN)
@@ -1059,7 +1078,7 @@
}
/*
- * Called via sys_ioctl under the BKL. We can use spin_lock_irq() here.
+ * Called via sys_ioctl. We can use spin_lock_irq() here.
*/
static int
uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd,
@@ -1069,7 +1088,6 @@
void __user *uarg = (void __user *)arg;
int ret = -ENOIOCTLCMD;
- BUG_ON(!kernel_locked());
/*
* These ioctls don't rely on the hardware to be present.
@@ -1140,9 +1158,9 @@
break;
}
}
- out_up:
+out_up:
mutex_unlock(&state->mutex);
- out:
+out:
return ret;
}
@@ -1153,7 +1171,6 @@
unsigned long flags;
unsigned int cflag = tty->termios->c_cflag;
- BUG_ON(!kernel_locked());
/*
* These are the bits that are used to setup various
@@ -1165,8 +1182,9 @@
if ((cflag ^ old_termios->c_cflag) == 0 &&
tty->termios->c_ospeed == old_termios->c_ospeed &&
tty->termios->c_ispeed == old_termios->c_ispeed &&
- RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0)
+ RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) {
return;
+ }
uart_change_speed(state, old_termios);
@@ -1200,7 +1218,6 @@
}
spin_unlock_irqrestore(&state->port->lock, flags);
}
-
#if 0
/*
* No need to wake up processes in open wait, since they
@@ -1316,11 +1333,11 @@
struct uart_port *port = state->port;
unsigned long char_time, expire;
- BUG_ON(!kernel_locked());
-
if (port->type == PORT_UNKNOWN || port->fifosize == 0)
return;
+ lock_kernel();
+
/*
* Set the check interval to be 1/5 of the estimated time to
* send a single character, and make it at least 1. The check
@@ -1366,6 +1383,7 @@
break;
}
set_current_state(TASK_RUNNING); /* might not be needed */
+ unlock_kernel();
}
/*
@@ -2079,7 +2097,9 @@
int ret;
uart_change_pm(state, 0);
+ spin_lock_irq(&port->lock);
ops->set_mctrl(port, 0);
+ spin_unlock_irq(&port->lock);
ret = ops->startup(port);
if (ret == 0) {
uart_change_speed(state, NULL);
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index c2ea5d4..9691061 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -855,7 +855,7 @@
printk(KERN_INFO "%s: got a postchange notification "
"for cpu %d (old %d, new %d)\n",
- __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
+ __func__, freqs->cpu, freqs->old, freqs->new);
}
return NOTIFY_OK;
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 41fc6126..019da2e 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -839,7 +839,7 @@
if (uart_add_one_port(&sal_console_uart, &sal_console_port.sc_port) < 0) {
/* error - not sure what I'd do - so I'll do nothing */
- printk(KERN_ERR "%s: unable to add port\n", __FUNCTION__);
+ printk(KERN_ERR "%s: unable to add port\n", __func__);
}
/* when this driver is compiled in, the console initialization
diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c
index b565d5a..b51c242 100644
--- a/drivers/serial/uartlite.c
+++ b/drivers/serial/uartlite.c
@@ -584,7 +584,7 @@
const unsigned int *id;
int irq, rc;
- dev_dbg(&op->dev, "%s(%p, %p)\n", __FUNCTION__, op, match);
+ dev_dbg(&op->dev, "%s(%p, %p)\n", __func__, op, match);
rc = of_address_to_resource(op->node, 0, &res);
if (rc) {
diff --git a/drivers/serial/ucc_uart.c b/drivers/serial/ucc_uart.c
index 5e4310c..01917c4 100644
--- a/drivers/serial/ucc_uart.c
+++ b/drivers/serial/ucc_uart.c
@@ -215,7 +215,7 @@
return qe_port->bd_dma_addr + (addr - qe_port->bd_virt);
/* something nasty happened */
- printk(KERN_ERR "%s: addr=%p\n", __FUNCTION__, addr);
+ printk(KERN_ERR "%s: addr=%p\n", __func__, addr);
BUG();
return 0;
}
@@ -234,7 +234,7 @@
return qe_port->bd_virt + (addr - qe_port->bd_dma_addr);
/* something nasty happened */
- printk(KERN_ERR "%s: addr=%x\n", __FUNCTION__, addr);
+ printk(KERN_ERR "%s: addr=%x\n", __func__, addr);
BUG();
return NULL;
}
diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 02c8e30..e81d59d 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -497,7 +497,7 @@
struct atmel_spi *as;
u32 scbr, csr;
unsigned int bits = spi->bits_per_word;
- unsigned long bus_hz, sck_hz;
+ unsigned long bus_hz;
unsigned int npcs_pin;
int ret;
@@ -536,14 +536,25 @@
return -EINVAL;
}
- /* speed zero convention is used by some upper layers */
+ /*
+ * Pre-new_1 chips start out at half the peripheral
+ * bus speed.
+ */
bus_hz = clk_get_rate(as->clk);
+ if (!as->new_1)
+ bus_hz /= 2;
+
if (spi->max_speed_hz) {
- /* assume div32/fdiv/mbz == 0 */
- if (!as->new_1)
- bus_hz /= 2;
- scbr = ((bus_hz + spi->max_speed_hz - 1)
- / spi->max_speed_hz);
+ /*
+ * Calculate the lowest divider that satisfies the
+ * constraint, assuming div32/fdiv/mbz == 0.
+ */
+ scbr = DIV_ROUND_UP(bus_hz, spi->max_speed_hz);
+
+ /*
+ * If the resulting divider doesn't fit into the
+ * register bitfield, we can't satisfy the constraint.
+ */
if (scbr >= (1 << SPI_SCBR_SIZE)) {
dev_dbg(&spi->dev,
"setup: %d Hz too slow, scbr %u; min %ld Hz\n",
@@ -551,8 +562,8 @@
return -EINVAL;
}
} else
+ /* speed zero means "as slow as possible" */
scbr = 0xff;
- sck_hz = bus_hz / scbr;
csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8);
if (spi->mode & SPI_CPOL)
@@ -589,7 +600,7 @@
dev_dbg(&spi->dev,
"setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
- sck_hz, bits, spi->mode, spi->chip_select, csr);
+ bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c
index a9ac1fd..7fea3cf 100644
--- a/drivers/spi/spi_bfin5xx.c
+++ b/drivers/spi/spi_bfin5xx.c
@@ -608,6 +608,7 @@
u8 width;
u16 cr, dma_width, dma_config;
u32 tranf_success = 1;
+ u8 full_duplex = 0;
/* Get current state information */
message = drv_data->cur_msg;
@@ -658,6 +659,7 @@
}
if (transfer->rx_buf != NULL) {
+ full_duplex = transfer->tx_buf != NULL;
drv_data->rx = transfer->rx_buf;
drv_data->rx_end = drv_data->rx + transfer->len;
dev_dbg(&drv_data->pdev->dev, "rx_buf is %p, rx_end is %p\n",
@@ -740,7 +742,8 @@
* successful use different way to r/w according to
* drv_data->cur_chip->enable_dma
*/
- if (drv_data->cur_chip->enable_dma && drv_data->len > 6) {
+ if (!full_duplex && drv_data->cur_chip->enable_dma
+ && drv_data->len > 6) {
disable_dma(drv_data->dma_channel);
clear_dma_irqstat(drv_data->dma_channel);
@@ -828,7 +831,7 @@
/* IO mode write then read */
dev_dbg(&drv_data->pdev->dev, "doing IO transfer\n");
- if (drv_data->tx != NULL && drv_data->rx != NULL) {
+ if (full_duplex) {
/* full duplex mode */
BUG_ON((drv_data->tx_end - drv_data->tx) !=
(drv_data->rx_end - drv_data->rx));
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 34bfb7d..0885cc3 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -125,10 +125,10 @@
/* is clk = pclk / (2 * (pre+1)), or is it
* clk = (pclk * 2) / ( pre + 1) */
- div = (div / 2) - 1;
+ div /= 2;
- if (div < 0)
- div = 1;
+ if (div > 0)
+ div -= 1;
if (div > 255)
div = 255;
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 17e71d5..4b62852 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -3,7 +3,7 @@
#
menuconfig THERMAL
- bool "Generic Thermal sysfs driver"
+ tristate "Generic Thermal sysfs driver"
help
Generic Thermal Sysfs driver offers a generic mechanism for
thermal management. Usually it's made up of one or more thermal
@@ -11,4 +11,4 @@
Each thermal zone contains its own temperature, trip points,
cooling devices.
All platforms with ACPI thermal support can use this driver.
- If you want this support, you should say Y here.
+ If you want this support, you should say Y or M here.
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 8ef1232..31108a0 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -2,4 +2,4 @@
# Makefile for sensor chip drivers.
#
-obj-$(CONFIG_THERMAL) += thermal.o
+obj-$(CONFIG_THERMAL) += thermal_sys.o
diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal_sys.c
similarity index 81%
rename from drivers/thermal/thermal.c
rename to drivers/thermal/thermal_sys.c
index 7f79bbf..6098787 100644
--- a/drivers/thermal/thermal.c
+++ b/drivers/thermal/thermal_sys.c
@@ -31,7 +31,7 @@
#include <linux/thermal.h>
#include <linux/spinlock.h>
-MODULE_AUTHOR("Zhang Rui")
+MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL");
@@ -295,6 +295,164 @@
/* Device management */
+#if defined(CONFIG_HWMON) || \
+ (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+/* hwmon sys I/F */
+#include <linux/hwmon.h>
+static LIST_HEAD(thermal_hwmon_list);
+
+static ssize_t
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct thermal_hwmon_device *hwmon = dev->driver_data;
+ return sprintf(buf, "%s\n", hwmon->type);
+}
+static DEVICE_ATTR(name, 0444, name_show, NULL);
+
+static ssize_t
+temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct thermal_hwmon_attr *hwmon_attr
+ = container_of(attr, struct thermal_hwmon_attr, attr);
+ struct thermal_zone_device *tz
+ = container_of(hwmon_attr, struct thermal_zone_device,
+ temp_input);
+
+ return tz->ops->get_temp(tz, buf);
+}
+
+static ssize_t
+temp_crit_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct thermal_hwmon_attr *hwmon_attr
+ = container_of(attr, struct thermal_hwmon_attr, attr);
+ struct thermal_zone_device *tz
+ = container_of(hwmon_attr, struct thermal_zone_device,
+ temp_crit);
+
+ return tz->ops->get_trip_temp(tz, 0, buf);
+}
+
+
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+ struct thermal_hwmon_device *hwmon;
+ int new_hwmon_device = 1;
+ int result;
+
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(hwmon, &thermal_hwmon_list, node)
+ if (!strcmp(hwmon->type, tz->type)) {
+ new_hwmon_device = 0;
+ mutex_unlock(&thermal_list_lock);
+ goto register_sys_interface;
+ }
+ mutex_unlock(&thermal_list_lock);
+
+ hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
+ if (!hwmon)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&hwmon->tz_list);
+ strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
+ hwmon->device = hwmon_device_register(NULL);
+ if (IS_ERR(hwmon->device)) {
+ result = PTR_ERR(hwmon->device);
+ goto free_mem;
+ }
+ hwmon->device->driver_data = hwmon;
+ result = device_create_file(hwmon->device, &dev_attr_name);
+ if (result)
+ goto unregister_hwmon_device;
+
+ register_sys_interface:
+ tz->hwmon = hwmon;
+ hwmon->count++;
+
+ snprintf(tz->temp_input.name, THERMAL_NAME_LENGTH,
+ "temp%d_input", hwmon->count);
+ tz->temp_input.attr.attr.name = tz->temp_input.name;
+ tz->temp_input.attr.attr.mode = 0444;
+ tz->temp_input.attr.show = temp_input_show;
+ result = device_create_file(hwmon->device, &tz->temp_input.attr);
+ if (result)
+ goto unregister_hwmon_device;
+
+ if (tz->ops->get_crit_temp) {
+ unsigned long temperature;
+ if (!tz->ops->get_crit_temp(tz, &temperature)) {
+ snprintf(tz->temp_crit.name, THERMAL_NAME_LENGTH,
+ "temp%d_crit", hwmon->count);
+ tz->temp_crit.attr.attr.name = tz->temp_crit.name;
+ tz->temp_crit.attr.attr.mode = 0444;
+ tz->temp_crit.attr.show = temp_crit_show;
+ result = device_create_file(hwmon->device,
+ &tz->temp_crit.attr);
+ if (result)
+ goto unregister_hwmon_device;
+ }
+ }
+
+ mutex_lock(&thermal_list_lock);
+ if (new_hwmon_device)
+ list_add_tail(&hwmon->node, &thermal_hwmon_list);
+ list_add_tail(&tz->hwmon_node, &hwmon->tz_list);
+ mutex_unlock(&thermal_list_lock);
+
+ return 0;
+
+ unregister_hwmon_device:
+ device_remove_file(hwmon->device, &tz->temp_crit.attr);
+ device_remove_file(hwmon->device, &tz->temp_input.attr);
+ if (new_hwmon_device) {
+ device_remove_file(hwmon->device, &dev_attr_name);
+ hwmon_device_unregister(hwmon->device);
+ }
+ free_mem:
+ if (new_hwmon_device)
+ kfree(hwmon);
+
+ return result;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+ struct thermal_hwmon_device *hwmon = tz->hwmon;
+
+ tz->hwmon = NULL;
+ device_remove_file(hwmon->device, &tz->temp_input.attr);
+ device_remove_file(hwmon->device, &tz->temp_crit.attr);
+
+ mutex_lock(&thermal_list_lock);
+ list_del(&tz->hwmon_node);
+ if (!list_empty(&hwmon->tz_list)) {
+ mutex_unlock(&thermal_list_lock);
+ return;
+ }
+ list_del(&hwmon->node);
+ mutex_unlock(&thermal_list_lock);
+
+ device_remove_file(hwmon->device, &dev_attr_name);
+ hwmon_device_unregister(hwmon->device);
+ kfree(hwmon);
+}
+#else
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+ return 0;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+}
+#endif
+
+
/**
* thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
* @tz: thermal zone device
@@ -642,6 +800,10 @@
goto unregister;
}
+ result = thermal_add_hwmon_sysfs(tz);
+ if (result)
+ goto unregister;
+
mutex_lock(&thermal_list_lock);
list_add_tail(&tz->node, &thermal_tz_list);
if (ops->bind)
@@ -700,6 +862,7 @@
for (count = 0; count < tz->trips; count++)
TRIP_POINT_ATTR_REMOVE(&tz->device, count);
+ thermal_remove_hwmon_sysfs(tz);
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
idr_destroy(&tz->idr);
mutex_destroy(&tz->lock);
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 516a640..a419c42 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -17,6 +17,8 @@
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
+obj-$(CONFIG_USB_C67X00_HCD) += c67x00/
+
obj-$(CONFIG_USB_ACM) += class/
obj-$(CONFIG_USB_PRINTER) += class/
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
index 86e6403..be0b8da 100644
--- a/drivers/usb/atm/Kconfig
+++ b/drivers/usb/atm/Kconfig
@@ -19,7 +19,6 @@
config USB_SPEEDTOUCH
tristate "Speedtouch USB support"
- depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an SpeedTouch USB or SpeedTouch 330
@@ -32,7 +31,6 @@
config USB_CXACRU
tristate "Conexant AccessRunner USB support"
- depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an ADSL USB modem based on the Conexant
@@ -45,7 +43,6 @@
config USB_UEAGLEATM
tristate "ADI 930 and eagle USB DSL modem"
- depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an ADSL USB modem based on the ADI 930
@@ -58,7 +55,6 @@
config USB_XUSBATM
tristate "Other USB DSL modem support"
- depends on USB_ATM
help
Say Y here if you have a DSL USB modem not explicitly supported by
another USB DSL drivers. In order to use your modem you will need to
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index 4220f22..5f71ff3 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -305,8 +305,6 @@
*/
#define FW_GET_BYTE(p) *((__u8 *) (p))
-#define FW_GET_WORD(p) le16_to_cpu(get_unaligned((__le16 *) (p)))
-#define FW_GET_LONG(p) le32_to_cpu(get_unaligned((__le32 *) (p)))
#define FW_DIR "ueagle-atm/"
#define NB_MODEM 4
@@ -621,7 +619,7 @@
if (size < 4)
goto err_fw_corrupted;
- crc = FW_GET_LONG(pfw);
+ crc = get_unaligned_le32(pfw);
pfw += 4;
size -= 4;
if (crc32_be(0, pfw, size) != crc)
@@ -640,7 +638,7 @@
while (size > 3) {
u8 len = FW_GET_BYTE(pfw);
- u16 add = FW_GET_WORD(pfw + 1);
+ u16 add = get_unaligned_le16(pfw + 1);
size -= len + 3;
if (size < 0)
@@ -738,7 +736,7 @@
for (i = 0; i < pagecount; i++) {
- pageoffset = FW_GET_LONG(dsp + p);
+ pageoffset = get_unaligned_le32(dsp + p);
p += 4;
if (pageoffset == 0)
@@ -759,7 +757,7 @@
return 1;
pp += 2; /* skip blockaddr */
- blocksize = FW_GET_WORD(dsp + pp);
+ blocksize = get_unaligned_le16(dsp + pp);
pp += 2;
/* enough space for block data? */
@@ -928,7 +926,7 @@
goto bad1;
p += 4 * pageno;
- pageoffset = FW_GET_LONG(p);
+ pageoffset = get_unaligned_le32(p);
if (pageoffset == 0)
goto bad1;
@@ -945,10 +943,10 @@
bi.wOvlOffset = cpu_to_le16(ovl | 0x8000);
for (i = 0; i < blockcount; i++) {
- blockaddr = FW_GET_WORD(p);
+ blockaddr = get_unaligned_le16(p);
p += 2;
- blocksize = FW_GET_WORD(p);
+ blocksize = get_unaligned_le16(p);
p += 2;
bi.wSize = cpu_to_le16(blocksize);
@@ -1152,9 +1150,9 @@
cmv.bDirection = E1_HOSTTOMODEM;
cmv.bFunction = function;
cmv.wIndex = cpu_to_le16(sc->cmv_dsc.e1.idx);
- put_unaligned(cpu_to_le32(address), &cmv.dwSymbolicAddress);
+ put_unaligned_le32(address, &cmv.dwSymbolicAddress);
cmv.wOffsetAddress = cpu_to_le16(offset);
- put_unaligned(cpu_to_le32(data >> 16 | data << 16), &cmv.dwData);
+ put_unaligned_le32(data >> 16 | data << 16, &cmv.dwData);
ret = uea_request(sc, UEA_E1_SET_BLOCK, UEA_MPTX_START, sizeof(cmv), &cmv);
if (ret < 0)
@@ -1646,7 +1644,7 @@
if (size < 5)
goto err_fw_corrupted;
- crc = FW_GET_LONG(data);
+ crc = get_unaligned_le32(data);
data += 4;
size -= 4;
if (crc32_be(0, data, size) != crc)
@@ -1696,9 +1694,9 @@
"please update your firmware\n");
for (i = 0; i < len; i++) {
- ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v1[i].address),
- FW_GET_WORD(&cmvs_v1[i].offset),
- FW_GET_LONG(&cmvs_v1[i].data));
+ ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v1[i].address),
+ get_unaligned_le16(&cmvs_v1[i].offset),
+ get_unaligned_le32(&cmvs_v1[i].data));
if (ret < 0)
goto out;
}
@@ -1706,9 +1704,9 @@
struct uea_cmvs_v2 *cmvs_v2 = cmvs_ptr;
for (i = 0; i < len; i++) {
- ret = uea_write_cmv_e1(sc, FW_GET_LONG(&cmvs_v2[i].address),
- (u16) FW_GET_LONG(&cmvs_v2[i].offset),
- FW_GET_LONG(&cmvs_v2[i].data));
+ ret = uea_write_cmv_e1(sc, get_unaligned_le32(&cmvs_v2[i].address),
+ (u16) get_unaligned_le32(&cmvs_v2[i].offset),
+ get_unaligned_le32(&cmvs_v2[i].data));
if (ret < 0)
goto out;
}
@@ -1759,10 +1757,10 @@
for (i = 0; i < len; i++) {
ret = uea_write_cmv_e4(sc, 1,
- FW_GET_LONG(&cmvs_v2[i].group),
- FW_GET_LONG(&cmvs_v2[i].address),
- FW_GET_LONG(&cmvs_v2[i].offset),
- FW_GET_LONG(&cmvs_v2[i].data));
+ get_unaligned_le32(&cmvs_v2[i].group),
+ get_unaligned_le32(&cmvs_v2[i].address),
+ get_unaligned_le32(&cmvs_v2[i].offset),
+ get_unaligned_le32(&cmvs_v2[i].data));
if (ret < 0)
goto out;
}
@@ -1964,7 +1962,7 @@
if (UEA_CHIP_VERSION(sc) == ADI930
&& cmv->bFunction == E1_MAKEFUNCTION(2, 2)) {
cmv->wIndex = cpu_to_le16(dsc->idx);
- put_unaligned(cpu_to_le32(dsc->address), &cmv->dwSymbolicAddress);
+ put_unaligned_le32(dsc->address, &cmv->dwSymbolicAddress);
cmv->wOffsetAddress = cpu_to_le16(dsc->offset);
} else
goto bad2;
@@ -1978,11 +1976,11 @@
/* in case of MEMACCESS */
if (le16_to_cpu(cmv->wIndex) != dsc->idx ||
- le32_to_cpu(get_unaligned(&cmv->dwSymbolicAddress)) != dsc->address ||
+ get_unaligned_le32(&cmv->dwSymbolicAddress) != dsc->address ||
le16_to_cpu(cmv->wOffsetAddress) != dsc->offset)
goto bad2;
- sc->data = le32_to_cpu(get_unaligned(&cmv->dwData));
+ sc->data = get_unaligned_le32(&cmv->dwData);
sc->data = sc->data << 16 | sc->data >> 16;
wake_up_cmv_ack(sc);
diff --git a/drivers/usb/c67x00/Makefile b/drivers/usb/c67x00/Makefile
new file mode 100644
index 0000000..868bc41
--- /dev/null
+++ b/drivers/usb/c67x00/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for Cypress C67X00 USB Controller
+#
+
+ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
+
+obj-$(CONFIG_USB_C67X00_HCD) += c67x00.o
+
+c67x00-objs := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
new file mode 100644
index 0000000..5633bc5
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-drv.c
@@ -0,0 +1,243 @@
+/*
+ * c67x00-drv.c: Cypress C67X00 USB Common infrastructure
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+/*
+ * This file implements the common infrastructure for using the c67x00.
+ * It is both the link between the platform configuration and subdrivers and
+ * the link between the common hardware parts and the subdrivers (e.g.
+ * interrupt handling).
+ *
+ * The c67x00 has 2 SIE's (serial interface engine) wich can be configured
+ * to be host, device or OTG (with some limitations, E.G. only SIE1 can be OTG).
+ *
+ * Depending on the platform configuration, the SIE's are created and
+ * the corresponding subdriver is initialized (c67x00_probe_sie).
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/usb/c67x00.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+static void c67x00_probe_sie(struct c67x00_sie *sie,
+ struct c67x00_device *dev, int sie_num)
+{
+ spin_lock_init(&sie->lock);
+ sie->dev = dev;
+ sie->sie_num = sie_num;
+ sie->mode = c67x00_sie_config(dev->pdata->sie_config, sie_num);
+
+ switch (sie->mode) {
+ case C67X00_SIE_HOST:
+ c67x00_hcd_probe(sie);
+ break;
+
+ case C67X00_SIE_UNUSED:
+ dev_info(sie_dev(sie),
+ "Not using SIE %d as requested\n", sie->sie_num);
+ break;
+
+ default:
+ dev_err(sie_dev(sie),
+ "Unsupported configuration: 0x%x for SIE %d\n",
+ sie->mode, sie->sie_num);
+ break;
+ }
+}
+
+static void c67x00_remove_sie(struct c67x00_sie *sie)
+{
+ switch (sie->mode) {
+ case C67X00_SIE_HOST:
+ c67x00_hcd_remove(sie);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static irqreturn_t c67x00_irq(int irq, void *__dev)
+{
+ struct c67x00_device *c67x00 = __dev;
+ struct c67x00_sie *sie;
+ u16 msg, int_status;
+ int i, count = 8;
+
+ int_status = c67x00_ll_hpi_status(c67x00);
+ if (!int_status)
+ return IRQ_NONE;
+
+ while (int_status != 0 && (count-- >= 0)) {
+ c67x00_ll_irq(c67x00, int_status);
+ for (i = 0; i < C67X00_SIES; i++) {
+ sie = &c67x00->sie[i];
+ msg = 0;
+ if (int_status & SIEMSG_FLG(i))
+ msg = c67x00_ll_fetch_siemsg(c67x00, i);
+ if (sie->irq)
+ sie->irq(sie, int_status, msg);
+ }
+ int_status = c67x00_ll_hpi_status(c67x00);
+ }
+
+ if (int_status)
+ dev_warn(&c67x00->pdev->dev, "Not all interrupts handled! "
+ "status = 0x%04x\n", int_status);
+
+ return IRQ_HANDLED;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int __devinit c67x00_drv_probe(struct platform_device *pdev)
+{
+ struct c67x00_device *c67x00;
+ struct c67x00_platform_data *pdata;
+ struct resource *res, *res2;
+ int ret, i;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ res2 = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res2)
+ return -ENODEV;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ c67x00 = kzalloc(sizeof(*c67x00), GFP_KERNEL);
+ if (!c67x00)
+ return -ENOMEM;
+
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name)) {
+ dev_err(&pdev->dev, "Memory region busy\n");
+ ret = -EBUSY;
+ goto request_mem_failed;
+ }
+ c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1);
+ if (!c67x00->hpi.base) {
+ dev_err(&pdev->dev, "Unable to map HPI registers\n");
+ ret = -EIO;
+ goto map_failed;
+ }
+
+ spin_lock_init(&c67x00->hpi.lock);
+ c67x00->hpi.regstep = pdata->hpi_regstep;
+ c67x00->pdata = pdev->dev.platform_data;
+ c67x00->pdev = pdev;
+
+ c67x00_ll_init(c67x00);
+ c67x00_ll_hpi_reg_init(c67x00);
+
+ ret = request_irq(res2->start, c67x00_irq, 0, pdev->name, c67x00);
+ if (ret) {
+ dev_err(&pdev->dev, "Cannot claim IRQ\n");
+ goto request_irq_failed;
+ }
+
+ ret = c67x00_ll_reset(c67x00);
+ if (ret) {
+ dev_err(&pdev->dev, "Device reset failed\n");
+ goto reset_failed;
+ }
+
+ for (i = 0; i < C67X00_SIES; i++)
+ c67x00_probe_sie(&c67x00->sie[i], c67x00, i);
+
+ platform_set_drvdata(pdev, c67x00);
+
+ return 0;
+
+ reset_failed:
+ free_irq(res2->start, c67x00);
+ request_irq_failed:
+ iounmap(c67x00->hpi.base);
+ map_failed:
+ release_mem_region(res->start, res->end - res->start + 1);
+ request_mem_failed:
+ kfree(c67x00);
+
+ return ret;
+}
+
+static int __devexit c67x00_drv_remove(struct platform_device *pdev)
+{
+ struct c67x00_device *c67x00 = platform_get_drvdata(pdev);
+ struct resource *res;
+ int i;
+
+ for (i = 0; i < C67X00_SIES; i++)
+ c67x00_remove_sie(&c67x00->sie[i]);
+
+ c67x00_ll_release(c67x00);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res)
+ free_irq(res->start, c67x00);
+
+ iounmap(c67x00->hpi.base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res)
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(c67x00);
+
+ return 0;
+}
+
+static struct platform_driver c67x00_driver = {
+ .probe = c67x00_drv_probe,
+ .remove = __devexit_p(c67x00_drv_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "c67x00",
+ },
+};
+MODULE_ALIAS("platform:c67x00");
+
+static int __init c67x00_init(void)
+{
+ return platform_driver_register(&c67x00_driver);
+}
+
+static void __exit c67x00_exit(void)
+{
+ platform_driver_unregister(&c67x00_driver);
+}
+
+module_init(c67x00_init);
+module_exit(c67x00_exit);
+
+MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
+MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c
new file mode 100644
index 0000000..a22b887
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-hcd.c
@@ -0,0 +1,412 @@
+/*
+ * c67x00-hcd.c: Cypress C67X00 USB Host Controller Driver
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+/* --------------------------------------------------------------------------
+ * Root Hub Support
+ */
+
+static __u8 c67x00_hub_des[] = {
+ 0x09, /* __u8 bLength; */
+ 0x29, /* __u8 bDescriptorType; Hub-descriptor */
+ 0x02, /* __u8 bNbrPorts; */
+ 0x00, /* __u16 wHubCharacteristics; */
+ 0x00, /* (per-port OC, no power switching) */
+ 0x32, /* __u8 bPwrOn2pwrGood; 2ms */
+ 0x00, /* __u8 bHubContrCurrent; 0 mA */
+ 0x00, /* __u8 DeviceRemovable; ** 7 Ports max ** */
+ 0xff, /* __u8 PortPwrCtrlMask; ** 7 ports max ** */
+};
+
+static void c67x00_hub_reset_host_port(struct c67x00_sie *sie, int port)
+{
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ unsigned long flags;
+
+ c67x00_ll_husb_reset(sie, port);
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+ c67x00_ll_husb_reset_port(sie, port);
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ c67x00_ll_set_husb_eot(sie->dev, DEFAULT_EOT);
+}
+
+static int c67x00_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ struct c67x00_sie *sie = c67x00->sie;
+ u16 status;
+ int i;
+
+ *buf = 0;
+ status = c67x00_ll_usb_get_status(sie);
+ for (i = 0; i < C67X00_PORTS; i++)
+ if (status & PORT_CONNECT_CHANGE(i))
+ *buf |= (1 << i);
+
+ /* bit 0 denotes hub change, b1..n port change */
+ *buf <<= 1;
+
+ return !!*buf;
+}
+
+static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ struct c67x00_sie *sie = c67x00->sie;
+ u16 status, usb_status;
+ int len = 0;
+ unsigned int port = wIndex-1;
+ u16 wPortChange, wPortStatus;
+
+ switch (typeReq) {
+
+ case GetHubStatus:
+ *(__le32 *) buf = cpu_to_le32(0);
+ len = 4; /* hub power */
+ break;
+
+ case GetPortStatus:
+ if (wIndex > C67X00_PORTS)
+ return -EPIPE;
+
+ status = c67x00_ll_usb_get_status(sie);
+ usb_status = c67x00_ll_get_usb_ctl(sie);
+
+ wPortChange = 0;
+ if (status & PORT_CONNECT_CHANGE(port))
+ wPortChange |= USB_PORT_STAT_C_CONNECTION;
+
+ wPortStatus = USB_PORT_STAT_POWER;
+ if (!(status & PORT_SE0_STATUS(port)))
+ wPortStatus |= USB_PORT_STAT_CONNECTION;
+ if (usb_status & LOW_SPEED_PORT(port)) {
+ wPortStatus |= USB_PORT_STAT_LOW_SPEED;
+ c67x00->low_speed_ports |= (1 << port);
+ } else
+ c67x00->low_speed_ports &= ~(1 << port);
+
+ if (usb_status & SOF_EOP_EN(port))
+ wPortStatus |= USB_PORT_STAT_ENABLE;
+
+ *(__le16 *) buf = cpu_to_le16(wPortStatus);
+ *(__le16 *) (buf + 2) = cpu_to_le16(wPortChange);
+ len = 4;
+ break;
+
+ case SetHubFeature: /* We don't implement these */
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ len = 0;
+ break;
+
+ default:
+ return -EPIPE;
+ }
+ break;
+
+ case SetPortFeature:
+ if (wIndex > C67X00_PORTS)
+ return -EPIPE;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "SetPortFeature %d (SUSPEND)\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_RESET:
+ c67x00_hub_reset_host_port(sie, port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ /* Power always enabled */
+ len = 0;
+ break;
+
+ default:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "%s: SetPortFeature %d (0x%04x) Error!\n",
+ __func__, port, wValue);
+ return -EPIPE;
+ }
+ break;
+
+ case ClearPortFeature:
+ if (wIndex > C67X00_PORTS)
+ return -EPIPE;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ /* Reset the port so that the c67x00 also notices the
+ * disconnect */
+ c67x00_hub_reset_host_port(sie, port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_ENABLE:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): C_ENABLE\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): SUSPEND\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_SUSPEND:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): C_SUSPEND\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_POWER:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): POWER\n", port);
+ return -EPIPE;
+
+ case USB_PORT_FEAT_C_CONNECTION:
+ c67x00_ll_usb_clear_status(sie,
+ PORT_CONNECT_CHANGE(port));
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): OVER_CURRENT\n", port);
+ len = 0;
+ break;
+
+ case USB_PORT_FEAT_C_RESET:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "ClearPortFeature (%d): C_RESET\n", port);
+ len = 0;
+ break;
+
+ default:
+ dev_dbg(c67x00_hcd_dev(c67x00),
+ "%s: ClearPortFeature %d (0x%04x) Error!\n",
+ __func__, port, wValue);
+ return -EPIPE;
+ }
+ break;
+
+ case GetHubDescriptor:
+ len = min_t(unsigned int, sizeof(c67x00_hub_des), wLength);
+ memcpy(buf, c67x00_hub_des, len);
+ break;
+
+ default:
+ dev_dbg(c67x00_hcd_dev(c67x00), "%s: unknown\n", __func__);
+ return -EPIPE;
+ }
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------
+ * Main part of host controller driver
+ */
+
+/**
+ * c67x00_hcd_irq
+ *
+ * This function is called from the interrupt handler in c67x00-drv.c
+ */
+static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
+{
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
+
+ /* Handle sie message flags */
+ if (msg) {
+ if (msg & HUSB_TDListDone)
+ c67x00_sched_kick(c67x00);
+ else
+ dev_warn(c67x00_hcd_dev(c67x00),
+ "Unknown SIE msg flag(s): 0x%04x\n", msg);
+ }
+
+ if (unlikely(hcd->state == HC_STATE_HALT))
+ return;
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
+ return;
+
+ /* Handle Start of frame events */
+ if (int_status & SOFEOP_FLG(sie->sie_num)) {
+ c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
+ c67x00_sched_kick(c67x00);
+ set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+ }
+}
+
+/**
+ * c67x00_hcd_start: Host controller start hook
+ */
+static int c67x00_hcd_start(struct usb_hcd *hcd)
+{
+ hcd->uses_new_polling = 1;
+ hcd->state = HC_STATE_RUNNING;
+ hcd->poll_rh = 1;
+
+ return 0;
+}
+
+/**
+ * c67x00_hcd_stop: Host controller stop hook
+ */
+static void c67x00_hcd_stop(struct usb_hcd *hcd)
+{
+ /* Nothing to do */
+}
+
+static int c67x00_hcd_get_frame(struct usb_hcd *hcd)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ u16 temp_val;
+
+ dev_dbg(c67x00_hcd_dev(c67x00), "%s\n", __func__);
+ temp_val = c67x00_ll_husb_get_frame(c67x00->sie);
+ temp_val &= HOST_FRAME_MASK;
+ return temp_val ? (temp_val - 1) : HOST_FRAME_MASK;
+}
+
+static struct hc_driver c67x00_hc_driver = {
+ .description = "c67x00-hcd",
+ .product_desc = "Cypress C67X00 Host Controller",
+ .hcd_priv_size = sizeof(struct c67x00_hcd),
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .start = c67x00_hcd_start,
+ .stop = c67x00_hcd_stop,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = c67x00_urb_enqueue,
+ .urb_dequeue = c67x00_urb_dequeue,
+ .endpoint_disable = c67x00_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = c67x00_hcd_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = c67x00_hub_status_data,
+ .hub_control = c67x00_hub_control,
+};
+
+/* ---------------------------------------------------------------------
+ * Setup/Teardown routines
+ */
+
+int c67x00_hcd_probe(struct c67x00_sie *sie)
+{
+ struct c67x00_hcd *c67x00;
+ struct usb_hcd *hcd;
+ unsigned long flags;
+ int retval;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ hcd = usb_create_hcd(&c67x00_hc_driver, sie_dev(sie), "c67x00_sie");
+ if (!hcd) {
+ retval = -ENOMEM;
+ goto err0;
+ }
+ c67x00 = hcd_to_c67x00_hcd(hcd);
+
+ spin_lock_init(&c67x00->lock);
+ c67x00->sie = sie;
+
+ INIT_LIST_HEAD(&c67x00->list[PIPE_ISOCHRONOUS]);
+ INIT_LIST_HEAD(&c67x00->list[PIPE_INTERRUPT]);
+ INIT_LIST_HEAD(&c67x00->list[PIPE_CONTROL]);
+ INIT_LIST_HEAD(&c67x00->list[PIPE_BULK]);
+ c67x00->urb_count = 0;
+ INIT_LIST_HEAD(&c67x00->td_list);
+ c67x00->td_base_addr = CY_HCD_BUF_ADDR + SIE_TD_OFFSET(sie->sie_num);
+ c67x00->buf_base_addr = CY_HCD_BUF_ADDR + SIE_BUF_OFFSET(sie->sie_num);
+ c67x00->max_frame_bw = MAX_FRAME_BW_STD;
+
+ c67x00_ll_husb_init_host_port(sie);
+
+ init_completion(&c67x00->endpoint_disable);
+ retval = c67x00_sched_start_scheduler(c67x00);
+ if (retval)
+ goto err1;
+
+ retval = usb_add_hcd(hcd, 0, 0);
+ if (retval) {
+ dev_dbg(sie_dev(sie), "%s: usb_add_hcd returned %d\n",
+ __func__, retval);
+ goto err2;
+ }
+
+ spin_lock_irqsave(&sie->lock, flags);
+ sie->private_data = c67x00;
+ sie->irq = c67x00_hcd_irq;
+ spin_unlock_irqrestore(&sie->lock, flags);
+
+ return retval;
+
+ err2:
+ c67x00_sched_stop_scheduler(c67x00);
+ err1:
+ usb_put_hcd(hcd);
+ err0:
+ return retval;
+}
+
+/* may be called with controller, bus, and devices active */
+void c67x00_hcd_remove(struct c67x00_sie *sie)
+{
+ struct c67x00_hcd *c67x00 = sie->private_data;
+ struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
+
+ c67x00_sched_stop_scheduler(c67x00);
+ usb_remove_hcd(hcd);
+ usb_put_hcd(hcd);
+}
diff --git a/drivers/usb/c67x00/c67x00-hcd.h b/drivers/usb/c67x00/c67x00-hcd.h
new file mode 100644
index 0000000..e8c6d94
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-hcd.h
@@ -0,0 +1,133 @@
+/*
+ * c67x00-hcd.h: Cypress C67X00 USB HCD
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#ifndef _USB_C67X00_HCD_H
+#define _USB_C67X00_HCD_H
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include "../core/hcd.h"
+#include "c67x00.h"
+
+/*
+ * The following parameters depend on the CPU speed, bus speed, ...
+ * These can be tuned for specific use cases, e.g. if isochronous transfers
+ * are very important, bandwith can be sacrificed to guarantee that the
+ * 1ms deadline will be met.
+ * If bulk transfers are important, the MAX_FRAME_BW can be increased,
+ * but some (or many) isochronous deadlines might not be met.
+ *
+ * The values are specified in bittime.
+ */
+
+/*
+ * The current implementation switches between _STD (default) and _ISO (when
+ * isochronous transfers are scheduled), in order to optimize the throughput
+ * in normal cicrumstances, but also provide good isochronous behaviour.
+ *
+ * Bandwidth is described in bit time so with a 12MHz USB clock and 1ms
+ * frames; there are 12000 bit times per frame.
+ */
+
+#define TOTAL_FRAME_BW 12000
+#define DEFAULT_EOT 2250
+
+#define MAX_FRAME_BW_STD (TOTAL_FRAME_BW - DEFAULT_EOT)
+#define MAX_FRAME_BW_ISO 2400
+
+/*
+ * Periodic transfers may only use 90% of the full frame, but as
+ * we currently don't even use 90% of the full frame, we may
+ * use the full usable time for periodic transfers.
+ */
+#define MAX_PERIODIC_BW(full_bw) full_bw
+
+/* -------------------------------------------------------------------------- */
+
+struct c67x00_hcd {
+ spinlock_t lock;
+ struct c67x00_sie *sie;
+ unsigned int low_speed_ports; /* bitmask of low speed ports */
+ unsigned int urb_count;
+ unsigned int urb_iso_count;
+
+ struct list_head list[4]; /* iso, int, ctrl, bulk */
+#if PIPE_BULK != 3
+#error "Sanity check failed, this code presumes PIPE_... to range from 0 to 3"
+#endif
+
+ /* USB bandwidth allocated to td_list */
+ int bandwidth_allocated;
+ /* USB bandwidth allocated for isoc/int transfer */
+ int periodic_bw_allocated;
+ struct list_head td_list;
+ int max_frame_bw;
+
+ u16 td_base_addr;
+ u16 buf_base_addr;
+ u16 next_td_addr;
+ u16 next_buf_addr;
+
+ struct tasklet_struct tasklet;
+
+ struct completion endpoint_disable;
+
+ u16 current_frame;
+ u16 last_frame;
+};
+
+static inline struct c67x00_hcd *hcd_to_c67x00_hcd(struct usb_hcd *hcd)
+{
+ return (struct c67x00_hcd *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *c67x00_hcd_to_hcd(struct c67x00_hcd *c67x00)
+{
+ return container_of((void *)c67x00, struct usb_hcd, hcd_priv);
+}
+
+/* ---------------------------------------------------------------------
+ * Functions used by c67x00-drv
+ */
+
+int c67x00_hcd_probe(struct c67x00_sie *sie);
+void c67x00_hcd_remove(struct c67x00_sie *sie);
+
+/* ---------------------------------------------------------------------
+ * Transfer Descriptor scheduling functions
+ */
+int c67x00_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags);
+int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
+void c67x00_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep);
+
+void c67x00_hcd_msg_received(struct c67x00_sie *sie, u16 msg);
+void c67x00_sched_kick(struct c67x00_hcd *c67x00);
+int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00);
+void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00);
+
+#define c67x00_hcd_dev(x) (c67x00_hcd_to_hcd(x)->self.controller)
+
+#endif /* _USB_C67X00_HCD_H */
diff --git a/drivers/usb/c67x00/c67x00-ll-hpi.c b/drivers/usb/c67x00/c67x00-ll-hpi.c
new file mode 100644
index 0000000..f3430b3
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-ll-hpi.c
@@ -0,0 +1,480 @@
+/*
+ * c67x00-ll-hpi.c: Cypress C67X00 USB Low level interface using HPI
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#include <asm/byteorder.h>
+#include <linux/io.h>
+#include <linux/usb/c67x00.h>
+#include "c67x00.h"
+
+#define COMM_REGS 14
+
+struct c67x00_lcp_int_data {
+ u16 regs[COMM_REGS];
+};
+
+/* -------------------------------------------------------------------------- */
+/* Interface definitions */
+
+#define COMM_ACK 0x0FED
+#define COMM_NAK 0xDEAD
+
+#define COMM_RESET 0xFA50
+#define COMM_EXEC_INT 0xCE01
+#define COMM_INT_NUM 0x01C2
+
+/* Registers 0 to COMM_REGS-1 */
+#define COMM_R(x) (0x01C4 + 2 * (x))
+
+#define HUSB_SIE_pCurrentTDPtr(x) ((x) ? 0x01B2 : 0x01B0)
+#define HUSB_SIE_pTDListDone_Sem(x) ((x) ? 0x01B8 : 0x01B6)
+#define HUSB_pEOT 0x01B4
+
+/* Software interrupts */
+/* 114, 115: */
+#define HUSB_SIE_INIT_INT(x) ((x) ? 0x0073 : 0x0072)
+#define HUSB_RESET_INT 0x0074
+
+#define SUSB_INIT_INT 0x0071
+#define SUSB_INIT_INT_LOC (SUSB_INIT_INT * 2)
+
+/* -----------------------------------------------------------------------
+ * HPI implementation
+ *
+ * The c67x00 chip also support control via SPI or HSS serial
+ * interfaces. However, this driver assumes that register access can
+ * be performed from IRQ context. While this is a safe assuption with
+ * the HPI interface, it is not true for the serial interfaces.
+ */
+
+/* HPI registers */
+#define HPI_DATA 0
+#define HPI_MAILBOX 1
+#define HPI_ADDR 2
+#define HPI_STATUS 3
+
+static inline u16 hpi_read_reg(struct c67x00_device *dev, int reg)
+{
+ return __raw_readw(dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline void hpi_write_reg(struct c67x00_device *dev, int reg, u16 value)
+{
+ __raw_writew(value, dev->hpi.base + reg * dev->hpi.regstep);
+}
+
+static inline u16 hpi_read_word_nolock(struct c67x00_device *dev, u16 reg)
+{
+ hpi_write_reg(dev, HPI_ADDR, reg);
+ return hpi_read_reg(dev, HPI_DATA);
+}
+
+static u16 hpi_read_word(struct c67x00_device *dev, u16 reg)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_word_nolock(dev, reg);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+static void hpi_write_word_nolock(struct c67x00_device *dev, u16 reg, u16 value)
+{
+ hpi_write_reg(dev, HPI_ADDR, reg);
+ hpi_write_reg(dev, HPI_DATA, value);
+}
+
+static void hpi_write_word(struct c67x00_device *dev, u16 reg, u16 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ hpi_write_word_nolock(dev, reg, value);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_write_words_le16(struct c67x00_device *dev, u16 addr,
+ u16 *data, u16 count)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+
+ hpi_write_reg(dev, HPI_ADDR, addr);
+ for (i = 0; i < count; i++)
+ hpi_write_reg(dev, HPI_DATA, cpu_to_le16(*data++));
+
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+/*
+ * Only data is little endian, addr has cpu endianess
+ */
+static void hpi_read_words_le16(struct c67x00_device *dev, u16 addr,
+ u16 *data, u16 count)
+{
+ unsigned long flags;
+ int i;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ hpi_write_reg(dev, HPI_ADDR, addr);
+ for (i = 0; i < count; i++)
+ *data++ = le16_to_cpu(hpi_read_reg(dev, HPI_DATA));
+
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_set_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_word_nolock(dev, reg);
+ hpi_write_word_nolock(dev, reg, value | mask);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static void hpi_clear_bits(struct c67x00_device *dev, u16 reg, u16 mask)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_word_nolock(dev, reg);
+ hpi_write_word_nolock(dev, reg, value & ~mask);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+}
+
+static u16 hpi_recv_mbox(struct c67x00_device *dev)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_reg(dev, HPI_MAILBOX);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+static u16 hpi_send_mbox(struct c67x00_device *dev, u16 value)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ hpi_write_reg(dev, HPI_MAILBOX, value);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev)
+{
+ u16 value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hpi.lock, flags);
+ value = hpi_read_reg(dev, HPI_STATUS);
+ spin_unlock_irqrestore(&dev->hpi.lock, flags);
+
+ return value;
+}
+
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev)
+{
+ int i;
+
+ hpi_recv_mbox(dev);
+ c67x00_ll_hpi_status(dev);
+ hpi_write_word(dev, HPI_IRQ_ROUTING_REG, 0);
+
+ for (i = 0; i < C67X00_SIES; i++) {
+ hpi_write_word(dev, SIEMSG_REG(i), 0);
+ hpi_read_word(dev, SIEMSG_REG(i));
+ }
+}
+
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie)
+{
+ hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+ SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie)
+{
+ hpi_clear_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+ SOFEOP_TO_HPI_EN(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+/* Transactions */
+
+static inline u16 ll_recv_msg(struct c67x00_device *dev)
+{
+ u16 res;
+
+ res = wait_for_completion_timeout(&dev->hpi.lcp.msg_received, 5 * HZ);
+ WARN_ON(!res);
+
+ return (res == 0) ? -EIO : 0;
+}
+
+/* -------------------------------------------------------------------------- */
+/* General functions */
+
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num)
+{
+ u16 val;
+
+ val = hpi_read_word(dev, SIEMSG_REG(sie_num));
+ /* clear register to allow next message */
+ hpi_write_word(dev, SIEMSG_REG(sie_num), 0);
+
+ return val;
+}
+
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num));
+}
+
+/**
+ * c67x00_ll_usb_clear_status - clear the USB status bits
+ */
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits)
+{
+ hpi_write_word(sie->dev, USB_STAT_REG(sie->sie_num), bits);
+}
+
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, USB_STAT_REG(sie->sie_num));
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_comm_exec_int(struct c67x00_device *dev, u16 nr,
+ struct c67x00_lcp_int_data *data)
+{
+ int i, rc;
+
+ mutex_lock(&dev->hpi.lcp.mutex);
+ hpi_write_word(dev, COMM_INT_NUM, nr);
+ for (i = 0; i < COMM_REGS; i++)
+ hpi_write_word(dev, COMM_R(i), data->regs[i]);
+ hpi_send_mbox(dev, COMM_EXEC_INT);
+ rc = ll_recv_msg(dev);
+ mutex_unlock(&dev->hpi.lcp.mutex);
+
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Host specific functions */
+
+void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value)
+{
+ mutex_lock(&dev->hpi.lcp.mutex);
+ hpi_write_word(dev, HUSB_pEOT, value);
+ mutex_unlock(&dev->hpi.lcp.mutex);
+}
+
+static inline void c67x00_ll_husb_sie_init(struct c67x00_sie *sie)
+{
+ struct c67x00_device *dev = sie->dev;
+ struct c67x00_lcp_int_data data;
+ int rc;
+
+ rc = c67x00_comm_exec_int(dev, HUSB_SIE_INIT_INT(sie->sie_num), &data);
+ BUG_ON(rc); /* No return path for error code; crash spectacularly */
+}
+
+void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port)
+{
+ struct c67x00_device *dev = sie->dev;
+ struct c67x00_lcp_int_data data;
+ int rc;
+
+ data.regs[0] = 50; /* Reset USB port for 50ms */
+ data.regs[1] = port | (sie->sie_num << 1);
+ rc = c67x00_comm_exec_int(dev, HUSB_RESET_INT, &data);
+ BUG_ON(rc); /* No return path for error code; crash spectacularly */
+}
+
+void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr)
+{
+ hpi_write_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num), addr);
+}
+
+u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, HUSB_SIE_pCurrentTDPtr(sie->sie_num));
+}
+
+u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie)
+{
+ return hpi_read_word(sie->dev, HOST_FRAME_REG(sie->sie_num));
+}
+
+void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie)
+{
+ /* Set port into host mode */
+ hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), HOST_MODE);
+ c67x00_ll_husb_sie_init(sie);
+ /* Clear interrupts */
+ c67x00_ll_usb_clear_status(sie, HOST_STAT_MASK);
+ /* Check */
+ if (!(hpi_read_word(sie->dev, USB_CTL_REG(sie->sie_num)) & HOST_MODE))
+ dev_warn(sie_dev(sie),
+ "SIE %d not set to host mode\n", sie->sie_num);
+}
+
+void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port)
+{
+ /* Clear connect change */
+ c67x00_ll_usb_clear_status(sie, PORT_CONNECT_CHANGE(port));
+
+ /* Enable interrupts */
+ hpi_set_bits(sie->dev, HPI_IRQ_ROUTING_REG,
+ SOFEOP_TO_CPU_EN(sie->sie_num));
+ hpi_set_bits(sie->dev, HOST_IRQ_EN_REG(sie->sie_num),
+ SOF_EOP_IRQ_EN | DONE_IRQ_EN);
+
+ /* Enable pull down transistors */
+ hpi_set_bits(sie->dev, USB_CTL_REG(sie->sie_num), PORT_RES_EN(port));
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status)
+{
+ if ((int_status & MBX_OUT_FLG) == 0)
+ return;
+
+ dev->hpi.lcp.last_msg = hpi_recv_mbox(dev);
+ complete(&dev->hpi.lcp.msg_received);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int c67x00_ll_reset(struct c67x00_device *dev)
+{
+ int rc;
+
+ mutex_lock(&dev->hpi.lcp.mutex);
+ hpi_send_mbox(dev, COMM_RESET);
+ rc = ll_recv_msg(dev);
+ mutex_unlock(&dev->hpi.lcp.mutex);
+
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_ll_write_mem_le16 - write into c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len)
+{
+ u8 *buf = data;
+
+ /* Sanity check */
+ if (addr + len > 0xffff) {
+ dev_err(&dev->pdev->dev,
+ "Trying to write beyond writable region!\n");
+ return;
+ }
+
+ if (addr & 0x01) {
+ /* unaligned access */
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr - 1);
+ tmp = (tmp & 0x00ff) | (*buf++ << 8);
+ hpi_write_word(dev, addr - 1, tmp);
+ addr++;
+ len--;
+ }
+
+ hpi_write_words_le16(dev, addr, (u16 *)buf, len / 2);
+ buf += len & ~0x01;
+ addr += len & ~0x01;
+ len &= 0x01;
+
+ if (len) {
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr);
+ tmp = (tmp & 0xff00) | *buf;
+ hpi_write_word(dev, addr, tmp);
+ }
+}
+
+/**
+ * c67x00_ll_read_mem_le16 - read from c67x00 memory
+ * Only data is little endian, addr has cpu endianess.
+ */
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len)
+{
+ u8 *buf = data;
+
+ if (addr & 0x01) {
+ /* unaligned access */
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr - 1);
+ *buf++ = (tmp >> 8) & 0x00ff;
+ addr++;
+ len--;
+ }
+
+ hpi_read_words_le16(dev, addr, (u16 *)buf, len / 2);
+ buf += len & ~0x01;
+ addr += len & ~0x01;
+ len &= 0x01;
+
+ if (len) {
+ u16 tmp;
+ tmp = hpi_read_word(dev, addr);
+ *buf = tmp & 0x00ff;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+void c67x00_ll_init(struct c67x00_device *dev)
+{
+ mutex_init(&dev->hpi.lcp.mutex);
+ init_completion(&dev->hpi.lcp.msg_received);
+}
+
+void c67x00_ll_release(struct c67x00_device *dev)
+{
+}
diff --git a/drivers/usb/c67x00/c67x00-sched.c b/drivers/usb/c67x00/c67x00-sched.c
new file mode 100644
index 0000000..85dfe29
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00-sched.c
@@ -0,0 +1,1170 @@
+/*
+ * c67x00-sched.c: Cypress C67X00 USB Host Controller Driver - TD scheduling
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#include <linux/kthread.h>
+
+#include "c67x00.h"
+#include "c67x00-hcd.h"
+
+/*
+ * These are the stages for a control urb, they are kept
+ * in both urb->interval and td->privdata.
+ */
+#define SETUP_STAGE 0
+#define DATA_STAGE 1
+#define STATUS_STAGE 2
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * struct c67x00_ep_data: Host endpoint data structure
+ */
+struct c67x00_ep_data {
+ struct list_head queue;
+ struct list_head node;
+ struct usb_host_endpoint *hep;
+ struct usb_device *dev;
+ u16 next_frame; /* For int/isoc transactions */
+};
+
+/**
+ * struct c67x00_td
+ *
+ * Hardware parts are little endiannes, SW in CPU endianess.
+ */
+struct c67x00_td {
+ /* HW specific part */
+ __le16 ly_base_addr; /* Bytes 0-1 */
+ __le16 port_length; /* Bytes 2-3 */
+ u8 pid_ep; /* Byte 4 */
+ u8 dev_addr; /* Byte 5 */
+ u8 ctrl_reg; /* Byte 6 */
+ u8 status; /* Byte 7 */
+ u8 retry_cnt; /* Byte 8 */
+#define TT_OFFSET 2
+#define TT_CONTROL 0
+#define TT_ISOCHRONOUS 1
+#define TT_BULK 2
+#define TT_INTERRUPT 3
+ u8 residue; /* Byte 9 */
+ __le16 next_td_addr; /* Bytes 10-11 */
+ /* SW part */
+ struct list_head td_list;
+ u16 td_addr;
+ void *data;
+ struct urb *urb;
+ unsigned long privdata;
+
+ /* These are needed for handling the toggle bits:
+ * an urb can be dequeued while a td is in progress
+ * after checking the td, the toggle bit might need to
+ * be fixed */
+ struct c67x00_ep_data *ep_data;
+ unsigned int pipe;
+};
+
+struct c67x00_urb_priv {
+ struct list_head hep_node;
+ struct urb *urb;
+ int port;
+ int cnt; /* packet number for isoc */
+ int status;
+ struct c67x00_ep_data *ep_data;
+};
+
+#define td_udev(td) ((td)->ep_data->dev)
+
+#define CY_TD_SIZE 12
+
+#define TD_PIDEP_OFFSET 0x04
+#define TD_PIDEPMASK_PID 0xF0
+#define TD_PIDEPMASK_EP 0x0F
+#define TD_PORTLENMASK_DL 0x02FF
+#define TD_PORTLENMASK_PN 0xC000
+
+#define TD_STATUS_OFFSET 0x07
+#define TD_STATUSMASK_ACK 0x01
+#define TD_STATUSMASK_ERR 0x02
+#define TD_STATUSMASK_TMOUT 0x04
+#define TD_STATUSMASK_SEQ 0x08
+#define TD_STATUSMASK_SETUP 0x10
+#define TD_STATUSMASK_OVF 0x20
+#define TD_STATUSMASK_NAK 0x40
+#define TD_STATUSMASK_STALL 0x80
+
+#define TD_ERROR_MASK (TD_STATUSMASK_ERR | TD_STATUSMASK_TMOUT | \
+ TD_STATUSMASK_STALL)
+
+#define TD_RETRYCNT_OFFSET 0x08
+#define TD_RETRYCNTMASK_ACT_FLG 0x10
+#define TD_RETRYCNTMASK_TX_TYPE 0x0C
+#define TD_RETRYCNTMASK_RTY_CNT 0x03
+
+#define TD_RESIDUE_OVERFLOW 0x80
+
+#define TD_PID_IN 0x90
+
+/* Residue: signed 8bits, neg -> OVERFLOW, pos -> UNDERFLOW */
+#define td_residue(td) ((__s8)(td->residue))
+#define td_ly_base_addr(td) (__le16_to_cpu((td)->ly_base_addr))
+#define td_port_length(td) (__le16_to_cpu((td)->port_length))
+#define td_next_td_addr(td) (__le16_to_cpu((td)->next_td_addr))
+
+#define td_active(td) ((td)->retry_cnt & TD_RETRYCNTMASK_ACT_FLG)
+#define td_length(td) (td_port_length(td) & TD_PORTLENMASK_DL)
+
+#define td_sequence_ok(td) (!td->status || \
+ (!(td->status & TD_STATUSMASK_SEQ) == \
+ !(td->ctrl_reg & SEQ_SEL)))
+
+#define td_acked(td) (!td->status || \
+ (td->status & TD_STATUSMASK_ACK))
+#define td_actual_bytes(td) (td_length(td) - td_residue(td))
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef DEBUG
+
+/**
+ * dbg_td - Dump the contents of the TD
+ */
+static void dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg)
+{
+ struct device *dev = c67x00_hcd_dev(c67x00);
+
+ dev_dbg(dev, "### %s at 0x%04x\n", msg, td->td_addr);
+ dev_dbg(dev, "urb: 0x%p\n", td->urb);
+ dev_dbg(dev, "endpoint: %4d\n", usb_pipeendpoint(td->pipe));
+ dev_dbg(dev, "pipeout: %4d\n", usb_pipeout(td->pipe));
+ dev_dbg(dev, "ly_base_addr: 0x%04x\n", td_ly_base_addr(td));
+ dev_dbg(dev, "port_length: 0x%04x\n", td_port_length(td));
+ dev_dbg(dev, "pid_ep: 0x%02x\n", td->pid_ep);
+ dev_dbg(dev, "dev_addr: 0x%02x\n", td->dev_addr);
+ dev_dbg(dev, "ctrl_reg: 0x%02x\n", td->ctrl_reg);
+ dev_dbg(dev, "status: 0x%02x\n", td->status);
+ dev_dbg(dev, "retry_cnt: 0x%02x\n", td->retry_cnt);
+ dev_dbg(dev, "residue: 0x%02x\n", td->residue);
+ dev_dbg(dev, "next_td_addr: 0x%04x\n", td_next_td_addr(td));
+ dev_dbg(dev, "data:");
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 1,
+ td->data, td_length(td), 1);
+}
+#else /* DEBUG */
+
+static inline void
+dbg_td(struct c67x00_hcd *c67x00, struct c67x00_td *td, char *msg) { }
+
+#endif /* DEBUG */
+
+/* -------------------------------------------------------------------------- */
+/* Helper functions */
+
+static inline u16 c67x00_get_current_frame_number(struct c67x00_hcd *c67x00)
+{
+ return c67x00_ll_husb_get_frame(c67x00->sie) & HOST_FRAME_MASK;
+}
+
+/**
+ * frame_add
+ * Software wraparound for framenumbers.
+ */
+static inline u16 frame_add(u16 a, u16 b)
+{
+ return (a + b) & HOST_FRAME_MASK;
+}
+
+/**
+ * frame_after - is frame a after frame b
+ */
+static inline int frame_after(u16 a, u16 b)
+{
+ return ((HOST_FRAME_MASK + a - b) & HOST_FRAME_MASK) <
+ (HOST_FRAME_MASK / 2);
+}
+
+/**
+ * frame_after_eq - is frame a after or equal to frame b
+ */
+static inline int frame_after_eq(u16 a, u16 b)
+{
+ return ((HOST_FRAME_MASK + 1 + a - b) & HOST_FRAME_MASK) <
+ (HOST_FRAME_MASK / 2);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_release_urb - remove link from all tds to this urb
+ * Disconnects the urb from it's tds, so that it can be given back.
+ * pre: urb->hcpriv != NULL
+ */
+static void c67x00_release_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct c67x00_td *td;
+ struct c67x00_urb_priv *urbp;
+
+ BUG_ON(!urb);
+
+ c67x00->urb_count--;
+
+ if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ c67x00->urb_iso_count--;
+ if (c67x00->urb_iso_count == 0)
+ c67x00->max_frame_bw = MAX_FRAME_BW_STD;
+ }
+
+ /* TODO this might be not so efficient when we've got many urbs!
+ * Alternatives:
+ * * only clear when needed
+ * * keep a list of tds with each urbp
+ */
+ list_for_each_entry(td, &c67x00->td_list, td_list)
+ if (urb == td->urb)
+ td->urb = NULL;
+
+ urbp = urb->hcpriv;
+ urb->hcpriv = NULL;
+ list_del(&urbp->hep_node);
+ kfree(urbp);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct c67x00_ep_data *
+c67x00_ep_data_alloc(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct usb_host_endpoint *hep = urb->ep;
+ struct c67x00_ep_data *ep_data;
+ int type;
+
+ c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
+
+ /* Check if endpoint already has a c67x00_ep_data struct allocated */
+ if (hep->hcpriv) {
+ ep_data = hep->hcpriv;
+ if (frame_after(c67x00->current_frame, ep_data->next_frame))
+ ep_data->next_frame =
+ frame_add(c67x00->current_frame, 1);
+ return hep->hcpriv;
+ }
+
+ /* Allocate and initialize a new c67x00 endpoint data structure */
+ ep_data = kzalloc(sizeof(*ep_data), GFP_ATOMIC);
+ if (!ep_data)
+ return NULL;
+
+ INIT_LIST_HEAD(&ep_data->queue);
+ INIT_LIST_HEAD(&ep_data->node);
+ ep_data->hep = hep;
+
+ /* hold a reference to udev as long as this endpoint lives,
+ * this is needed to possibly fix the data toggle */
+ ep_data->dev = usb_get_dev(urb->dev);
+ hep->hcpriv = ep_data;
+
+ /* For ISOC and INT endpoints, start ASAP: */
+ ep_data->next_frame = frame_add(c67x00->current_frame, 1);
+
+ /* Add the endpoint data to one of the pipe lists; must be added
+ in order of endpoint address */
+ type = usb_pipetype(urb->pipe);
+ if (list_empty(&ep_data->node)) {
+ list_add(&ep_data->node, &c67x00->list[type]);
+ } else {
+ struct c67x00_ep_data *prev;
+
+ list_for_each_entry(prev, &c67x00->list[type], node) {
+ if (prev->hep->desc.bEndpointAddress >
+ hep->desc.bEndpointAddress) {
+ list_add(&ep_data->node, prev->node.prev);
+ break;
+ }
+ }
+ }
+
+ return ep_data;
+}
+
+static int c67x00_ep_data_free(struct usb_host_endpoint *hep)
+{
+ struct c67x00_ep_data *ep_data = hep->hcpriv;
+
+ if (!ep_data)
+ return 0;
+
+ if (!list_empty(&ep_data->queue))
+ return -EBUSY;
+
+ usb_put_dev(ep_data->dev);
+ list_del(&ep_data->queue);
+ list_del(&ep_data->node);
+
+ kfree(ep_data);
+ hep->hcpriv = NULL;
+
+ return 0;
+}
+
+void c67x00_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ unsigned long flags;
+
+ if (!list_empty(&ep->urb_list))
+ dev_warn(c67x00_hcd_dev(c67x00), "error: urb list not empty\n");
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+
+ /* loop waiting for all transfers in the endpoint queue to complete */
+ while (c67x00_ep_data_free(ep)) {
+ /* Drop the lock so we can sleep waiting for the hardware */
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ /* it could happen that we reinitialize this completion, while
+ * somebody was waiting for that completion. The timeout and
+ * while loop handle such cases, but this might be improved */
+ INIT_COMPLETION(c67x00->endpoint_disable);
+ c67x00_sched_kick(c67x00);
+ wait_for_completion_timeout(&c67x00->endpoint_disable, 1 * HZ);
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+ }
+
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline int get_root_port(struct usb_device *dev)
+{
+ while (dev->parent->parent)
+ dev = dev->parent;
+ return dev->portnum;
+}
+
+int c67x00_urb_enqueue(struct usb_hcd *hcd,
+ struct urb *urb, gfp_t mem_flags)
+{
+ int ret;
+ unsigned long flags;
+ struct c67x00_urb_priv *urbp;
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ int port = get_root_port(urb->dev)-1;
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+
+ /* Make sure host controller is running */
+ if (!HC_IS_RUNNING(hcd->state)) {
+ ret = -ENODEV;
+ goto err_not_linked;
+ }
+
+ ret = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (ret)
+ goto err_not_linked;
+
+ /* Allocate and initialize urb private data */
+ urbp = kzalloc(sizeof(*urbp), mem_flags);
+ if (!urbp) {
+ ret = -ENOMEM;
+ goto err_urbp;
+ }
+
+ INIT_LIST_HEAD(&urbp->hep_node);
+ urbp->urb = urb;
+ urbp->port = port;
+
+ urbp->ep_data = c67x00_ep_data_alloc(c67x00, urb);
+
+ if (!urbp->ep_data) {
+ ret = -ENOMEM;
+ goto err_epdata;
+ }
+
+ /* TODO claim bandwidth with usb_claim_bandwidth?
+ * also release it somewhere! */
+
+ urb->hcpriv = urbp;
+
+ urb->actual_length = 0; /* Nothing received/transmitted yet */
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ urb->interval = SETUP_STAGE;
+ break;
+ case PIPE_INTERRUPT:
+ break;
+ case PIPE_BULK:
+ break;
+ case PIPE_ISOCHRONOUS:
+ if (c67x00->urb_iso_count == 0)
+ c67x00->max_frame_bw = MAX_FRAME_BW_ISO;
+ c67x00->urb_iso_count++;
+ /* Assume always URB_ISO_ASAP, FIXME */
+ if (list_empty(&urbp->ep_data->queue))
+ urb->start_frame = urbp->ep_data->next_frame;
+ else {
+ /* Go right after the last one */
+ struct urb *last_urb;
+
+ last_urb = list_entry(urbp->ep_data->queue.prev,
+ struct c67x00_urb_priv,
+ hep_node)->urb;
+ urb->start_frame =
+ frame_add(last_urb->start_frame,
+ last_urb->number_of_packets *
+ last_urb->interval);
+ }
+ urbp->cnt = 0;
+ break;
+ }
+
+ /* Add the URB to the endpoint queue */
+ list_add_tail(&urbp->hep_node, &urbp->ep_data->queue);
+
+ /* If this is the only URB, kick start the controller */
+ if (!c67x00->urb_count++)
+ c67x00_ll_hpi_enable_sofeop(c67x00->sie);
+
+ c67x00_sched_kick(c67x00);
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ return 0;
+
+err_epdata:
+ kfree(urbp);
+err_urbp:
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+err_not_linked:
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ return ret;
+}
+
+int c67x00_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
+{
+ struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
+ unsigned long flags;
+ int rc;
+
+ spin_lock_irqsave(&c67x00->lock, flags);
+ rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (rc)
+ goto done;
+
+ c67x00_release_urb(c67x00, urb);
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+ spin_unlock(&c67x00->lock);
+ usb_hcd_giveback_urb(hcd, urb, status);
+ spin_lock(&c67x00->lock);
+
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+
+ return 0;
+
+ done:
+ spin_unlock_irqrestore(&c67x00->lock, flags);
+ return rc;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * pre: c67x00 locked, urb unlocked
+ */
+static void
+c67x00_giveback_urb(struct c67x00_hcd *c67x00, struct urb *urb, int status)
+{
+ struct c67x00_urb_priv *urbp;
+
+ if (!urb)
+ return;
+
+ urbp = urb->hcpriv;
+ urbp->status = status;
+
+ list_del_init(&urbp->hep_node);
+
+ c67x00_release_urb(c67x00, urb);
+ usb_hcd_unlink_urb_from_ep(c67x00_hcd_to_hcd(c67x00), urb);
+ spin_unlock(&c67x00->lock);
+ usb_hcd_giveback_urb(c67x00_hcd_to_hcd(c67x00), urb, urbp->status);
+ spin_lock(&c67x00->lock);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_claim_frame_bw(struct c67x00_hcd *c67x00, struct urb *urb,
+ int len, int periodic)
+{
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+ int bit_time;
+
+ /* According to the C67x00 BIOS user manual, page 3-18,19, the
+ * following calculations provide the full speed bit times for
+ * a transaction.
+ *
+ * FS(in) = 112.5 + 9.36*BC + HOST_DELAY
+ * FS(in,iso) = 90.5 + 9.36*BC + HOST_DELAY
+ * FS(out) = 112.5 + 9.36*BC + HOST_DELAY
+ * FS(out,iso) = 78.4 + 9.36*BC + HOST_DELAY
+ * LS(in) = 802.4 + 75.78*BC + HOST_DELAY
+ * LS(out) = 802.6 + 74.67*BC + HOST_DELAY
+ *
+ * HOST_DELAY == 106 for the c67200 and c67300.
+ */
+
+ /* make calculations in 1/100 bit times to maintain resolution */
+ if (urbp->ep_data->dev->speed == USB_SPEED_LOW) {
+ /* Low speed pipe */
+ if (usb_pipein(urb->pipe))
+ bit_time = 80240 + 7578*len;
+ else
+ bit_time = 80260 + 7467*len;
+ } else {
+ /* FS pipes */
+ if (usb_pipeisoc(urb->pipe))
+ bit_time = usb_pipein(urb->pipe) ? 9050 : 7840;
+ else
+ bit_time = 11250;
+ bit_time += 936*len;
+ }
+
+ /* Scale back down to integer bit times. Use a host delay of 106.
+ * (this is the only place it is used) */
+ bit_time = ((bit_time+50) / 100) + 106;
+
+ if (unlikely(bit_time + c67x00->bandwidth_allocated >=
+ c67x00->max_frame_bw))
+ return -EMSGSIZE;
+
+ if (unlikely(c67x00->next_td_addr + CY_TD_SIZE >=
+ c67x00->td_base_addr + SIE_TD_SIZE))
+ return -EMSGSIZE;
+
+ if (unlikely(c67x00->next_buf_addr + len >=
+ c67x00->buf_base_addr + SIE_TD_BUF_SIZE))
+ return -EMSGSIZE;
+
+ if (periodic) {
+ if (unlikely(bit_time + c67x00->periodic_bw_allocated >=
+ MAX_PERIODIC_BW(c67x00->max_frame_bw)))
+ return -EMSGSIZE;
+ c67x00->periodic_bw_allocated += bit_time;
+ }
+
+ c67x00->bandwidth_allocated += bit_time;
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * td_addr and buf_addr must be word aligned
+ */
+static int c67x00_create_td(struct c67x00_hcd *c67x00, struct urb *urb,
+ void *data, int len, int pid, int toggle,
+ unsigned long privdata)
+{
+ struct c67x00_td *td;
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+ const __u8 active_flag = 1, retry_cnt = 1;
+ __u8 cmd = 0;
+ int tt = 0;
+
+ if (c67x00_claim_frame_bw(c67x00, urb, len, usb_pipeisoc(urb->pipe)
+ || usb_pipeint(urb->pipe)))
+ return -EMSGSIZE; /* Not really an error, but expected */
+
+ td = kzalloc(sizeof(*td), GFP_ATOMIC);
+ if (!td)
+ return -ENOMEM;
+
+ td->pipe = urb->pipe;
+ td->ep_data = urbp->ep_data;
+
+ if ((td_udev(td)->speed == USB_SPEED_LOW) &&
+ !(c67x00->low_speed_ports & (1 << urbp->port)))
+ cmd |= PREAMBLE_EN;
+
+ switch (usb_pipetype(td->pipe)) {
+ case PIPE_ISOCHRONOUS:
+ tt = TT_ISOCHRONOUS;
+ cmd |= ISO_EN;
+ break;
+ case PIPE_CONTROL:
+ tt = TT_CONTROL;
+ break;
+ case PIPE_BULK:
+ tt = TT_BULK;
+ break;
+ case PIPE_INTERRUPT:
+ tt = TT_INTERRUPT;
+ break;
+ }
+
+ if (toggle)
+ cmd |= SEQ_SEL;
+
+ cmd |= ARM_EN;
+
+ /* SW part */
+ td->td_addr = c67x00->next_td_addr;
+ c67x00->next_td_addr = c67x00->next_td_addr + CY_TD_SIZE;
+
+ /* HW part */
+ td->ly_base_addr = __cpu_to_le16(c67x00->next_buf_addr);
+ td->port_length = __cpu_to_le16((c67x00->sie->sie_num << 15) |
+ (urbp->port << 14) | (len & 0x3FF));
+ td->pid_ep = ((pid & 0xF) << TD_PIDEP_OFFSET) |
+ (usb_pipeendpoint(td->pipe) & 0xF);
+ td->dev_addr = usb_pipedevice(td->pipe) & 0x7F;
+ td->ctrl_reg = cmd;
+ td->status = 0;
+ td->retry_cnt = (tt << TT_OFFSET) | (active_flag << 4) | retry_cnt;
+ td->residue = 0;
+ td->next_td_addr = __cpu_to_le16(c67x00->next_td_addr);
+
+ /* SW part */
+ td->data = data;
+ td->urb = urb;
+ td->privdata = privdata;
+
+ c67x00->next_buf_addr += (len + 1) & ~0x01; /* properly align */
+
+ list_add_tail(&td->td_list, &c67x00->td_list);
+ return 0;
+}
+
+static inline void c67x00_release_td(struct c67x00_td *td)
+{
+ list_del_init(&td->td_list);
+ kfree(td);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int c67x00_add_data_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ int remaining;
+ int toggle;
+ int pid;
+ int ret = 0;
+ int maxps;
+ int need_empty;
+
+ toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe));
+ remaining = urb->transfer_buffer_length - urb->actual_length;
+
+ maxps = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+
+ need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
+ usb_pipeout(urb->pipe) && !(remaining % maxps);
+
+ while (remaining || need_empty) {
+ int len;
+ char *td_buf;
+
+ len = (remaining > maxps) ? maxps : remaining;
+ if (!len)
+ need_empty = 0;
+
+ pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+ td_buf = urb->transfer_buffer + urb->transfer_buffer_length -
+ remaining;
+ ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, toggle,
+ DATA_STAGE);
+ if (ret)
+ return ret; /* td wasn't created */
+
+ toggle ^= 1;
+ remaining -= len;
+ if (usb_pipecontrol(urb->pipe))
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * return 0 in case more bandwidth is available, else errorcode
+ */
+static int c67x00_add_ctrl_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ int ret;
+ int pid;
+
+ switch (urb->interval) {
+ default:
+ case SETUP_STAGE:
+ ret = c67x00_create_td(c67x00, urb, urb->setup_packet,
+ 8, USB_PID_SETUP, 0, SETUP_STAGE);
+ if (ret)
+ return ret;
+ urb->interval = SETUP_STAGE;
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe), 1);
+ break;
+ case DATA_STAGE:
+ if (urb->transfer_buffer_length) {
+ ret = c67x00_add_data_urb(c67x00, urb);
+ if (ret)
+ return ret;
+ break;
+ } /* else fallthrough */
+ case STATUS_STAGE:
+ pid = !usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+ ret = c67x00_create_td(c67x00, urb, NULL, 0, pid, 1,
+ STATUS_STAGE);
+ if (ret)
+ return ret;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * return 0 in case more bandwidth is available, else errorcode
+ */
+static int c67x00_add_int_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+
+ if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
+ urbp->ep_data->next_frame =
+ frame_add(urbp->ep_data->next_frame, urb->interval);
+ return c67x00_add_data_urb(c67x00, urb);
+ }
+ return 0;
+}
+
+static int c67x00_add_iso_urb(struct c67x00_hcd *c67x00, struct urb *urb)
+{
+ struct c67x00_urb_priv *urbp = urb->hcpriv;
+
+ if (frame_after_eq(c67x00->current_frame, urbp->ep_data->next_frame)) {
+ char *td_buf;
+ int len, pid, ret;
+
+ BUG_ON(urbp->cnt >= urb->number_of_packets);
+
+ td_buf = urb->transfer_buffer +
+ urb->iso_frame_desc[urbp->cnt].offset;
+ len = urb->iso_frame_desc[urbp->cnt].length;
+ pid = usb_pipeout(urb->pipe) ? USB_PID_OUT : USB_PID_IN;
+
+ ret = c67x00_create_td(c67x00, urb, td_buf, len, pid, 0,
+ urbp->cnt);
+ if (ret) {
+ printk(KERN_DEBUG "create failed: %d\n", ret);
+ urb->iso_frame_desc[urbp->cnt].actual_length = 0;
+ urb->iso_frame_desc[urbp->cnt].status = ret;
+ if (urbp->cnt + 1 == urb->number_of_packets)
+ c67x00_giveback_urb(c67x00, urb, 0);
+ }
+
+ urbp->ep_data->next_frame =
+ frame_add(urbp->ep_data->next_frame, urb->interval);
+ urbp->cnt++;
+ }
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_fill_from_list(struct c67x00_hcd *c67x00, int type,
+ int (*add)(struct c67x00_hcd *, struct urb *))
+{
+ struct c67x00_ep_data *ep_data;
+ struct urb *urb;
+
+ /* traverse every endpoint on the list */
+ list_for_each_entry(ep_data, &c67x00->list[type], node) {
+ if (!list_empty(&ep_data->queue)) {
+ /* and add the first urb */
+ /* isochronous transfer rely on this */
+ urb = list_entry(ep_data->queue.next,
+ struct c67x00_urb_priv,
+ hep_node)->urb;
+ add(c67x00, urb);
+ }
+ }
+}
+
+static void c67x00_fill_frame(struct c67x00_hcd *c67x00)
+{
+ struct c67x00_td *td, *ttd;
+
+ /* Check if we can proceed */
+ if (!list_empty(&c67x00->td_list)) {
+ dev_warn(c67x00_hcd_dev(c67x00),
+ "TD list not empty! This should not happen!\n");
+ list_for_each_entry_safe(td, ttd, &c67x00->td_list, td_list) {
+ dbg_td(c67x00, td, "Unprocessed td");
+ c67x00_release_td(td);
+ }
+ }
+
+ /* Reinitialize variables */
+ c67x00->bandwidth_allocated = 0;
+ c67x00->periodic_bw_allocated = 0;
+
+ c67x00->next_td_addr = c67x00->td_base_addr;
+ c67x00->next_buf_addr = c67x00->buf_base_addr;
+
+ /* Fill the list */
+ c67x00_fill_from_list(c67x00, PIPE_ISOCHRONOUS, c67x00_add_iso_urb);
+ c67x00_fill_from_list(c67x00, PIPE_INTERRUPT, c67x00_add_int_urb);
+ c67x00_fill_from_list(c67x00, PIPE_CONTROL, c67x00_add_ctrl_urb);
+ c67x00_fill_from_list(c67x00, PIPE_BULK, c67x00_add_data_urb);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * Get TD from C67X00
+ */
+static inline void
+c67x00_parse_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ c67x00_ll_read_mem_le16(c67x00->sie->dev,
+ td->td_addr, td, CY_TD_SIZE);
+
+ if (usb_pipein(td->pipe) && td_actual_bytes(td))
+ c67x00_ll_read_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+ td->data, td_actual_bytes(td));
+}
+
+static int c67x00_td_to_error(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ if (td->status & TD_STATUSMASK_ERR) {
+ dbg_td(c67x00, td, "ERROR_FLAG");
+ return -EILSEQ;
+ }
+ if (td->status & TD_STATUSMASK_STALL) {
+ /* dbg_td(c67x00, td, "STALL"); */
+ return -EPIPE;
+ }
+ if (td->status & TD_STATUSMASK_TMOUT) {
+ dbg_td(c67x00, td, "TIMEOUT");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static inline int c67x00_end_of_data(struct c67x00_td *td)
+{
+ int maxps, need_empty, remaining;
+ struct urb *urb = td->urb;
+ int act_bytes;
+
+ act_bytes = td_actual_bytes(td);
+
+ if (unlikely(!act_bytes))
+ return 1; /* This was an empty packet */
+
+ maxps = usb_maxpacket(td_udev(td), td->pipe, usb_pipeout(td->pipe));
+
+ if (unlikely(act_bytes < maxps))
+ return 1; /* Smaller then full packet */
+
+ remaining = urb->transfer_buffer_length - urb->actual_length;
+ need_empty = (urb->transfer_flags & URB_ZERO_PACKET) &&
+ usb_pipeout(urb->pipe) && !(remaining % maxps);
+
+ if (unlikely(!remaining && !need_empty))
+ return 1;
+
+ return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Remove all td's from the list which come
+ * after last_td and are meant for the same pipe.
+ * This is used when a short packet has occured */
+static inline void c67x00_clear_pipe(struct c67x00_hcd *c67x00,
+ struct c67x00_td *last_td)
+{
+ struct c67x00_td *td, *tmp;
+ td = last_td;
+ tmp = last_td;
+ while (td->td_list.next != &c67x00->td_list) {
+ td = list_entry(td->td_list.next, struct c67x00_td, td_list);
+ if (td->pipe == last_td->pipe) {
+ c67x00_release_td(td);
+ td = tmp;
+ }
+ tmp = td;
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_handle_successful_td(struct c67x00_hcd *c67x00,
+ struct c67x00_td *td)
+{
+ struct urb *urb = td->urb;
+
+ if (!urb)
+ return;
+
+ urb->actual_length += td_actual_bytes(td);
+
+ switch (usb_pipetype(td->pipe)) {
+ /* isochronous tds are handled separately */
+ case PIPE_CONTROL:
+ switch (td->privdata) {
+ case SETUP_STAGE:
+ urb->interval =
+ urb->transfer_buffer_length ?
+ DATA_STAGE : STATUS_STAGE;
+ /* Don't count setup_packet with normal data: */
+ urb->actual_length = 0;
+ break;
+
+ case DATA_STAGE:
+ if (c67x00_end_of_data(td)) {
+ urb->interval = STATUS_STAGE;
+ c67x00_clear_pipe(c67x00, td);
+ }
+ break;
+
+ case STATUS_STAGE:
+ urb->interval = 0;
+ c67x00_giveback_urb(c67x00, urb, 0);
+ break;
+ }
+ break;
+
+ case PIPE_INTERRUPT:
+ case PIPE_BULK:
+ if (unlikely(c67x00_end_of_data(td))) {
+ c67x00_clear_pipe(c67x00, td);
+ c67x00_giveback_urb(c67x00, urb, 0);
+ }
+ break;
+ }
+}
+
+static void c67x00_handle_isoc(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ struct urb *urb = td->urb;
+ struct c67x00_urb_priv *urbp;
+ int cnt;
+
+ if (!urb)
+ return;
+
+ urbp = urb->hcpriv;
+ cnt = td->privdata;
+
+ if (td->status & TD_ERROR_MASK)
+ urb->error_count++;
+
+ urb->iso_frame_desc[cnt].actual_length = td_actual_bytes(td);
+ urb->iso_frame_desc[cnt].status = c67x00_td_to_error(c67x00, td);
+ if (cnt + 1 == urb->number_of_packets) /* Last packet */
+ c67x00_giveback_urb(c67x00, urb, 0);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_check_td_list - handle tds which have been processed by the c67x00
+ * pre: current_td == 0
+ */
+static inline void c67x00_check_td_list(struct c67x00_hcd *c67x00)
+{
+ struct c67x00_td *td, *tmp;
+ struct urb *urb;
+ int ack_ok;
+ int clear_endpoint;
+
+ list_for_each_entry_safe(td, tmp, &c67x00->td_list, td_list) {
+ /* get the TD */
+ c67x00_parse_td(c67x00, td);
+ urb = td->urb; /* urb can be NULL! */
+ ack_ok = 0;
+ clear_endpoint = 1;
+
+ /* Handle isochronous transfers separately */
+ if (usb_pipeisoc(td->pipe)) {
+ clear_endpoint = 0;
+ c67x00_handle_isoc(c67x00, td);
+ goto cont;
+ }
+
+ /* When an error occurs, all td's for that pipe go into an
+ * inactive state. This state matches successful transfers so
+ * we must make sure not to service them. */
+ if (td->status & TD_ERROR_MASK) {
+ c67x00_giveback_urb(c67x00, urb,
+ c67x00_td_to_error(c67x00, td));
+ goto cont;
+ }
+
+ if ((td->status & TD_STATUSMASK_NAK) || !td_sequence_ok(td) ||
+ !td_acked(td))
+ goto cont;
+
+ /* Sequence ok and acked, don't need to fix toggle */
+ ack_ok = 1;
+
+ if (unlikely(td->status & TD_STATUSMASK_OVF)) {
+ if (td_residue(td) & TD_RESIDUE_OVERFLOW) {
+ /* Overflow */
+ c67x00_giveback_urb(c67x00, urb, -EOVERFLOW);
+ goto cont;
+ }
+ }
+
+ clear_endpoint = 0;
+ c67x00_handle_successful_td(c67x00, td);
+
+cont:
+ if (clear_endpoint)
+ c67x00_clear_pipe(c67x00, td);
+ if (ack_ok)
+ usb_settoggle(td_udev(td), usb_pipeendpoint(td->pipe),
+ usb_pipeout(td->pipe),
+ !(td->ctrl_reg & SEQ_SEL));
+ /* next in list could have been removed, due to clear_pipe! */
+ tmp = list_entry(td->td_list.next, typeof(*td), td_list);
+ c67x00_release_td(td);
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+static inline int c67x00_all_tds_processed(struct c67x00_hcd *c67x00)
+{
+ /* If all tds are processed, we can check the previous frame (if
+ * there was any) and start our next frame.
+ */
+ return !c67x00_ll_husb_get_current_td(c67x00->sie);
+}
+
+/**
+ * Send td to C67X00
+ */
+static void c67x00_send_td(struct c67x00_hcd *c67x00, struct c67x00_td *td)
+{
+ int len = td_length(td);
+
+ if (len && ((td->pid_ep & TD_PIDEPMASK_PID) != TD_PID_IN))
+ c67x00_ll_write_mem_le16(c67x00->sie->dev, td_ly_base_addr(td),
+ td->data, len);
+
+ c67x00_ll_write_mem_le16(c67x00->sie->dev,
+ td->td_addr, td, CY_TD_SIZE);
+}
+
+static void c67x00_send_frame(struct c67x00_hcd *c67x00)
+{
+ struct c67x00_td *td;
+
+ if (list_empty(&c67x00->td_list))
+ dev_warn(c67x00_hcd_dev(c67x00),
+ "%s: td list should not be empty here!\n",
+ __func__);
+
+ list_for_each_entry(td, &c67x00->td_list, td_list) {
+ if (td->td_list.next == &c67x00->td_list)
+ td->next_td_addr = 0; /* Last td in list */
+
+ c67x00_send_td(c67x00, td);
+ }
+
+ c67x00_ll_husb_set_current_td(c67x00->sie, c67x00->td_base_addr);
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * c67x00_do_work - Schedulers state machine
+ */
+static void c67x00_do_work(struct c67x00_hcd *c67x00)
+{
+ spin_lock(&c67x00->lock);
+ /* Make sure all tds are processed */
+ if (!c67x00_all_tds_processed(c67x00))
+ goto out;
+
+ c67x00_check_td_list(c67x00);
+
+ /* no td's are being processed (current == 0)
+ * and all have been "checked" */
+ complete(&c67x00->endpoint_disable);
+
+ if (!list_empty(&c67x00->td_list))
+ goto out;
+
+ c67x00->current_frame = c67x00_get_current_frame_number(c67x00);
+ if (c67x00->current_frame == c67x00->last_frame)
+ goto out; /* Don't send tds in same frame */
+ c67x00->last_frame = c67x00->current_frame;
+
+ /* If no urbs are scheduled, our work is done */
+ if (!c67x00->urb_count) {
+ c67x00_ll_hpi_disable_sofeop(c67x00->sie);
+ goto out;
+ }
+
+ c67x00_fill_frame(c67x00);
+ if (!list_empty(&c67x00->td_list))
+ /* TD's have been added to the frame */
+ c67x00_send_frame(c67x00);
+
+ out:
+ spin_unlock(&c67x00->lock);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static void c67x00_sched_tasklet(unsigned long __c67x00)
+{
+ struct c67x00_hcd *c67x00 = (struct c67x00_hcd *)__c67x00;
+ c67x00_do_work(c67x00);
+}
+
+void c67x00_sched_kick(struct c67x00_hcd *c67x00)
+{
+ tasklet_hi_schedule(&c67x00->tasklet);
+}
+
+int c67x00_sched_start_scheduler(struct c67x00_hcd *c67x00)
+{
+ tasklet_init(&c67x00->tasklet, c67x00_sched_tasklet,
+ (unsigned long)c67x00);
+ return 0;
+}
+
+void c67x00_sched_stop_scheduler(struct c67x00_hcd *c67x00)
+{
+ tasklet_kill(&c67x00->tasklet);
+}
diff --git a/drivers/usb/c67x00/c67x00.h b/drivers/usb/c67x00/c67x00.h
new file mode 100644
index 0000000..a26e9de
--- /dev/null
+++ b/drivers/usb/c67x00/c67x00.h
@@ -0,0 +1,294 @@
+/*
+ * c67x00.h: Cypress C67X00 USB register and field definitions
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ * Derived from the Cypress cy7c67200/300 ezusb linux driver and
+ * based on multiple host controller drivers inside the linux kernel.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#ifndef _USB_C67X00_H
+#define _USB_C67X00_H
+
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+
+/* ---------------------------------------------------------------------
+ * Cypress C67x00 register definitions
+ */
+
+/* Hardware Revision Register */
+#define HW_REV_REG 0xC004
+
+/* General USB registers */
+/* ===================== */
+
+/* USB Control Register */
+#define USB_CTL_REG(x) ((x) ? 0xC0AA : 0xC08A)
+
+#define LOW_SPEED_PORT(x) ((x) ? 0x0800 : 0x0400)
+#define HOST_MODE 0x0200
+#define PORT_RES_EN(x) ((x) ? 0x0100 : 0x0080)
+#define SOF_EOP_EN(x) ((x) ? 0x0002 : 0x0001)
+
+/* USB status register - Notice it has different content in hcd/udc mode */
+#define USB_STAT_REG(x) ((x) ? 0xC0B0 : 0xC090)
+
+#define EP0_IRQ_FLG 0x0001
+#define EP1_IRQ_FLG 0x0002
+#define EP2_IRQ_FLG 0x0004
+#define EP3_IRQ_FLG 0x0008
+#define EP4_IRQ_FLG 0x0010
+#define EP5_IRQ_FLG 0x0020
+#define EP6_IRQ_FLG 0x0040
+#define EP7_IRQ_FLG 0x0080
+#define RESET_IRQ_FLG 0x0100
+#define SOF_EOP_IRQ_FLG 0x0200
+#define ID_IRQ_FLG 0x4000
+#define VBUS_IRQ_FLG 0x8000
+
+/* USB Host only registers */
+/* ======================= */
+
+/* Host n Control Register */
+#define HOST_CTL_REG(x) ((x) ? 0xC0A0 : 0xC080)
+
+#define PREAMBLE_EN 0x0080 /* Preamble enable */
+#define SEQ_SEL 0x0040 /* Data Toggle Sequence Bit Select */
+#define ISO_EN 0x0010 /* Isochronous enable */
+#define ARM_EN 0x0001 /* Arm operation */
+
+/* Host n Interrupt Enable Register */
+#define HOST_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
+
+#define SOF_EOP_IRQ_EN 0x0200 /* SOF/EOP Interrupt Enable */
+#define SOF_EOP_TMOUT_IRQ_EN 0x0800 /* SOF/EOP Timeout Interrupt Enable */
+#define ID_IRQ_EN 0x4000 /* ID interrupt enable */
+#define VBUS_IRQ_EN 0x8000 /* VBUS interrupt enable */
+#define DONE_IRQ_EN 0x0001 /* Done Interrupt Enable */
+
+/* USB status register */
+#define HOST_STAT_MASK 0x02FD
+#define PORT_CONNECT_CHANGE(x) ((x) ? 0x0020 : 0x0010)
+#define PORT_SE0_STATUS(x) ((x) ? 0x0008 : 0x0004)
+
+/* Host Frame Register */
+#define HOST_FRAME_REG(x) ((x) ? 0xC0B6 : 0xC096)
+
+#define HOST_FRAME_MASK 0x07FF
+
+/* USB Peripheral only registers */
+/* ============================= */
+
+/* Device n Port Sel reg */
+#define DEVICE_N_PORT_SEL(x) ((x) ? 0xC0A4 : 0xC084)
+
+/* Device n Interrupt Enable Register */
+#define DEVICE_N_IRQ_EN_REG(x) ((x) ? 0xC0AC : 0xC08C)
+
+#define DEVICE_N_ENDPOINT_N_CTL_REG(dev, ep) ((dev) \
+ ? (0x0280 + (ep << 4)) \
+ : (0x0200 + (ep << 4)))
+#define DEVICE_N_ENDPOINT_N_STAT_REG(dev, ep) ((dev) \
+ ? (0x0286 + (ep << 4)) \
+ : (0x0206 + (ep << 4)))
+
+#define DEVICE_N_ADDRESS(dev) ((dev) ? (0xC0AE) : (0xC08E))
+
+/* HPI registers */
+/* ============= */
+
+/* HPI Status register */
+#define SOFEOP_FLG(x) (1 << ((x) ? 12 : 10))
+#define SIEMSG_FLG(x) (1 << (4 + (x)))
+#define RESET_FLG(x) ((x) ? 0x0200 : 0x0002)
+#define DONE_FLG(x) (1 << (2 + (x)))
+#define RESUME_FLG(x) (1 << (6 + (x)))
+#define MBX_OUT_FLG 0x0001 /* Message out available */
+#define MBX_IN_FLG 0x0100
+#define ID_FLG 0x4000
+#define VBUS_FLG 0x8000
+
+/* Interrupt routing register */
+#define HPI_IRQ_ROUTING_REG 0x0142
+
+#define HPI_SWAP_ENABLE(x) ((x) ? 0x0100 : 0x0001)
+#define RESET_TO_HPI_ENABLE(x) ((x) ? 0x0200 : 0x0002)
+#define DONE_TO_HPI_ENABLE(x) ((x) ? 0x0008 : 0x0004)
+#define RESUME_TO_HPI_ENABLE(x) ((x) ? 0x0080 : 0x0040)
+#define SOFEOP_TO_HPI_EN(x) ((x) ? 0x2000 : 0x0800)
+#define SOFEOP_TO_CPU_EN(x) ((x) ? 0x1000 : 0x0400)
+#define ID_TO_HPI_ENABLE 0x4000
+#define VBUS_TO_HPI_ENABLE 0x8000
+
+/* SIE msg registers */
+#define SIEMSG_REG(x) ((x) ? 0x0148 : 0x0144)
+
+#define HUSB_TDListDone 0x1000
+
+#define SUSB_EP0_MSG 0x0001
+#define SUSB_EP1_MSG 0x0002
+#define SUSB_EP2_MSG 0x0004
+#define SUSB_EP3_MSG 0x0008
+#define SUSB_EP4_MSG 0x0010
+#define SUSB_EP5_MSG 0x0020
+#define SUSB_EP6_MSG 0x0040
+#define SUSB_EP7_MSG 0x0080
+#define SUSB_RST_MSG 0x0100
+#define SUSB_SOF_MSG 0x0200
+#define SUSB_CFG_MSG 0x0400
+#define SUSB_SUS_MSG 0x0800
+#define SUSB_ID_MSG 0x4000
+#define SUSB_VBUS_MSG 0x8000
+
+/* BIOS interrupt routines */
+
+#define SUSBx_RECEIVE_INT(x) ((x) ? 97 : 81)
+#define SUSBx_SEND_INT(x) ((x) ? 96 : 80)
+
+#define SUSBx_DEV_DESC_VEC(x) ((x) ? 0x00D4 : 0x00B4)
+#define SUSBx_CONF_DESC_VEC(x) ((x) ? 0x00D6 : 0x00B6)
+#define SUSBx_STRING_DESC_VEC(x) ((x) ? 0x00D8 : 0x00B8)
+
+#define CY_HCD_BUF_ADDR 0x500 /* Base address for host */
+#define SIE_TD_SIZE 0x200 /* size of the td list */
+#define SIE_TD_BUF_SIZE 0x400 /* size of the data buffer */
+
+#define SIE_TD_OFFSET(host) ((host) ? (SIE_TD_SIZE+SIE_TD_BUF_SIZE) : 0)
+#define SIE_BUF_OFFSET(host) (SIE_TD_OFFSET(host) + SIE_TD_SIZE)
+
+/* Base address of HCD + 2 x TD_SIZE + 2 x TD_BUF_SIZE */
+#define CY_UDC_REQ_HEADER_BASE 0x1100
+/* 8- byte request headers for IN/OUT transfers */
+#define CY_UDC_REQ_HEADER_SIZE 8
+
+#define CY_UDC_REQ_HEADER_ADDR(ep_num) (CY_UDC_REQ_HEADER_BASE + \
+ ((ep_num) * CY_UDC_REQ_HEADER_SIZE))
+#define CY_UDC_DESC_BASE_ADDRESS (CY_UDC_REQ_HEADER_ADDR(8))
+
+#define CY_UDC_BIOS_REPLACE_BASE 0x1800
+#define CY_UDC_REQ_BUFFER_BASE 0x2000
+#define CY_UDC_REQ_BUFFER_SIZE 0x0400
+#define CY_UDC_REQ_BUFFER_ADDR(ep_num) (CY_UDC_REQ_BUFFER_BASE + \
+ ((ep_num) * CY_UDC_REQ_BUFFER_SIZE))
+
+/* ---------------------------------------------------------------------
+ * Driver data structures
+ */
+
+struct c67x00_device;
+
+/**
+ * struct c67x00_sie - Common data associated with a SIE
+ * @lock: lock to protect this struct and the associated chip registers
+ * @private_data: subdriver dependent data
+ * @irq: subdriver dependent irq handler, set NULL when not used
+ * @dev: link to common driver structure
+ * @sie_num: SIE number on chip, starting from 0
+ * @mode: SIE mode (host/peripheral/otg/not used)
+ */
+struct c67x00_sie {
+ /* Entries to be used by the subdrivers */
+ spinlock_t lock; /* protect this structure */
+ void *private_data;
+ void (*irq) (struct c67x00_sie *sie, u16 int_status, u16 msg);
+
+ /* Read only: */
+ struct c67x00_device *dev;
+ int sie_num;
+ int mode;
+};
+
+#define sie_dev(s) (&(s)->dev->pdev->dev)
+
+/**
+ * struct c67x00_lcp
+ */
+struct c67x00_lcp {
+ /* Internal use only */
+ struct mutex mutex;
+ struct completion msg_received;
+ u16 last_msg;
+};
+
+/*
+ * struct c67x00_hpi
+ */
+struct c67x00_hpi {
+ void __iomem *base;
+ int regstep;
+ spinlock_t lock;
+ struct c67x00_lcp lcp;
+};
+
+#define C67X00_SIES 2
+#define C67X00_PORTS 2
+
+/**
+ * struct c67x00_device - Common data associated with a c67x00 instance
+ * @hpi: hpi addresses
+ * @sie: array of sie's on this chip
+ * @pdev: platform device of instance
+ * @pdata: configuration provided by the platform
+ */
+struct c67x00_device {
+ struct c67x00_hpi hpi;
+ struct c67x00_sie sie[C67X00_SIES];
+ struct platform_device *pdev;
+ struct c67x00_platform_data *pdata;
+};
+
+/* ---------------------------------------------------------------------
+ * Low level interface functions
+ */
+
+/* Host Port Interface (HPI) functions */
+u16 c67x00_ll_hpi_status(struct c67x00_device *dev);
+void c67x00_ll_hpi_reg_init(struct c67x00_device *dev);
+void c67x00_ll_hpi_enable_sofeop(struct c67x00_sie *sie);
+void c67x00_ll_hpi_disable_sofeop(struct c67x00_sie *sie);
+
+/* General functions */
+u16 c67x00_ll_fetch_siemsg(struct c67x00_device *dev, int sie_num);
+u16 c67x00_ll_get_usb_ctl(struct c67x00_sie *sie);
+void c67x00_ll_usb_clear_status(struct c67x00_sie *sie, u16 bits);
+u16 c67x00_ll_usb_get_status(struct c67x00_sie *sie);
+void c67x00_ll_write_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len);
+void c67x00_ll_read_mem_le16(struct c67x00_device *dev, u16 addr,
+ void *data, int len);
+
+/* Host specific functions */
+void c67x00_ll_set_husb_eot(struct c67x00_device *dev, u16 value);
+void c67x00_ll_husb_reset(struct c67x00_sie *sie, int port);
+void c67x00_ll_husb_set_current_td(struct c67x00_sie *sie, u16 addr);
+u16 c67x00_ll_husb_get_current_td(struct c67x00_sie *sie);
+u16 c67x00_ll_husb_get_frame(struct c67x00_sie *sie);
+void c67x00_ll_husb_init_host_port(struct c67x00_sie *sie);
+void c67x00_ll_husb_reset_port(struct c67x00_sie *sie, int port);
+
+/* Called by c67x00_irq to handle lcp interrupts */
+void c67x00_ll_irq(struct c67x00_device *dev, u16 int_status);
+
+/* Setup and teardown */
+void c67x00_ll_init(struct c67x00_device *dev);
+void c67x00_ll_release(struct c67x00_device *dev);
+int c67x00_ll_reset(struct c67x00_device *dev);
+
+#endif /* _USB_C67X00_H */
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 7b572e7..cefe7f2 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -280,7 +280,7 @@
case USB_CDC_NOTIFY_SERIAL_STATE:
- newctrl = le16_to_cpu(get_unaligned((__le16 *) data));
+ newctrl = get_unaligned_le16(data);
if (acm->tty && !acm->clocal && (acm->ctrlin & ~newctrl & ACM_CTRL_DCD)) {
dbg("calling hangup");
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 8607846..1d253dd 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -773,7 +773,7 @@
usb_register_notify(&usbfs_nb);
/* create mount point for usbfs */
- usbdir = proc_mkdir("usb", proc_bus);
+ usbdir = proc_mkdir("bus/usb", NULL);
return 0;
}
@@ -783,6 +783,6 @@
usb_unregister_notify(&usbfs_nb);
unregister_filesystem(&usb_fs_type);
if (usbdir)
- remove_proc_entry("usb", proc_bus);
+ remove_proc_entry("bus/usb", NULL);
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index e819e53..3e69266 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -394,7 +394,9 @@
if (!io->urbs)
goto nomem;
- urb_flags = URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT;
+ urb_flags = URB_NO_INTERRUPT;
+ if (dma)
+ urb_flags |= URB_NO_TRANSFER_DMA_MAP;
if (usb_pipein(pipe))
urb_flags |= URB_SHORT_NOT_OK;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index f7b5465..6e784d2 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -231,6 +231,26 @@
However, this problem is improved if change a value of
NET_IP_ALIGN to 4.
+config USB_GADGET_PXA27X
+ boolean "PXA 27x"
+ depends on ARCH_PXA && PXA27x
+ help
+ Intel's PXA 27x series XScale ARM v5TE processors include
+ an integrated full speed USB 1.1 device controller.
+
+ It has up to 23 endpoints, as well as endpoint zero (for
+ control transfers).
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "pxa27x_udc" and force all
+ gadget drivers to also be dynamically linked.
+
+config USB_PXA27X
+ tristate
+ depends on USB_GADGET_PXA27X
+ default USB_GADGET
+ select USB_GADGET_SELECTED
+
config USB_GADGET_GOKU
boolean "Toshiba TC86C001 'Goku-S'"
depends on PCI
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index c3aab80..1235725 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -9,6 +9,7 @@
obj-$(CONFIG_USB_NET2280) += net2280.o
obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o
obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o
+obj-$(CONFIG_USB_PXA27X) += pxa27x_udc.o
obj-$(CONFIG_USB_GOKU) += goku_udc.o
obj-$(CONFIG_USB_OMAP) += omap_udc.o
obj-$(CONFIG_USB_LH7A40X) += lh7a40x_udc.o
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 9b913af..274c60a 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -231,6 +231,7 @@
}
static const struct file_operations proc_ops = {
+ .owner = THIS_MODULE,
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -239,15 +240,7 @@
static void create_debug_file(struct at91_udc *udc)
{
- struct proc_dir_entry *pde;
-
- pde = create_proc_entry (debug_filename, 0, NULL);
- udc->pde = pde;
- if (pde == NULL)
- return;
-
- pde->proc_fops = &proc_ops;
- pde->data = udc;
+ udc->pde = proc_create_data(debug_filename, 0, NULL, &proc_ops, udc);
}
static void remove_debug_file(struct at91_udc *udc)
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index bb93bdd..8d61ea6 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -235,10 +235,6 @@
#define DEV_CONFIG_CDC
#endif
-#ifdef CONFIG_USB_GADGET_PXA27X
-#define DEV_CONFIG_CDC
-#endif
-
#ifdef CONFIG_USB_GADGET_S3C2410
#define DEV_CONFIG_CDC
#endif
@@ -270,6 +266,10 @@
#define DEV_CONFIG_SUBSET
#endif
+#ifdef CONFIG_USB_GADGET_PXA27X
+#define DEV_CONFIG_SUBSET
+#endif
+
#ifdef CONFIG_USB_GADGET_SUPERH
#define DEV_CONFIG_SUBSET
#endif
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index bf3f946..47bb9f0 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -2307,6 +2307,29 @@
return rc;
}
+static int wedge_bulk_in_endpoint(struct fsg_dev *fsg)
+{
+ int rc;
+
+ DBG(fsg, "bulk-in set wedge\n");
+ rc = usb_ep_set_wedge(fsg->bulk_in);
+ if (rc == -EAGAIN)
+ VDBG(fsg, "delayed bulk-in endpoint wedge\n");
+ while (rc != 0) {
+ if (rc != -EAGAIN) {
+ WARN(fsg, "usb_ep_set_wedge -> %d\n", rc);
+ rc = 0;
+ break;
+ }
+
+ /* Wait for a short time and then try again */
+ if (msleep_interruptible(100) != 0)
+ return -EINTR;
+ rc = usb_ep_set_wedge(fsg->bulk_in);
+ }
+ return rc;
+}
+
static int pad_with_zeros(struct fsg_dev *fsg)
{
struct fsg_buffhd *bh = fsg->next_buffhd_to_fill;
@@ -2957,7 +2980,7 @@
* We aren't required to halt the OUT endpoint; instead
* we can simply accept and discard any data received
* until the next reset. */
- halt_bulk_in_endpoint(fsg);
+ wedge_bulk_in_endpoint(fsg);
set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
return -EINVAL;
}
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 64a592c..be6613a 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -127,7 +127,7 @@
/* enabling the no-toggle interrupt mode would need an api hook */
mode = 0;
- max = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize));
+ max = get_unaligned_le16(&desc->wMaxPacketSize);
switch (max) {
case 64: mode++;
case 32: mode++;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 95f7662..881d74c 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2504,6 +2504,7 @@
}
static const struct file_operations proc_ops = {
+ .owner = THIS_MODULE,
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -2512,11 +2513,7 @@
static void create_proc_file(void)
{
- struct proc_dir_entry *pde;
-
- pde = create_proc_entry (proc_filename, 0, NULL);
- if (pde)
- pde->proc_fops = &proc_ops;
+ proc_create(proc_filename, 0, NULL, &proc_ops);
}
static void remove_proc_file(void)
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
new file mode 100644
index 0000000..75eba20
--- /dev/null
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -0,0 +1,2404 @@
+/*
+ * Handles the Intel 27x USB Device Controller (UDC)
+ *
+ * Inspired by original driver by Frank Becker, David Brownell, and others.
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/irq.h>
+
+#include <asm/byteorder.h>
+#include <asm/hardware.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/arch/udc.h>
+
+#include "pxa27x_udc.h"
+
+/*
+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 27x
+ * series processors.
+ *
+ * Such controller drivers work with a gadget driver. The gadget driver
+ * returns descriptors, implements configuration and data protocols used
+ * by the host to interact with this device, and allocates endpoints to
+ * the different protocol interfaces. The controller driver virtualizes
+ * usb hardware so that the gadget drivers will be more portable.
+ *
+ * This UDC hardware wants to implement a bit too much USB protocol. The
+ * biggest issues are: that the endpoints have to be set up before the
+ * controller can be enabled (minor, and not uncommon); and each endpoint
+ * can only have one configuration, interface and alternative interface
+ * number (major, and very unusual). Once set up, these cannot be changed
+ * without a controller reset.
+ *
+ * The workaround is to setup all combinations necessary for the gadgets which
+ * will work with this driver. This is done in pxa_udc structure, statically.
+ * See pxa_udc, udc_usb_ep versus pxa_ep, and matching function find_pxa_ep.
+ * (You could modify this if needed. Some drivers have a "fifo_mode" module
+ * parameter to facilitate such changes.)
+ *
+ * The combinations have been tested with these gadgets :
+ * - zero gadget
+ * - file storage gadget
+ * - ether gadget
+ *
+ * The driver doesn't use DMA, only IO access and IRQ callbacks. No use is
+ * made of UDC's double buffering either. USB "On-The-Go" is not implemented.
+ *
+ * All the requests are handled the same way :
+ * - the drivers tries to handle the request directly to the IO
+ * - if the IO fifo is not big enough, the remaining is send/received in
+ * interrupt handling.
+ */
+
+#define DRIVER_VERSION "2008-04-18"
+#define DRIVER_DESC "PXA 27x USB Device Controller driver"
+
+static const char driver_name[] = "pxa27x_udc";
+static struct pxa_udc *the_controller;
+
+static void handle_ep(struct pxa_ep *ep);
+
+/*
+ * Debug filesystem
+ */
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+
+static int state_dbg_show(struct seq_file *s, void *p)
+{
+ struct pxa_udc *udc = s->private;
+ int pos = 0, ret;
+ u32 tmp;
+
+ ret = -ENODEV;
+ if (!udc->driver)
+ goto out;
+
+ /* basic device status */
+ pos += seq_printf(s, DRIVER_DESC "\n"
+ "%s version: %s\nGadget driver: %s\n",
+ driver_name, DRIVER_VERSION,
+ udc->driver ? udc->driver->driver.name : "(none)");
+
+ tmp = udc_readl(udc, UDCCR);
+ pos += seq_printf(s,
+ "udccr=0x%0x(%s%s%s%s%s%s%s%s%s%s), "
+ "con=%d,inter=%d,altinter=%d\n", tmp,
+ (tmp & UDCCR_OEN) ? " oen":"",
+ (tmp & UDCCR_AALTHNP) ? " aalthnp":"",
+ (tmp & UDCCR_AHNP) ? " rem" : "",
+ (tmp & UDCCR_BHNP) ? " rstir" : "",
+ (tmp & UDCCR_DWRE) ? " dwre" : "",
+ (tmp & UDCCR_SMAC) ? " smac" : "",
+ (tmp & UDCCR_EMCE) ? " emce" : "",
+ (tmp & UDCCR_UDR) ? " udr" : "",
+ (tmp & UDCCR_UDA) ? " uda" : "",
+ (tmp & UDCCR_UDE) ? " ude" : "",
+ (tmp & UDCCR_ACN) >> UDCCR_ACN_S,
+ (tmp & UDCCR_AIN) >> UDCCR_AIN_S,
+ (tmp & UDCCR_AAISN) >> UDCCR_AAISN_S);
+ /* registers for device and ep0 */
+ pos += seq_printf(s, "udcicr0=0x%08x udcicr1=0x%08x\n",
+ udc_readl(udc, UDCICR0), udc_readl(udc, UDCICR1));
+ pos += seq_printf(s, "udcisr0=0x%08x udcisr1=0x%08x\n",
+ udc_readl(udc, UDCISR0), udc_readl(udc, UDCISR1));
+ pos += seq_printf(s, "udcfnr=%d\n", udc_readl(udc, UDCFNR));
+ pos += seq_printf(s, "irqs: reset=%lu, suspend=%lu, resume=%lu, "
+ "reconfig=%lu\n",
+ udc->stats.irqs_reset, udc->stats.irqs_suspend,
+ udc->stats.irqs_resume, udc->stats.irqs_reconfig);
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int queues_dbg_show(struct seq_file *s, void *p)
+{
+ struct pxa_udc *udc = s->private;
+ struct pxa_ep *ep;
+ struct pxa27x_request *req;
+ int pos = 0, i, maxpkt, ret;
+
+ ret = -ENODEV;
+ if (!udc->driver)
+ goto out;
+
+ /* dump endpoint queues */
+ for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ maxpkt = ep->fifo_size;
+ pos += seq_printf(s, "%-12s max_pkt=%d %s\n",
+ EPNAME(ep), maxpkt, "pio");
+
+ if (list_empty(&ep->queue)) {
+ pos += seq_printf(s, "\t(nothing queued)\n");
+ continue;
+ }
+
+ list_for_each_entry(req, &ep->queue, queue) {
+ pos += seq_printf(s, "\treq %p len %d/%d buf %p\n",
+ &req->req, req->req.actual,
+ req->req.length, req->req.buf);
+ }
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int eps_dbg_show(struct seq_file *s, void *p)
+{
+ struct pxa_udc *udc = s->private;
+ struct pxa_ep *ep;
+ int pos = 0, i, ret;
+ u32 tmp;
+
+ ret = -ENODEV;
+ if (!udc->driver)
+ goto out;
+
+ ep = &udc->pxa_ep[0];
+ tmp = udc_ep_readl(ep, UDCCSR);
+ pos += seq_printf(s, "udccsr0=0x%03x(%s%s%s%s%s%s%s)\n", tmp,
+ (tmp & UDCCSR0_SA) ? " sa" : "",
+ (tmp & UDCCSR0_RNE) ? " rne" : "",
+ (tmp & UDCCSR0_FST) ? " fst" : "",
+ (tmp & UDCCSR0_SST) ? " sst" : "",
+ (tmp & UDCCSR0_DME) ? " dme" : "",
+ (tmp & UDCCSR0_IPR) ? " ipr" : "",
+ (tmp & UDCCSR0_OPC) ? " opc" : "");
+ for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ tmp = i? udc_ep_readl(ep, UDCCR) : udc_readl(udc, UDCCR);
+ pos += seq_printf(s, "%-12s: "
+ "IN %lu(%lu reqs), OUT %lu(%lu reqs), "
+ "irqs=%lu, udccr=0x%08x, udccsr=0x%03x, "
+ "udcbcr=%d\n",
+ EPNAME(ep),
+ ep->stats.in_bytes, ep->stats.in_ops,
+ ep->stats.out_bytes, ep->stats.out_ops,
+ ep->stats.irqs,
+ tmp, udc_ep_readl(ep, UDCCSR),
+ udc_ep_readl(ep, UDCBCR));
+ }
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static int eps_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, eps_dbg_show, inode->i_private);
+}
+
+static int queues_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, queues_dbg_show, inode->i_private);
+}
+
+static int state_dbg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, state_dbg_show, inode->i_private);
+}
+
+static const struct file_operations state_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = state_dbg_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static const struct file_operations queues_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = queues_dbg_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static const struct file_operations eps_dbg_fops = {
+ .owner = THIS_MODULE,
+ .open = eps_dbg_open,
+ .llseek = seq_lseek,
+ .read = seq_read,
+ .release = single_release,
+};
+
+static void pxa_init_debugfs(struct pxa_udc *udc)
+{
+ struct dentry *root, *state, *queues, *eps;
+
+ root = debugfs_create_dir(udc->gadget.name, NULL);
+ if (IS_ERR(root) || !root)
+ goto err_root;
+
+ state = debugfs_create_file("udcstate", 0400, root, udc,
+ &state_dbg_fops);
+ if (!state)
+ goto err_state;
+ queues = debugfs_create_file("queues", 0400, root, udc,
+ &queues_dbg_fops);
+ if (!queues)
+ goto err_queues;
+ eps = debugfs_create_file("epstate", 0400, root, udc,
+ &eps_dbg_fops);
+ if (!queues)
+ goto err_eps;
+
+ udc->debugfs_root = root;
+ udc->debugfs_state = state;
+ udc->debugfs_queues = queues;
+ udc->debugfs_eps = eps;
+ return;
+err_eps:
+ debugfs_remove(eps);
+err_queues:
+ debugfs_remove(queues);
+err_state:
+ debugfs_remove(root);
+err_root:
+ dev_err(udc->dev, "debugfs is not available\n");
+}
+
+static void pxa_cleanup_debugfs(struct pxa_udc *udc)
+{
+ debugfs_remove(udc->debugfs_eps);
+ debugfs_remove(udc->debugfs_queues);
+ debugfs_remove(udc->debugfs_state);
+ debugfs_remove(udc->debugfs_root);
+ udc->debugfs_eps = NULL;
+ udc->debugfs_queues = NULL;
+ udc->debugfs_state = NULL;
+ udc->debugfs_root = NULL;
+}
+
+#else
+static inline void pxa_init_debugfs(struct pxa_udc *udc)
+{
+}
+
+static inline void pxa_cleanup_debugfs(struct pxa_udc *udc)
+{
+}
+#endif
+
+/**
+ * is_match_usb_pxa - check if usb_ep and pxa_ep match
+ * @udc_usb_ep: usb endpoint
+ * @ep: pxa endpoint
+ * @config: configuration required in pxa_ep
+ * @interface: interface required in pxa_ep
+ * @altsetting: altsetting required in pxa_ep
+ *
+ * Returns 1 if all criteria match between pxa and usb endpoint, 0 otherwise
+ */
+static int is_match_usb_pxa(struct udc_usb_ep *udc_usb_ep, struct pxa_ep *ep,
+ int config, int interface, int altsetting)
+{
+ if (usb_endpoint_num(&udc_usb_ep->desc) != ep->addr)
+ return 0;
+ if (usb_endpoint_dir_in(&udc_usb_ep->desc) != ep->dir_in)
+ return 0;
+ if (usb_endpoint_type(&udc_usb_ep->desc) != ep->type)
+ return 0;
+ if ((ep->config != config) || (ep->interface != interface)
+ || (ep->alternate != altsetting))
+ return 0;
+ return 1;
+}
+
+/**
+ * find_pxa_ep - find pxa_ep structure matching udc_usb_ep
+ * @udc: pxa udc
+ * @udc_usb_ep: udc_usb_ep structure
+ *
+ * Match udc_usb_ep and all pxa_ep available, to see if one matches.
+ * This is necessary because of the strong pxa hardware restriction requiring
+ * that once pxa endpoints are initialized, their configuration is freezed, and
+ * no change can be made to their address, direction, or in which configuration,
+ * interface or altsetting they are active ... which differs from more usual
+ * models which have endpoints be roughly just addressable fifos, and leave
+ * configuration events up to gadget drivers (like all control messages).
+ *
+ * Note that there is still a blurred point here :
+ * - we rely on UDCCR register "active interface" and "active altsetting".
+ * This is a nonsense in regard of USB spec, where multiple interfaces are
+ * active at the same time.
+ * - if we knew for sure that the pxa can handle multiple interface at the
+ * same time, assuming Intel's Developer Guide is wrong, this function
+ * should be reviewed, and a cache of couples (iface, altsetting) should
+ * be kept in the pxa_udc structure. In this case this function would match
+ * against the cache of couples instead of the "last altsetting" set up.
+ *
+ * Returns the matched pxa_ep structure or NULL if none found
+ */
+static struct pxa_ep *find_pxa_ep(struct pxa_udc *udc,
+ struct udc_usb_ep *udc_usb_ep)
+{
+ int i;
+ struct pxa_ep *ep;
+ int cfg = udc->config;
+ int iface = udc->last_interface;
+ int alt = udc->last_alternate;
+
+ if (udc_usb_ep == &udc->udc_usb_ep[0])
+ return &udc->pxa_ep[0];
+
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ if (is_match_usb_pxa(udc_usb_ep, ep, cfg, iface, alt))
+ return ep;
+ }
+ return NULL;
+}
+
+/**
+ * update_pxa_ep_matches - update pxa_ep cached values in all udc_usb_ep
+ * @udc: pxa udc
+ *
+ * Context: in_interrupt()
+ *
+ * Updates all pxa_ep fields in udc_usb_ep structures, if this field was
+ * previously set up (and is not NULL). The update is necessary is a
+ * configuration change or altsetting change was issued by the USB host.
+ */
+static void update_pxa_ep_matches(struct pxa_udc *udc)
+{
+ int i;
+ struct udc_usb_ep *udc_usb_ep;
+
+ for (i = 1; i < NR_USB_ENDPOINTS; i++) {
+ udc_usb_ep = &udc->udc_usb_ep[i];
+ if (udc_usb_ep->pxa_ep)
+ udc_usb_ep->pxa_ep = find_pxa_ep(udc, udc_usb_ep);
+ }
+}
+
+/**
+ * pio_irq_enable - Enables irq generation for one endpoint
+ * @ep: udc endpoint
+ */
+static void pio_irq_enable(struct pxa_ep *ep)
+{
+ struct pxa_udc *udc = ep->dev;
+ int index = EPIDX(ep);
+ u32 udcicr0 = udc_readl(udc, UDCICR0);
+ u32 udcicr1 = udc_readl(udc, UDCICR1);
+
+ if (index < 16)
+ udc_writel(udc, UDCICR0, udcicr0 | (3 << (index * 2)));
+ else
+ udc_writel(udc, UDCICR1, udcicr1 | (3 << ((index - 16) * 2)));
+}
+
+/**
+ * pio_irq_disable - Disables irq generation for one endpoint
+ * @ep: udc endpoint
+ * @index: endpoint number
+ */
+static void pio_irq_disable(struct pxa_ep *ep)
+{
+ struct pxa_udc *udc = ep->dev;
+ int index = EPIDX(ep);
+ u32 udcicr0 = udc_readl(udc, UDCICR0);
+ u32 udcicr1 = udc_readl(udc, UDCICR1);
+
+ if (index < 16)
+ udc_writel(udc, UDCICR0, udcicr0 & ~(3 << (index * 2)));
+ else
+ udc_writel(udc, UDCICR1, udcicr1 & ~(3 << ((index - 16) * 2)));
+}
+
+/**
+ * udc_set_mask_UDCCR - set bits in UDCCR
+ * @udc: udc device
+ * @mask: bits to set in UDCCR
+ *
+ * Sets bits in UDCCR, leaving DME and FST bits as they were.
+ */
+static inline void udc_set_mask_UDCCR(struct pxa_udc *udc, int mask)
+{
+ u32 udccr = udc_readl(udc, UDCCR);
+ udc_writel(udc, UDCCR,
+ (udccr & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS));
+}
+
+/**
+ * udc_clear_mask_UDCCR - clears bits in UDCCR
+ * @udc: udc device
+ * @mask: bit to clear in UDCCR
+ *
+ * Clears bits in UDCCR, leaving DME and FST bits as they were.
+ */
+static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask)
+{
+ u32 udccr = udc_readl(udc, UDCCR);
+ udc_writel(udc, UDCCR,
+ (udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS));
+}
+
+/**
+ * ep_count_bytes_remain - get how many bytes in udc endpoint
+ * @ep: udc endpoint
+ *
+ * Returns number of bytes in OUT fifos. Broken for IN fifos (-EOPNOTSUPP)
+ */
+static int ep_count_bytes_remain(struct pxa_ep *ep)
+{
+ if (ep->dir_in)
+ return -EOPNOTSUPP;
+ return udc_ep_readl(ep, UDCBCR) & 0x3ff;
+}
+
+/**
+ * ep_is_empty - checks if ep has byte ready for reading
+ * @ep: udc endpoint
+ *
+ * If endpoint is the control endpoint, checks if there are bytes in the
+ * control endpoint fifo. If endpoint is a data endpoint, checks if bytes
+ * are ready for reading on OUT endpoint.
+ *
+ * Returns 0 if ep not empty, 1 if ep empty, -EOPNOTSUPP if IN endpoint
+ */
+static int ep_is_empty(struct pxa_ep *ep)
+{
+ int ret;
+
+ if (!is_ep0(ep) && ep->dir_in)
+ return -EOPNOTSUPP;
+ if (is_ep0(ep))
+ ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR0_RNE);
+ else
+ ret = !(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNE);
+ return ret;
+}
+
+/**
+ * ep_is_full - checks if ep has place to write bytes
+ * @ep: udc endpoint
+ *
+ * If endpoint is not the control endpoint and is an IN endpoint, checks if
+ * there is place to write bytes into the endpoint.
+ *
+ * Returns 0 if ep not full, 1 if ep full, -EOPNOTSUPP if OUT endpoint
+ */
+static int ep_is_full(struct pxa_ep *ep)
+{
+ if (is_ep0(ep))
+ return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_IPR);
+ if (!ep->dir_in)
+ return -EOPNOTSUPP;
+ return (!(udc_ep_readl(ep, UDCCSR) & UDCCSR_BNF));
+}
+
+/**
+ * epout_has_pkt - checks if OUT endpoint fifo has a packet available
+ * @ep: pxa endpoint
+ *
+ * Returns 1 if a complete packet is available, 0 if not, -EOPNOTSUPP for IN ep.
+ */
+static int epout_has_pkt(struct pxa_ep *ep)
+{
+ if (!is_ep0(ep) && ep->dir_in)
+ return -EOPNOTSUPP;
+ if (is_ep0(ep))
+ return (udc_ep_readl(ep, UDCCSR) & UDCCSR0_OPC);
+ return (udc_ep_readl(ep, UDCCSR) & UDCCSR_PC);
+}
+
+/**
+ * set_ep0state - Set ep0 automata state
+ * @dev: udc device
+ * @state: state
+ */
+static void set_ep0state(struct pxa_udc *udc, int state)
+{
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+ char *old_stname = EP0_STNAME(udc);
+
+ udc->ep0state = state;
+ ep_dbg(ep, "state=%s->%s, udccsr0=0x%03x, udcbcr=%d\n", old_stname,
+ EP0_STNAME(udc), udc_ep_readl(ep, UDCCSR),
+ udc_ep_readl(ep, UDCBCR));
+}
+
+/**
+ * ep0_idle - Put control endpoint into idle state
+ * @dev: udc device
+ */
+static void ep0_idle(struct pxa_udc *dev)
+{
+ set_ep0state(dev, WAIT_FOR_SETUP);
+}
+
+/**
+ * inc_ep_stats_reqs - Update ep stats counts
+ * @ep: physical endpoint
+ * @req: usb request
+ * @is_in: ep direction (USB_DIR_IN or 0)
+ *
+ */
+static void inc_ep_stats_reqs(struct pxa_ep *ep, int is_in)
+{
+ if (is_in)
+ ep->stats.in_ops++;
+ else
+ ep->stats.out_ops++;
+}
+
+/**
+ * inc_ep_stats_bytes - Update ep stats counts
+ * @ep: physical endpoint
+ * @count: bytes transfered on endpoint
+ * @req: usb request
+ * @is_in: ep direction (USB_DIR_IN or 0)
+ */
+static void inc_ep_stats_bytes(struct pxa_ep *ep, int count, int is_in)
+{
+ if (is_in)
+ ep->stats.in_bytes += count;
+ else
+ ep->stats.out_bytes += count;
+}
+
+/**
+ * pxa_ep_setup - Sets up an usb physical endpoint
+ * @ep: pxa27x physical endpoint
+ *
+ * Find the physical pxa27x ep, and setup its UDCCR
+ */
+static __init void pxa_ep_setup(struct pxa_ep *ep)
+{
+ u32 new_udccr;
+
+ new_udccr = ((ep->config << UDCCONR_CN_S) & UDCCONR_CN)
+ | ((ep->interface << UDCCONR_IN_S) & UDCCONR_IN)
+ | ((ep->alternate << UDCCONR_AISN_S) & UDCCONR_AISN)
+ | ((EPADDR(ep) << UDCCONR_EN_S) & UDCCONR_EN)
+ | ((EPXFERTYPE(ep) << UDCCONR_ET_S) & UDCCONR_ET)
+ | ((ep->dir_in) ? UDCCONR_ED : 0)
+ | ((ep->fifo_size << UDCCONR_MPS_S) & UDCCONR_MPS)
+ | UDCCONR_EE;
+
+ udc_ep_writel(ep, UDCCR, new_udccr);
+}
+
+/**
+ * pxa_eps_setup - Sets up all usb physical endpoints
+ * @dev: udc device
+ *
+ * Setup all pxa physical endpoints, except ep0
+ */
+static __init void pxa_eps_setup(struct pxa_udc *dev)
+{
+ unsigned int i;
+
+ dev_dbg(dev->dev, "%s: dev=%p\n", __func__, dev);
+
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++)
+ pxa_ep_setup(&dev->pxa_ep[i]);
+}
+
+/**
+ * pxa_ep_alloc_request - Allocate usb request
+ * @_ep: usb endpoint
+ * @gfp_flags:
+ *
+ * For the pxa27x, these can just wrap kmalloc/kfree. gadget drivers
+ * must still pass correctly initialized endpoints, since other controller
+ * drivers may care about how it's currently set up (dma issues etc).
+ */
+static struct usb_request *
+pxa_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+ struct pxa27x_request *req;
+
+ req = kzalloc(sizeof *req, gfp_flags);
+ if (!req || !_ep)
+ return NULL;
+
+ INIT_LIST_HEAD(&req->queue);
+ req->in_use = 0;
+ req->udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+
+ return &req->req;
+}
+
+/**
+ * pxa_ep_free_request - Free usb request
+ * @_ep: usb endpoint
+ * @_req: usb request
+ *
+ * Wrapper around kfree to free _req
+ */
+static void pxa_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct pxa27x_request *req;
+
+ req = container_of(_req, struct pxa27x_request, req);
+ WARN_ON(!list_empty(&req->queue));
+ kfree(req);
+}
+
+/**
+ * ep_add_request - add a request to the endpoint's queue
+ * @ep: usb endpoint
+ * @req: usb request
+ *
+ * Context: ep->lock held
+ *
+ * Queues the request in the endpoint's queue, and enables the interrupts
+ * on the endpoint.
+ */
+static void ep_add_request(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ if (unlikely(!req))
+ return;
+ ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
+ req->req.length, udc_ep_readl(ep, UDCCSR));
+
+ req->in_use = 1;
+ list_add_tail(&req->queue, &ep->queue);
+ pio_irq_enable(ep);
+}
+
+/**
+ * ep_del_request - removes a request from the endpoint's queue
+ * @ep: usb endpoint
+ * @req: usb request
+ *
+ * Context: ep->lock held
+ *
+ * Unqueue the request from the endpoint's queue. If there are no more requests
+ * on the endpoint, and if it's not the control endpoint, interrupts are
+ * disabled on the endpoint.
+ */
+static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ if (unlikely(!req))
+ return;
+ ep_vdbg(ep, "req:%p, lg=%d, udccsr=0x%03x\n", req,
+ req->req.length, udc_ep_readl(ep, UDCCSR));
+
+ list_del_init(&req->queue);
+ req->in_use = 0;
+ if (!is_ep0(ep) && list_empty(&ep->queue))
+ pio_irq_disable(ep);
+}
+
+/**
+ * req_done - Complete an usb request
+ * @ep: pxa physical endpoint
+ * @req: pxa request
+ * @status: usb request status sent to gadget API
+ *
+ * Context: ep->lock held
+ *
+ * Retire a pxa27x usb request. Endpoint must be locked.
+ */
+static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
+{
+ ep_del_request(ep, req);
+ if (likely(req->req.status == -EINPROGRESS))
+ req->req.status = status;
+ else
+ status = req->req.status;
+
+ if (status && status != -ESHUTDOWN)
+ ep_dbg(ep, "complete req %p stat %d len %u/%u\n",
+ &req->req, status,
+ req->req.actual, req->req.length);
+
+ req->req.complete(&req->udc_usb_ep->usb_ep, &req->req);
+}
+
+/**
+ * ep_end_out_req - Ends control endpoint in request
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends endpoint in request (completes usb request).
+ */
+static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ inc_ep_stats_reqs(ep, !USB_DIR_IN);
+ req_done(ep, req, 0);
+}
+
+/**
+ * ep0_end_out_req - Ends control endpoint in request (ends data stage)
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends control endpoint in request (completes usb request), and puts
+ * control endpoint into idle state
+ */
+static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ set_ep0state(ep->dev, OUT_STATUS_STAGE);
+ ep_end_out_req(ep, req);
+ ep0_idle(ep->dev);
+}
+
+/**
+ * ep_end_in_req - Ends endpoint out request
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends endpoint out request (completes usb request).
+ */
+static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ inc_ep_stats_reqs(ep, USB_DIR_IN);
+ req_done(ep, req, 0);
+}
+
+/**
+ * ep0_end_in_req - Ends control endpoint out request (ends data stage)
+ * @ep: physical endpoint
+ * @req: pxa request
+ *
+ * Context: ep->lock held
+ *
+ * Ends control endpoint out request (completes usb request), and puts
+ * control endpoint into status state
+ */
+static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ struct pxa_udc *udc = ep->dev;
+
+ set_ep0state(udc, IN_STATUS_STAGE);
+ ep_end_in_req(ep, req);
+}
+
+/**
+ * nuke - Dequeue all requests
+ * @ep: pxa endpoint
+ * @status: usb request status
+ *
+ * Context: ep->lock held
+ *
+ * Dequeues all requests on an endpoint. As a side effect, interrupts will be
+ * disabled on that endpoint (because no more requests).
+ */
+static void nuke(struct pxa_ep *ep, int status)
+{
+ struct pxa27x_request *req;
+
+ while (!list_empty(&ep->queue)) {
+ req = list_entry(ep->queue.next, struct pxa27x_request, queue);
+ req_done(ep, req, status);
+ }
+}
+
+/**
+ * read_packet - transfer 1 packet from an OUT endpoint into request
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ *
+ * Takes bytes from OUT endpoint and transfers them info the usb request.
+ * If there is less space in request than bytes received in OUT endpoint,
+ * bytes are left in the OUT endpoint.
+ *
+ * Returns how many bytes were actually transfered
+ */
+static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ u32 *buf;
+ int bytes_ep, bufferspace, count, i;
+
+ bytes_ep = ep_count_bytes_remain(ep);
+ bufferspace = req->req.length - req->req.actual;
+
+ buf = (u32 *)(req->req.buf + req->req.actual);
+ prefetchw(buf);
+
+ if (likely(!ep_is_empty(ep)))
+ count = min(bytes_ep, bufferspace);
+ else /* zlp */
+ count = 0;
+
+ for (i = count; i > 0; i -= 4)
+ *buf++ = udc_ep_readl(ep, UDCDR);
+ req->req.actual += count;
+
+ udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+
+ return count;
+}
+
+/**
+ * write_packet - transfer 1 packet from request into an IN endpoint
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ * @max: max bytes that fit into endpoint
+ *
+ * Takes bytes from usb request, and transfers them into the physical
+ * endpoint. If there are no bytes to transfer, doesn't write anything
+ * to physical endpoint.
+ *
+ * Returns how many bytes were actually transfered.
+ */
+static int write_packet(struct pxa_ep *ep, struct pxa27x_request *req,
+ unsigned int max)
+{
+ int length, count, remain, i;
+ u32 *buf;
+ u8 *buf_8;
+
+ buf = (u32 *)(req->req.buf + req->req.actual);
+ prefetch(buf);
+
+ length = min(req->req.length - req->req.actual, max);
+ req->req.actual += length;
+
+ remain = length & 0x3;
+ count = length & ~(0x3);
+ for (i = count; i > 0 ; i -= 4)
+ udc_ep_writel(ep, UDCDR, *buf++);
+
+ buf_8 = (u8 *)buf;
+ for (i = remain; i > 0; i--)
+ udc_ep_writeb(ep, UDCDR, *buf_8++);
+
+ ep_vdbg(ep, "length=%d+%d, udccsr=0x%03x\n", count, remain,
+ udc_ep_readl(ep, UDCCSR));
+
+ return length;
+}
+
+/**
+ * read_fifo - Transfer packets from OUT endpoint into usb request
+ * @ep: pxa physical endpoint
+ * @req: usb request
+ *
+ * Context: callable when in_interrupt()
+ *
+ * Unload as many packets as possible from the fifo we use for usb OUT
+ * transfers and put them into the request. Caller should have made sure
+ * there's at least one packet ready.
+ * Doesn't complete the request, that's the caller's job
+ *
+ * Returns 1 if the request completed, 0 otherwise
+ */
+static int read_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ int count, is_short, completed = 0;
+
+ while (epout_has_pkt(ep)) {
+ count = read_packet(ep, req);
+ inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
+
+ is_short = (count < ep->fifo_size);
+ ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
+ udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
+ &req->req, req->req.actual, req->req.length);
+
+ /* completion */
+ if (is_short || req->req.actual == req->req.length) {
+ completed = 1;
+ break;
+ }
+ /* finished that packet. the next one may be waiting... */
+ }
+ return completed;
+}
+
+/**
+ * write_fifo - transfer packets from usb request into an IN endpoint
+ * @ep: pxa physical endpoint
+ * @req: pxa usb request
+ *
+ * Write to an IN endpoint fifo, as many packets as possible.
+ * irqs will use this to write the rest later.
+ * caller guarantees at least one packet buffer is ready (or a zlp).
+ * Doesn't complete the request, that's the caller's job
+ *
+ * Returns 1 if request fully transfered, 0 if partial transfer
+ */
+static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ unsigned max;
+ int count, is_short, is_last = 0, completed = 0, totcount = 0;
+ u32 udccsr;
+
+ max = ep->fifo_size;
+ do {
+ is_short = 0;
+
+ udccsr = udc_ep_readl(ep, UDCCSR);
+ if (udccsr & UDCCSR_PC) {
+ ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n",
+ udccsr);
+ udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
+ }
+ if (udccsr & UDCCSR_TRN) {
+ ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n",
+ udccsr);
+ udc_ep_writel(ep, UDCCSR, UDCCSR_TRN);
+ }
+
+ count = write_packet(ep, req, max);
+ inc_ep_stats_bytes(ep, count, USB_DIR_IN);
+ totcount += count;
+
+ /* last packet is usually short (or a zlp) */
+ if (unlikely(count < max)) {
+ is_last = 1;
+ is_short = 1;
+ } else {
+ if (likely(req->req.length > req->req.actual)
+ || req->req.zero)
+ is_last = 0;
+ else
+ is_last = 1;
+ /* interrupt/iso maxpacket may not fill the fifo */
+ is_short = unlikely(max < ep->fifo_size);
+ }
+
+ if (is_short)
+ udc_ep_writel(ep, UDCCSR, UDCCSR_SP);
+
+ /* requests complete when all IN data is in the FIFO */
+ if (is_last) {
+ completed = 1;
+ break;
+ }
+ } while (!ep_is_full(ep));
+
+ ep_dbg(ep, "wrote count:%d bytes%s%s, left:%d req=%p\n",
+ totcount, is_last ? "/L" : "", is_short ? "/S" : "",
+ req->req.length - req->req.actual, &req->req);
+
+ return completed;
+}
+
+/**
+ * read_ep0_fifo - Transfer packets from control endpoint into usb request
+ * @ep: control endpoint
+ * @req: pxa usb request
+ *
+ * Special ep0 version of the above read_fifo. Reads as many bytes from control
+ * endpoint as can be read, and stores them into usb request (limited by request
+ * maximum length).
+ *
+ * Returns 0 if usb request only partially filled, 1 if fully filled
+ */
+static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ int count, is_short, completed = 0;
+
+ while (epout_has_pkt(ep)) {
+ count = read_packet(ep, req);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+ inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
+
+ is_short = (count < ep->fifo_size);
+ ep_dbg(ep, "read udccsr:%03x, count:%d bytes%s req %p %d/%d\n",
+ udc_ep_readl(ep, UDCCSR), count, is_short ? "/S" : "",
+ &req->req, req->req.actual, req->req.length);
+
+ if (is_short || req->req.actual >= req->req.length) {
+ completed = 1;
+ break;
+ }
+ }
+
+ return completed;
+}
+
+/**
+ * write_ep0_fifo - Send a request to control endpoint (ep0 in)
+ * @ep: control endpoint
+ * @req: request
+ *
+ * Context: callable when in_interrupt()
+ *
+ * Sends a request (or a part of the request) to the control endpoint (ep0 in).
+ * If the request doesn't fit, the remaining part will be sent from irq.
+ * The request is considered fully written only if either :
+ * - last write transfered all remaining bytes, but fifo was not fully filled
+ * - last write was a 0 length write
+ *
+ * Returns 1 if request fully written, 0 if request only partially sent
+ */
+static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
+{
+ unsigned count;
+ int is_last, is_short;
+
+ count = write_packet(ep, req, EP0_FIFO_SIZE);
+ inc_ep_stats_bytes(ep, count, USB_DIR_IN);
+
+ is_short = (count < EP0_FIFO_SIZE);
+ is_last = ((count == 0) || (count < EP0_FIFO_SIZE));
+
+ /* Sends either a short packet or a 0 length packet */
+ if (unlikely(is_short))
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_IPR);
+
+ ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n",
+ count, is_short ? "/S" : "", is_last ? "/L" : "",
+ req->req.length - req->req.actual,
+ &req->req, udc_ep_readl(ep, UDCCSR));
+
+ return is_last;
+}
+
+/**
+ * pxa_ep_queue - Queue a request into an IN endpoint
+ * @_ep: usb endpoint
+ * @_req: usb request
+ * @gfp_flags: flags
+ *
+ * Context: normally called when !in_interrupt, but callable when in_interrupt()
+ * in the special case of ep0 setup :
+ * (irq->handle_ep0_ctrl_req->gadget_setup->pxa_ep_queue)
+ *
+ * Returns 0 if succedeed, error otherwise
+ */
+static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct udc_usb_ep *udc_usb_ep;
+ struct pxa_ep *ep;
+ struct pxa27x_request *req;
+ struct pxa_udc *dev;
+ unsigned long flags;
+ int rc = 0;
+ int is_first_req;
+ unsigned length;
+
+ req = container_of(_req, struct pxa27x_request, req);
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+
+ if (unlikely(!_req || !_req->complete || !_req->buf))
+ return -EINVAL;
+
+ if (unlikely(!_ep))
+ return -EINVAL;
+
+ dev = udc_usb_ep->dev;
+ ep = udc_usb_ep->pxa_ep;
+ if (unlikely(!ep))
+ return -EINVAL;
+
+ dev = ep->dev;
+ if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+ ep_dbg(ep, "bogus device state\n");
+ return -ESHUTDOWN;
+ }
+
+ /* iso is always one packet per request, that's the only way
+ * we can report per-packet status. that also helps with dma.
+ */
+ if (unlikely(EPXFERTYPE_is_ISO(ep)
+ && req->req.length > ep->fifo_size))
+ return -EMSGSIZE;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ is_first_req = list_empty(&ep->queue);
+ ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n",
+ _req, is_first_req ? "yes" : "no",
+ _req->length, _req->buf);
+
+ if (!ep->enabled) {
+ _req->status = -ESHUTDOWN;
+ rc = -ESHUTDOWN;
+ goto out;
+ }
+
+ if (req->in_use) {
+ ep_err(ep, "refusing to queue req %p (already queued)\n", req);
+ goto out;
+ }
+
+ length = _req->length;
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ ep_add_request(ep, req);
+
+ if (is_ep0(ep)) {
+ switch (dev->ep0state) {
+ case WAIT_ACK_SET_CONF_INTERF:
+ if (length == 0) {
+ ep_end_in_req(ep, req);
+ } else {
+ ep_err(ep, "got a request of %d bytes while"
+ "in state WATI_ACK_SET_CONF_INTERF\n",
+ length);
+ ep_del_request(ep, req);
+ rc = -EL2HLT;
+ }
+ ep0_idle(ep->dev);
+ break;
+ case IN_DATA_STAGE:
+ if (!ep_is_full(ep))
+ if (write_ep0_fifo(ep, req))
+ ep0_end_in_req(ep, req);
+ break;
+ case OUT_DATA_STAGE:
+ if ((length == 0) || !epout_has_pkt(ep))
+ if (read_ep0_fifo(ep, req))
+ ep0_end_out_req(ep, req);
+ break;
+ default:
+ ep_err(ep, "odd state %s to send me a request\n",
+ EP0_STNAME(ep->dev));
+ ep_del_request(ep, req);
+ rc = -EL2HLT;
+ break;
+ }
+ } else {
+ handle_ep(ep);
+ }
+
+out:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ return rc;
+}
+
+/**
+ * pxa_ep_dequeue - Dequeue one request
+ * @_ep: usb endpoint
+ * @_req: usb request
+ *
+ * Return 0 if no error, -EINVAL or -ECONNRESET otherwise
+ */
+static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ struct pxa27x_request *req;
+ unsigned long flags;
+ int rc;
+
+ if (!_ep)
+ return -EINVAL;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ /* make sure it's actually queued on this endpoint */
+ list_for_each_entry(req, &ep->queue, queue) {
+ if (&req->req == _req)
+ break;
+ }
+
+ rc = -EINVAL;
+ if (&req->req != _req)
+ goto out;
+
+ rc = 0;
+ req_done(ep, req, -ECONNRESET);
+out:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ return rc;
+}
+
+/**
+ * pxa_ep_set_halt - Halts operations on one endpoint
+ * @_ep: usb endpoint
+ * @value:
+ *
+ * Returns 0 if no error, -EINVAL, -EROFS, -EAGAIN otherwise
+ */
+static int pxa_ep_set_halt(struct usb_ep *_ep, int value)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned long flags;
+ int rc;
+
+
+ if (!_ep)
+ return -EINVAL;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return -EINVAL;
+
+ if (value == 0) {
+ /*
+ * This path (reset toggle+halt) is needed to implement
+ * SET_INTERFACE on normal hardware. but it can't be
+ * done from software on the PXA UDC, and the hardware
+ * forgets to do it as part of SET_INTERFACE automagic.
+ */
+ ep_dbg(ep, "only host can clear halt\n");
+ return -EROFS;
+ }
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ rc = -EAGAIN;
+ if (ep->dir_in && (ep_is_full(ep) || !list_empty(&ep->queue)))
+ goto out;
+
+ /* FST, FEF bits are the same for control and non control endpoints */
+ rc = 0;
+ udc_ep_writel(ep, UDCCSR, UDCCSR_FST | UDCCSR_FEF);
+ if (is_ep0(ep))
+ set_ep0state(ep->dev, STALL);
+
+out:
+ spin_unlock_irqrestore(&ep->lock, flags);
+ return rc;
+}
+
+/**
+ * pxa_ep_fifo_status - Get how many bytes in physical endpoint
+ * @_ep: usb endpoint
+ *
+ * Returns number of bytes in OUT fifos. Broken for IN fifos.
+ */
+static int pxa_ep_fifo_status(struct usb_ep *_ep)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+
+ if (!_ep)
+ return -ENODEV;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return -ENODEV;
+
+ if (ep->dir_in)
+ return -EOPNOTSUPP;
+ if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN || ep_is_empty(ep))
+ return 0;
+ else
+ return ep_count_bytes_remain(ep) + 1;
+}
+
+/**
+ * pxa_ep_fifo_flush - Flushes one endpoint
+ * @_ep: usb endpoint
+ *
+ * Discards all data in one endpoint(IN or OUT), except control endpoint.
+ */
+static void pxa_ep_fifo_flush(struct usb_ep *_ep)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned long flags;
+
+ if (!_ep)
+ return;
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep))
+ return;
+
+ spin_lock_irqsave(&ep->lock, flags);
+
+ if (unlikely(!list_empty(&ep->queue)))
+ ep_dbg(ep, "called while queue list not empty\n");
+ ep_dbg(ep, "called\n");
+
+ /* for OUT, just read and discard the FIFO contents. */
+ if (!ep->dir_in) {
+ while (!ep_is_empty(ep))
+ udc_ep_readl(ep, UDCDR);
+ } else {
+ /* most IN status is the same, but ISO can't stall */
+ udc_ep_writel(ep, UDCCSR,
+ UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN
+ | (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST));
+ }
+
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ return;
+}
+
+/**
+ * pxa_ep_enable - Enables usb endpoint
+ * @_ep: usb endpoint
+ * @desc: usb endpoint descriptor
+ *
+ * Nothing much to do here, as ep configuration is done once and for all
+ * before udc is enabled. After udc enable, no physical endpoint configuration
+ * can be changed.
+ * Function makes sanity checks and flushes the endpoint.
+ */
+static int pxa_ep_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ struct pxa_udc *udc;
+
+ if (!_ep || !desc)
+ return -EINVAL;
+
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ if (udc_usb_ep->pxa_ep) {
+ ep = udc_usb_ep->pxa_ep;
+ ep_warn(ep, "usb_ep %s already enabled, doing nothing\n",
+ _ep->name);
+ } else {
+ ep = find_pxa_ep(udc_usb_ep->dev, udc_usb_ep);
+ }
+
+ if (!ep || is_ep0(ep)) {
+ dev_err(udc_usb_ep->dev->dev,
+ "unable to match pxa_ep for ep %s\n",
+ _ep->name);
+ return -EINVAL;
+ }
+
+ if ((desc->bDescriptorType != USB_DT_ENDPOINT)
+ || (ep->type != usb_endpoint_type(desc))) {
+ ep_err(ep, "type mismatch\n");
+ return -EINVAL;
+ }
+
+ if (ep->fifo_size < le16_to_cpu(desc->wMaxPacketSize)) {
+ ep_err(ep, "bad maxpacket\n");
+ return -ERANGE;
+ }
+
+ udc_usb_ep->pxa_ep = ep;
+ udc = ep->dev;
+
+ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) {
+ ep_err(ep, "bogus device state\n");
+ return -ESHUTDOWN;
+ }
+
+ ep->enabled = 1;
+
+ /* flush fifo (mostly for OUT buffers) */
+ pxa_ep_fifo_flush(_ep);
+
+ ep_dbg(ep, "enabled\n");
+ return 0;
+}
+
+/**
+ * pxa_ep_disable - Disable usb endpoint
+ * @_ep: usb endpoint
+ *
+ * Same as for pxa_ep_enable, no physical endpoint configuration can be
+ * changed.
+ * Function flushes the endpoint and related requests.
+ */
+static int pxa_ep_disable(struct usb_ep *_ep)
+{
+ struct pxa_ep *ep;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned long flags;
+
+ if (!_ep)
+ return -EINVAL;
+
+ udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
+ ep = udc_usb_ep->pxa_ep;
+ if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
+ return -EINVAL;
+
+ spin_lock_irqsave(&ep->lock, flags);
+ ep->enabled = 0;
+ nuke(ep, -ESHUTDOWN);
+ spin_unlock_irqrestore(&ep->lock, flags);
+
+ pxa_ep_fifo_flush(_ep);
+ udc_usb_ep->pxa_ep = NULL;
+
+ ep_dbg(ep, "disabled\n");
+ return 0;
+}
+
+static struct usb_ep_ops pxa_ep_ops = {
+ .enable = pxa_ep_enable,
+ .disable = pxa_ep_disable,
+
+ .alloc_request = pxa_ep_alloc_request,
+ .free_request = pxa_ep_free_request,
+
+ .queue = pxa_ep_queue,
+ .dequeue = pxa_ep_dequeue,
+
+ .set_halt = pxa_ep_set_halt,
+ .fifo_status = pxa_ep_fifo_status,
+ .fifo_flush = pxa_ep_fifo_flush,
+};
+
+
+/**
+ * pxa_udc_get_frame - Returns usb frame number
+ * @_gadget: usb gadget
+ */
+static int pxa_udc_get_frame(struct usb_gadget *_gadget)
+{
+ struct pxa_udc *udc = to_gadget_udc(_gadget);
+
+ return (udc_readl(udc, UDCFNR) & 0x7ff);
+}
+
+/**
+ * pxa_udc_wakeup - Force udc device out of suspend
+ * @_gadget: usb gadget
+ *
+ * Returns 0 if succesfull, error code otherwise
+ */
+static int pxa_udc_wakeup(struct usb_gadget *_gadget)
+{
+ struct pxa_udc *udc = to_gadget_udc(_gadget);
+
+ /* host may not have enabled remote wakeup */
+ if ((udc_readl(udc, UDCCR) & UDCCR_DWRE) == 0)
+ return -EHOSTUNREACH;
+ udc_set_mask_UDCCR(udc, UDCCR_UDR);
+ return 0;
+}
+
+static const struct usb_gadget_ops pxa_udc_ops = {
+ .get_frame = pxa_udc_get_frame,
+ .wakeup = pxa_udc_wakeup,
+ /* current versions must always be self-powered */
+};
+
+/**
+ * udc_disable - disable udc device controller
+ * @udc: udc device
+ *
+ * Disables the udc device : disables clocks, udc interrupts, control endpoint
+ * interrupts.
+ */
+static void udc_disable(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCICR0, 0);
+ udc_writel(udc, UDCICR1, 0);
+
+ udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+ clk_disable(udc->clk);
+
+ ep0_idle(udc);
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+}
+
+/**
+ * udc_init_data - Initialize udc device data structures
+ * @dev: udc device
+ *
+ * Initializes gadget endpoint list, endpoints locks. No action is taken
+ * on the hardware.
+ */
+static __init void udc_init_data(struct pxa_udc *dev)
+{
+ int i;
+ struct pxa_ep *ep;
+
+ /* device/ep0 records init */
+ INIT_LIST_HEAD(&dev->gadget.ep_list);
+ INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+ dev->udc_usb_ep[0].pxa_ep = &dev->pxa_ep[0];
+ ep0_idle(dev);
+ strcpy(dev->dev->bus_id, "");
+
+ /* PXA endpoints init */
+ for (i = 0; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &dev->pxa_ep[i];
+
+ ep->enabled = is_ep0(ep);
+ INIT_LIST_HEAD(&ep->queue);
+ spin_lock_init(&ep->lock);
+ }
+
+ /* USB endpoints init */
+ for (i = 0; i < NR_USB_ENDPOINTS; i++)
+ if (i != 0)
+ list_add_tail(&dev->udc_usb_ep[i].usb_ep.ep_list,
+ &dev->gadget.ep_list);
+}
+
+/**
+ * udc_enable - Enables the udc device
+ * @dev: udc device
+ *
+ * Enables the udc device : enables clocks, udc interrupts, control endpoint
+ * interrupts, sets usb as UDC client and setups endpoints.
+ */
+static void udc_enable(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCICR0, 0);
+ udc_writel(udc, UDCICR1, 0);
+ udc_writel(udc, UP2OCR, UP2OCR_HXOE);
+ udc_clear_mask_UDCCR(udc, UDCCR_UDE);
+
+ clk_enable(udc->clk);
+
+ ep0_idle(udc);
+ udc->gadget.speed = USB_SPEED_FULL;
+ memset(&udc->stats, 0, sizeof(udc->stats));
+
+ udc_set_mask_UDCCR(udc, UDCCR_UDE);
+ udelay(2);
+ if (udc_readl(udc, UDCCR) & UDCCR_EMCE)
+ dev_err(udc->dev, "Configuration errors, udc disabled\n");
+
+ /*
+ * Caller must be able to sleep in order to cope with startup transients
+ */
+ msleep(100);
+
+ /* enable suspend/resume and reset irqs */
+ udc_writel(udc, UDCICR1,
+ UDCICR1_IECC | UDCICR1_IERU
+ | UDCICR1_IESU | UDCICR1_IERS);
+
+ /* enable ep0 irqs */
+ pio_irq_enable(&udc->pxa_ep[0]);
+
+ dev_info(udc->dev, "UDC connecting\n");
+ if (udc->mach->udc_command)
+ udc->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+}
+
+/**
+ * usb_gadget_register_driver - Register gadget driver
+ * @driver: gadget driver
+ *
+ * When a driver is successfully registered, it will receive control requests
+ * including set_configuration(), which enables non-control requests. Then
+ * usb traffic follows until a disconnect is reported. Then a host may connect
+ * again, or the driver might get unbound.
+ *
+ * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+ struct pxa_udc *udc = the_controller;
+ int retval;
+
+ if (!driver || driver->speed != USB_SPEED_FULL || !driver->bind
+ || !driver->disconnect || !driver->setup)
+ return -EINVAL;
+ if (!udc)
+ return -ENODEV;
+ if (udc->driver)
+ return -EBUSY;
+
+ /* first hook up the driver ... */
+ udc->driver = driver;
+ udc->gadget.dev.driver = &driver->driver;
+
+ retval = device_add(&udc->gadget.dev);
+ if (retval) {
+ dev_err(udc->dev, "device_add error %d\n", retval);
+ goto add_fail;
+ }
+ retval = driver->bind(&udc->gadget);
+ if (retval) {
+ dev_err(udc->dev, "bind to driver %s --> error %d\n",
+ driver->driver.name, retval);
+ goto bind_fail;
+ }
+ dev_dbg(udc->dev, "registered gadget driver '%s'\n",
+ driver->driver.name);
+
+ udc_enable(udc);
+ return 0;
+
+bind_fail:
+ device_del(&udc->gadget.dev);
+add_fail:
+ udc->driver = NULL;
+ udc->gadget.dev.driver = NULL;
+ return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+
+/**
+ * stop_activity - Stops udc endpoints
+ * @udc: udc device
+ * @driver: gadget driver
+ *
+ * Disables all udc endpoints (even control endpoint), report disconnect to
+ * the gadget user.
+ */
+static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
+{
+ int i;
+
+ /* don't disconnect drivers more than once */
+ if (udc->gadget.speed == USB_SPEED_UNKNOWN)
+ driver = NULL;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+
+ for (i = 0; i < NR_USB_ENDPOINTS; i++)
+ pxa_ep_disable(&udc->udc_usb_ep[i].usb_ep);
+
+ if (driver)
+ driver->disconnect(&udc->gadget);
+}
+
+/**
+ * usb_gadget_unregister_driver - Unregister the gadget driver
+ * @driver: gadget driver
+ *
+ * Returns 0 if no error, -ENODEV, -EINVAL otherwise
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+ struct pxa_udc *udc = the_controller;
+
+ if (!udc)
+ return -ENODEV;
+ if (!driver || driver != udc->driver || !driver->unbind)
+ return -EINVAL;
+
+ stop_activity(udc, driver);
+ udc_disable(udc);
+
+ driver->unbind(&udc->gadget);
+ udc->driver = NULL;
+
+ device_del(&udc->gadget.dev);
+
+ dev_info(udc->dev, "unregistered gadget driver '%s'\n",
+ driver->driver.name);
+ return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/**
+ * handle_ep0_ctrl_req - handle control endpoint control request
+ * @udc: udc device
+ * @req: control request
+ */
+static void handle_ep0_ctrl_req(struct pxa_udc *udc,
+ struct pxa27x_request *req)
+{
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+ union {
+ struct usb_ctrlrequest r;
+ u32 word[2];
+ } u;
+ int i;
+ int have_extrabytes = 0;
+
+ nuke(ep, -EPROTO);
+
+ /* read SETUP packet */
+ for (i = 0; i < 2; i++) {
+ if (unlikely(ep_is_empty(ep)))
+ goto stall;
+ u.word[i] = udc_ep_readl(ep, UDCDR);
+ }
+
+ have_extrabytes = !ep_is_empty(ep);
+ while (!ep_is_empty(ep)) {
+ i = udc_ep_readl(ep, UDCDR);
+ ep_err(ep, "wrong to have extra bytes for setup : 0x%08x\n", i);
+ }
+
+ le16_to_cpus(&u.r.wValue);
+ le16_to_cpus(&u.r.wIndex);
+ le16_to_cpus(&u.r.wLength);
+
+ ep_dbg(ep, "SETUP %02x.%02x v%04x i%04x l%04x\n",
+ u.r.bRequestType, u.r.bRequest,
+ u.r.wValue, u.r.wIndex, u.r.wLength);
+ if (unlikely(have_extrabytes))
+ goto stall;
+
+ if (u.r.bRequestType & USB_DIR_IN)
+ set_ep0state(udc, IN_DATA_STAGE);
+ else
+ set_ep0state(udc, OUT_DATA_STAGE);
+
+ /* Tell UDC to enter Data Stage */
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_SA | UDCCSR0_OPC);
+
+ i = udc->driver->setup(&udc->gadget, &u.r);
+ if (i < 0)
+ goto stall;
+out:
+ return;
+stall:
+ ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
+ udc_ep_readl(ep, UDCCSR), i);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_FST | UDCCSR0_FTF);
+ set_ep0state(udc, STALL);
+ goto out;
+}
+
+/**
+ * handle_ep0 - Handle control endpoint data transfers
+ * @udc: udc device
+ * @fifo_irq: 1 if triggered by fifo service type irq
+ * @opc_irq: 1 if triggered by output packet complete type irq
+ *
+ * Context : when in_interrupt() or with ep->lock held
+ *
+ * Tries to transfer all pending request data into the endpoint and/or
+ * transfer all pending data in the endpoint into usb requests.
+ * Handles states of ep0 automata.
+ *
+ * PXA27x hardware handles several standard usb control requests without
+ * driver notification. The requests fully handled by hardware are :
+ * SET_ADDRESS, SET_FEATURE, CLEAR_FEATURE, GET_CONFIGURATION, GET_INTERFACE,
+ * GET_STATUS
+ * The requests handled by hardware, but with irq notification are :
+ * SYNCH_FRAME, SET_CONFIGURATION, SET_INTERFACE
+ * The remaining standard requests really handled by handle_ep0 are :
+ * GET_DESCRIPTOR, SET_DESCRIPTOR, specific requests.
+ * Requests standardized outside of USB 2.0 chapter 9 are handled more
+ * uniformly, by gadget drivers.
+ *
+ * The control endpoint state machine is _not_ USB spec compliant, it's even
+ * hardly compliant with Intel PXA270 developers guide.
+ * The key points which inferred this state machine are :
+ * - on every setup token, bit UDCCSR0_SA is raised and held until cleared by
+ * software.
+ * - on every OUT packet received, UDCCSR0_OPC is raised and held until
+ * cleared by software.
+ * - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it
+ * before reading ep0.
+ * - irq can be called on a "packet complete" event (opc_irq=1), while
+ * UDCCSR0_OPC is not yet raised (delta can be as big as 100ms
+ * from experimentation).
+ * - as UDCCSR0_SA can be activated while in irq handling, and clearing
+ * UDCCSR0_OPC would flush the setup data, we almost never clear UDCCSR0_OPC
+ * => we never actually read the "status stage" packet of an IN data stage
+ * => this is not documented in Intel documentation
+ * - hardware as no idea of STATUS STAGE, it only handle SETUP STAGE and DATA
+ * STAGE. The driver add STATUS STAGE to send last zero length packet in
+ * OUT_STATUS_STAGE.
+ * - special attention was needed for IN_STATUS_STAGE. If a packet complete
+ * event is detected, we terminate the status stage without ackowledging the
+ * packet (not to risk to loose a potential SETUP packet)
+ */
+static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
+{
+ u32 udccsr0;
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+ struct pxa27x_request *req = NULL;
+ int completed = 0;
+
+ udccsr0 = udc_ep_readl(ep, UDCCSR);
+ ep_dbg(ep, "state=%s, req=%p, udccsr0=0x%03x, udcbcr=%d, irq_msk=%x\n",
+ EP0_STNAME(udc), req, udccsr0, udc_ep_readl(ep, UDCBCR),
+ (fifo_irq << 1 | opc_irq));
+
+ if (!list_empty(&ep->queue))
+ req = list_entry(ep->queue.next, struct pxa27x_request, queue);
+
+ if (udccsr0 & UDCCSR0_SST) {
+ ep_dbg(ep, "clearing stall status\n");
+ nuke(ep, -EPIPE);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_SST);
+ ep0_idle(udc);
+ }
+
+ if (udccsr0 & UDCCSR0_SA) {
+ nuke(ep, 0);
+ set_ep0state(udc, SETUP_STAGE);
+ }
+
+ switch (udc->ep0state) {
+ case WAIT_FOR_SETUP:
+ /*
+ * Hardware bug : beware, we cannot clear OPC, since we would
+ * miss a potential OPC irq for a setup packet.
+ * So, we only do ... nothing, and hope for a next irq with
+ * UDCCSR0_SA set.
+ */
+ break;
+ case SETUP_STAGE:
+ udccsr0 &= UDCCSR0_CTRL_REQ_MASK;
+ if (likely(udccsr0 == UDCCSR0_CTRL_REQ_MASK))
+ handle_ep0_ctrl_req(udc, req);
+ break;
+ case IN_DATA_STAGE: /* GET_DESCRIPTOR */
+ if (epout_has_pkt(ep))
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
+ if (req && !ep_is_full(ep))
+ completed = write_ep0_fifo(ep, req);
+ if (completed)
+ ep0_end_in_req(ep, req);
+ break;
+ case OUT_DATA_STAGE: /* SET_DESCRIPTOR */
+ if (epout_has_pkt(ep) && req)
+ completed = read_ep0_fifo(ep, req);
+ if (completed)
+ ep0_end_out_req(ep, req);
+ break;
+ case STALL:
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_FST);
+ break;
+ case IN_STATUS_STAGE:
+ /*
+ * Hardware bug : beware, we cannot clear OPC, since we would
+ * miss a potential PC irq for a setup packet.
+ * So, we only put the ep0 into WAIT_FOR_SETUP state.
+ */
+ if (opc_irq)
+ ep0_idle(udc);
+ break;
+ case OUT_STATUS_STAGE:
+ case WAIT_ACK_SET_CONF_INTERF:
+ ep_warn(ep, "should never get in %s state here!!!\n",
+ EP0_STNAME(ep->dev));
+ ep0_idle(udc);
+ break;
+ }
+}
+
+/**
+ * handle_ep - Handle endpoint data tranfers
+ * @ep: pxa physical endpoint
+ *
+ * Tries to transfer all pending request data into the endpoint and/or
+ * transfer all pending data in the endpoint into usb requests.
+ *
+ * Is always called when in_interrupt() or with ep->lock held.
+ */
+static void handle_ep(struct pxa_ep *ep)
+{
+ struct pxa27x_request *req;
+ int completed;
+ u32 udccsr;
+ int is_in = ep->dir_in;
+ int loop = 0;
+
+ do {
+ completed = 0;
+ udccsr = udc_ep_readl(ep, UDCCSR);
+ if (likely(!list_empty(&ep->queue)))
+ req = list_entry(ep->queue.next,
+ struct pxa27x_request, queue);
+ else
+ req = NULL;
+
+ ep_dbg(ep, "req:%p, udccsr 0x%03x loop=%d\n",
+ req, udccsr, loop++);
+
+ if (unlikely(udccsr & (UDCCSR_SST | UDCCSR_TRN)))
+ udc_ep_writel(ep, UDCCSR,
+ udccsr & (UDCCSR_SST | UDCCSR_TRN));
+ if (!req)
+ break;
+
+ if (unlikely(is_in)) {
+ if (likely(!ep_is_full(ep)))
+ completed = write_fifo(ep, req);
+ if (completed)
+ ep_end_in_req(ep, req);
+ } else {
+ if (likely(epout_has_pkt(ep)))
+ completed = read_fifo(ep, req);
+ if (completed)
+ ep_end_out_req(ep, req);
+ }
+ } while (completed);
+}
+
+/**
+ * pxa27x_change_configuration - Handle SET_CONF usb request notification
+ * @udc: udc device
+ * @config: usb configuration
+ *
+ * Post the request to upper level.
+ * Don't use any pxa specific harware configuration capabilities
+ */
+static void pxa27x_change_configuration(struct pxa_udc *udc, int config)
+{
+ struct usb_ctrlrequest req ;
+
+ dev_dbg(udc->dev, "config=%d\n", config);
+
+ udc->config = config;
+ udc->last_interface = 0;
+ udc->last_alternate = 0;
+
+ req.bRequestType = 0;
+ req.bRequest = USB_REQ_SET_CONFIGURATION;
+ req.wValue = config;
+ req.wIndex = 0;
+ req.wLength = 0;
+
+ set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
+ udc->driver->setup(&udc->gadget, &req);
+}
+
+/**
+ * pxa27x_change_interface - Handle SET_INTERF usb request notification
+ * @udc: udc device
+ * @iface: interface number
+ * @alt: alternate setting number
+ *
+ * Post the request to upper level.
+ * Don't use any pxa specific harware configuration capabilities
+ */
+static void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt)
+{
+ struct usb_ctrlrequest req;
+
+ dev_dbg(udc->dev, "interface=%d, alternate setting=%d\n", iface, alt);
+
+ udc->last_interface = iface;
+ udc->last_alternate = alt;
+
+ req.bRequestType = USB_RECIP_INTERFACE;
+ req.bRequest = USB_REQ_SET_INTERFACE;
+ req.wValue = alt;
+ req.wIndex = iface;
+ req.wLength = 0;
+
+ set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
+ udc->driver->setup(&udc->gadget, &req);
+}
+
+/*
+ * irq_handle_data - Handle data transfer
+ * @irq: irq IRQ number
+ * @udc: dev pxa_udc device structure
+ *
+ * Called from irq handler, transferts data to or from endpoint to queue
+ */
+static void irq_handle_data(int irq, struct pxa_udc *udc)
+{
+ int i;
+ struct pxa_ep *ep;
+ u32 udcisr0 = udc_readl(udc, UDCISR0) & UDCCISR0_EP_MASK;
+ u32 udcisr1 = udc_readl(udc, UDCISR1) & UDCCISR1_EP_MASK;
+
+ if (udcisr0 & UDCISR_INT_MASK) {
+ udc->pxa_ep[0].stats.irqs++;
+ udc_writel(udc, UDCISR0, UDCISR_INT(0, UDCISR_INT_MASK));
+ handle_ep0(udc, !!(udcisr0 & UDCICR_FIFOERR),
+ !!(udcisr0 & UDCICR_PKTCOMPL));
+ }
+
+ udcisr0 >>= 2;
+ for (i = 1; udcisr0 != 0 && i < 16; udcisr0 >>= 2, i++) {
+ if (!(udcisr0 & UDCISR_INT_MASK))
+ continue;
+
+ udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK));
+ ep = &udc->pxa_ep[i];
+ ep->stats.irqs++;
+ handle_ep(ep);
+ }
+
+ for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) {
+ udc_writel(udc, UDCISR1, UDCISR_INT(i - 16, UDCISR_INT_MASK));
+ if (!(udcisr1 & UDCISR_INT_MASK))
+ continue;
+
+ ep = &udc->pxa_ep[i];
+ ep->stats.irqs++;
+ handle_ep(ep);
+ }
+
+}
+
+/**
+ * irq_udc_suspend - Handle IRQ "UDC Suspend"
+ * @udc: udc device
+ */
+static void irq_udc_suspend(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCISR1, UDCISR1_IRSU);
+ udc->stats.irqs_suspend++;
+
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+ ep0_idle(udc);
+}
+
+/**
+ * irq_udc_resume - Handle IRQ "UDC Resume"
+ * @udc: udc device
+ */
+static void irq_udc_resume(struct pxa_udc *udc)
+{
+ udc_writel(udc, UDCISR1, UDCISR1_IRRU);
+ udc->stats.irqs_resume++;
+
+ if (udc->gadget.speed != USB_SPEED_UNKNOWN
+ && udc->driver && udc->driver->resume)
+ udc->driver->resume(&udc->gadget);
+}
+
+/**
+ * irq_udc_reconfig - Handle IRQ "UDC Change Configuration"
+ * @udc: udc device
+ */
+static void irq_udc_reconfig(struct pxa_udc *udc)
+{
+ unsigned config, interface, alternate, config_change;
+ u32 udccr = udc_readl(udc, UDCCR);
+
+ udc_writel(udc, UDCISR1, UDCISR1_IRCC);
+ udc->stats.irqs_reconfig++;
+
+ config = (udccr & UDCCR_ACN) >> UDCCR_ACN_S;
+ config_change = (config != udc->config);
+ pxa27x_change_configuration(udc, config);
+
+ interface = (udccr & UDCCR_AIN) >> UDCCR_AIN_S;
+ alternate = (udccr & UDCCR_AAISN) >> UDCCR_AAISN_S;
+ pxa27x_change_interface(udc, interface, alternate);
+
+ if (config_change)
+ update_pxa_ep_matches(udc);
+ udc_set_mask_UDCCR(udc, UDCCR_SMAC);
+}
+
+/**
+ * irq_udc_reset - Handle IRQ "UDC Reset"
+ * @udc: udc device
+ */
+static void irq_udc_reset(struct pxa_udc *udc)
+{
+ u32 udccr = udc_readl(udc, UDCCR);
+ struct pxa_ep *ep = &udc->pxa_ep[0];
+
+ dev_info(udc->dev, "USB reset\n");
+ udc_writel(udc, UDCISR1, UDCISR1_IRRS);
+ udc->stats.irqs_reset++;
+
+ if ((udccr & UDCCR_UDA) == 0) {
+ dev_dbg(udc->dev, "USB reset start\n");
+ stop_activity(udc, udc->driver);
+ }
+ udc->gadget.speed = USB_SPEED_FULL;
+ memset(&udc->stats, 0, sizeof udc->stats);
+
+ nuke(ep, -EPROTO);
+ udc_ep_writel(ep, UDCCSR, UDCCSR0_FTF | UDCCSR0_OPC);
+ ep0_idle(udc);
+}
+
+/**
+ * pxa_udc_irq - Main irq handler
+ * @irq: irq number
+ * @_dev: udc device
+ *
+ * Handles all udc interrupts
+ */
+static irqreturn_t pxa_udc_irq(int irq, void *_dev)
+{
+ struct pxa_udc *udc = _dev;
+ u32 udcisr0 = udc_readl(udc, UDCISR0);
+ u32 udcisr1 = udc_readl(udc, UDCISR1);
+ u32 udccr = udc_readl(udc, UDCCR);
+ u32 udcisr1_spec;
+
+ dev_vdbg(udc->dev, "Interrupt, UDCISR0:0x%08x, UDCISR1:0x%08x, "
+ "UDCCR:0x%08x\n", udcisr0, udcisr1, udccr);
+
+ udcisr1_spec = udcisr1 & 0xf8000000;
+ if (unlikely(udcisr1_spec & UDCISR1_IRSU))
+ irq_udc_suspend(udc);
+ if (unlikely(udcisr1_spec & UDCISR1_IRRU))
+ irq_udc_resume(udc);
+ if (unlikely(udcisr1_spec & UDCISR1_IRCC))
+ irq_udc_reconfig(udc);
+ if (unlikely(udcisr1_spec & UDCISR1_IRRS))
+ irq_udc_reset(udc);
+
+ if ((udcisr0 & UDCCISR0_EP_MASK) | (udcisr1 & UDCCISR1_EP_MASK))
+ irq_handle_data(irq, udc);
+
+ return IRQ_HANDLED;
+}
+
+static struct pxa_udc memory = {
+ .gadget = {
+ .ops = &pxa_udc_ops,
+ .ep0 = &memory.udc_usb_ep[0].usb_ep,
+ .name = driver_name,
+ .dev = {
+ .bus_id = "gadget",
+ },
+ },
+
+ .udc_usb_ep = {
+ USB_EP_CTRL,
+ USB_EP_OUT_BULK(1),
+ USB_EP_IN_BULK(2),
+ USB_EP_IN_ISO(3),
+ USB_EP_OUT_ISO(4),
+ USB_EP_IN_INT(5),
+ },
+
+ .pxa_ep = {
+ PXA_EP_CTRL,
+ /* Endpoints for gadget zero */
+ PXA_EP_OUT_BULK(1, 1, 3, 0, 0),
+ PXA_EP_IN_BULK(2, 2, 3, 0, 0),
+ /* Endpoints for ether gadget, file storage gadget */
+ PXA_EP_OUT_BULK(3, 1, 1, 0, 0),
+ PXA_EP_IN_BULK(4, 2, 1, 0, 0),
+ PXA_EP_IN_ISO(5, 3, 1, 0, 0),
+ PXA_EP_OUT_ISO(6, 4, 1, 0, 0),
+ PXA_EP_IN_INT(7, 5, 1, 0, 0),
+ /* Endpoints for RNDIS, serial */
+ PXA_EP_OUT_BULK(8, 1, 2, 0, 0),
+ PXA_EP_IN_BULK(9, 2, 2, 0, 0),
+ PXA_EP_IN_INT(10, 5, 2, 0, 0),
+ /*
+ * All the following endpoints are only for completion. They
+ * won't never work, as multiple interfaces are really broken on
+ * the pxa.
+ */
+ PXA_EP_OUT_BULK(11, 1, 2, 1, 0),
+ PXA_EP_IN_BULK(12, 2, 2, 1, 0),
+ /* Endpoint for CDC Ether */
+ PXA_EP_OUT_BULK(13, 1, 1, 1, 1),
+ PXA_EP_IN_BULK(14, 2, 1, 1, 1),
+ }
+};
+
+/**
+ * pxa_udc_probe - probes the udc device
+ * @_dev: platform device
+ *
+ * Perform basic init : allocates udc clock, creates sysfs files, requests
+ * irq.
+ */
+static int __init pxa_udc_probe(struct platform_device *pdev)
+{
+ struct resource *regs;
+ struct pxa_udc *udc = &memory;
+ int retval;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!regs)
+ return -ENXIO;
+ udc->irq = platform_get_irq(pdev, 0);
+ if (udc->irq < 0)
+ return udc->irq;
+
+ udc->dev = &pdev->dev;
+ udc->mach = pdev->dev.platform_data;
+
+ udc->clk = clk_get(&pdev->dev, "UDCCLK");
+ if (IS_ERR(udc->clk)) {
+ retval = PTR_ERR(udc->clk);
+ goto err_clk;
+ }
+
+ retval = -ENOMEM;
+ udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+ if (!udc->regs) {
+ dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
+ goto err_map;
+ }
+
+ device_initialize(&udc->gadget.dev);
+ udc->gadget.dev.parent = &pdev->dev;
+ udc->gadget.dev.dma_mask = NULL;
+
+ the_controller = udc;
+ platform_set_drvdata(pdev, udc);
+ udc_init_data(udc);
+ pxa_eps_setup(udc);
+
+ /* irq setup after old hardware state is cleaned up */
+ retval = request_irq(udc->irq, pxa_udc_irq,
+ IRQF_SHARED, driver_name, udc);
+ if (retval != 0) {
+ dev_err(udc->dev, "%s: can't get irq %i, err %d\n",
+ driver_name, IRQ_USB, retval);
+ goto err_irq;
+ }
+
+ pxa_init_debugfs(udc);
+ return 0;
+err_irq:
+ iounmap(udc->regs);
+err_map:
+ clk_put(udc->clk);
+ udc->clk = NULL;
+err_clk:
+ return retval;
+}
+
+/**
+ * pxa_udc_remove - removes the udc device driver
+ * @_dev: platform device
+ */
+static int __exit pxa_udc_remove(struct platform_device *_dev)
+{
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+
+ usb_gadget_unregister_driver(udc->driver);
+ free_irq(udc->irq, udc);
+ pxa_cleanup_debugfs(udc);
+
+ platform_set_drvdata(_dev, NULL);
+ the_controller = NULL;
+ clk_put(udc->clk);
+
+ return 0;
+}
+
+static void pxa_udc_shutdown(struct platform_device *_dev)
+{
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+
+ udc_disable(udc);
+}
+
+#ifdef CONFIG_PM
+/**
+ * pxa_udc_suspend - Suspend udc device
+ * @_dev: platform device
+ * @state: suspend state
+ *
+ * Suspends udc : saves configuration registers (UDCCR*), then disables the udc
+ * device.
+ */
+static int pxa_udc_suspend(struct platform_device *_dev, pm_message_t state)
+{
+ int i;
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+ struct pxa_ep *ep;
+
+ ep = &udc->pxa_ep[0];
+ udc->udccsr0 = udc_ep_readl(ep, UDCCSR);
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ ep->udccsr_value = udc_ep_readl(ep, UDCCSR);
+ ep->udccr_value = udc_ep_readl(ep, UDCCR);
+ ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
+ ep->udccsr_value, ep->udccr_value);
+ }
+
+ udc_disable(udc);
+
+ return 0;
+}
+
+/**
+ * pxa_udc_resume - Resume udc device
+ * @_dev: platform device
+ *
+ * Resumes udc : restores configuration registers (UDCCR*), then enables the udc
+ * device.
+ */
+static int pxa_udc_resume(struct platform_device *_dev)
+{
+ int i;
+ struct pxa_udc *udc = platform_get_drvdata(_dev);
+ struct pxa_ep *ep;
+
+ ep = &udc->pxa_ep[0];
+ udc_ep_writel(ep, UDCCSR, udc->udccsr0 & (UDCCSR0_FST | UDCCSR0_DME));
+ for (i = 1; i < NR_PXA_ENDPOINTS; i++) {
+ ep = &udc->pxa_ep[i];
+ udc_ep_writel(ep, UDCCSR, ep->udccsr_value);
+ udc_ep_writel(ep, UDCCR, ep->udccr_value);
+ ep_dbg(ep, "udccsr:0x%03x, udccr:0x%x\n",
+ ep->udccsr_value, ep->udccr_value);
+ }
+
+ udc_enable(udc);
+ /*
+ * We do not handle OTG yet.
+ *
+ * OTGPH bit is set when sleep mode is entered.
+ * it indicates that OTG pad is retaining its state.
+ * Upon exit from sleep mode and before clearing OTGPH,
+ * Software must configure the USB OTG pad, UDC, and UHC
+ * to the state they were in before entering sleep mode.
+ *
+ * Should be : PSSR |= PSSR_OTGPH;
+ */
+
+ return 0;
+}
+#endif
+
+/* work with hotplug and coldplug */
+MODULE_ALIAS("platform:pxa2xx-udc");
+
+static struct platform_driver udc_driver = {
+ .driver = {
+ .name = "pxa2xx-udc",
+ .owner = THIS_MODULE,
+ },
+ .remove = __exit_p(pxa_udc_remove),
+ .shutdown = pxa_udc_shutdown,
+#ifdef CONFIG_PM
+ .suspend = pxa_udc_suspend,
+ .resume = pxa_udc_resume
+#endif
+};
+
+static int __init udc_init(void)
+{
+ printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
+ return platform_driver_probe(&udc_driver, pxa_udc_probe);
+}
+module_init(udc_init);
+
+
+static void __exit udc_exit(void)
+{
+ platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Robert Jarzmik");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
new file mode 100644
index 0000000..1d1b7936
--- /dev/null
+++ b/drivers/usb/gadget/pxa27x_udc.h
@@ -0,0 +1,487 @@
+/*
+ * linux/drivers/usb/gadget/pxa27x_udc.h
+ * Intel PXA27x on-chip full speed USB device controller
+ *
+ * Inspired by original driver by Frank Becker, David Brownell, and others.
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __LINUX_USB_GADGET_PXA27X_H
+#define __LINUX_USB_GADGET_PXA27X_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+
+/*
+ * Register definitions
+ */
+/* Offsets */
+#define UDCCR 0x0000 /* UDC Control Register */
+#define UDCICR0 0x0004 /* UDC Interrupt Control Register0 */
+#define UDCICR1 0x0008 /* UDC Interrupt Control Register1 */
+#define UDCISR0 0x000C /* UDC Interrupt Status Register 0 */
+#define UDCISR1 0x0010 /* UDC Interrupt Status Register 1 */
+#define UDCFNR 0x0014 /* UDC Frame Number Register */
+#define UDCOTGICR 0x0018 /* UDC On-The-Go interrupt control */
+#define UP2OCR 0x0020 /* USB Port 2 Output Control register */
+#define UP3OCR 0x0024 /* USB Port 3 Output Control register */
+#define UDCCSRn(x) (0x0100 + ((x)<<2)) /* UDC Control/Status register */
+#define UDCBCRn(x) (0x0200 + ((x)<<2)) /* UDC Byte Count Register */
+#define UDCDRn(x) (0x0300 + ((x)<<2)) /* UDC Data Register */
+#define UDCCRn(x) (0x0400 + ((x)<<2)) /* UDC Control Register */
+
+#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */
+#define UDCCR_AALTHNP (1 << 30) /* A-device Alternate Host Negotiation
+ Protocol Port Support */
+#define UDCCR_AHNP (1 << 29) /* A-device Host Negotiation Protocol
+ Support */
+#define UDCCR_BHNP (1 << 28) /* B-device Host Negotiation Protocol
+ Enable */
+#define UDCCR_DWRE (1 << 16) /* Device Remote Wake-up Enable */
+#define UDCCR_ACN (0x03 << 11) /* Active UDC configuration Number */
+#define UDCCR_ACN_S 11
+#define UDCCR_AIN (0x07 << 8) /* Active UDC interface Number */
+#define UDCCR_AIN_S 8
+#define UDCCR_AAISN (0x07 << 5) /* Active UDC Alternate Interface
+ Setting Number */
+#define UDCCR_AAISN_S 5
+#define UDCCR_SMAC (1 << 4) /* Switch Endpoint Memory to Active
+ Configuration */
+#define UDCCR_EMCE (1 << 3) /* Endpoint Memory Configuration
+ Error */
+#define UDCCR_UDR (1 << 2) /* UDC Resume */
+#define UDCCR_UDA (1 << 1) /* UDC Active */
+#define UDCCR_UDE (1 << 0) /* UDC Enable */
+
+#define UDCICR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCICR1_IECC (1 << 31) /* IntEn - Configuration Change */
+#define UDCICR1_IESOF (1 << 30) /* IntEn - Start of Frame */
+#define UDCICR1_IERU (1 << 29) /* IntEn - Resume */
+#define UDCICR1_IESU (1 << 28) /* IntEn - Suspend */
+#define UDCICR1_IERS (1 << 27) /* IntEn - Reset */
+#define UDCICR_FIFOERR (1 << 1) /* FIFO Error interrupt for EP */
+#define UDCICR_PKTCOMPL (1 << 0) /* Packet Complete interrupt for EP */
+#define UDCICR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
+
+#define UDCISR_INT(n, intr) (((intr) & 0x03) << (((n) & 0x0F) * 2))
+#define UDCISR1_IRCC (1 << 31) /* IntReq - Configuration Change */
+#define UDCISR1_IRSOF (1 << 30) /* IntReq - Start of Frame */
+#define UDCISR1_IRRU (1 << 29) /* IntReq - Resume */
+#define UDCISR1_IRSU (1 << 28) /* IntReq - Suspend */
+#define UDCISR1_IRRS (1 << 27) /* IntReq - Reset */
+#define UDCISR_INT_MASK (UDCICR_FIFOERR | UDCICR_PKTCOMPL)
+
+#define UDCOTGICR_IESF (1 << 24) /* OTG SET_FEATURE command recvd */
+#define UDCOTGICR_IEXR (1 << 17) /* Extra Transciever Interrupt
+ Rising Edge Interrupt Enable */
+#define UDCOTGICR_IEXF (1 << 16) /* Extra Transciever Interrupt
+ Falling Edge Interrupt Enable */
+#define UDCOTGICR_IEVV40R (1 << 9) /* OTG Vbus Valid 4.0V Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEVV40F (1 << 8) /* OTG Vbus Valid 4.0V Falling Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEVV44R (1 << 7) /* OTG Vbus Valid 4.4V Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEVV44F (1 << 6) /* OTG Vbus Valid 4.4V Falling Edge
+ Interrupt Enable */
+#define UDCOTGICR_IESVR (1 << 5) /* OTG Session Valid Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IESVF (1 << 4) /* OTG Session Valid Falling Edge
+ Interrupt Enable */
+#define UDCOTGICR_IESDR (1 << 3) /* OTG A-Device SRP Detect Rising
+ Edge Interrupt Enable */
+#define UDCOTGICR_IESDF (1 << 2) /* OTG A-Device SRP Detect Falling
+ Edge Interrupt Enable */
+#define UDCOTGICR_IEIDR (1 << 1) /* OTG ID Change Rising Edge
+ Interrupt Enable */
+#define UDCOTGICR_IEIDF (1 << 0) /* OTG ID Change Falling Edge
+ Interrupt Enable */
+
+/* Host Port 2 field bits */
+#define UP2OCR_CPVEN (1 << 0) /* Charge Pump Vbus Enable */
+#define UP2OCR_CPVPE (1 << 1) /* Charge Pump Vbus Pulse Enable */
+ /* Transceiver enablers */
+#define UP2OCR_DPPDE (1 << 2) /* D+ Pull Down Enable */
+#define UP2OCR_DMPDE (1 << 3) /* D- Pull Down Enable */
+#define UP2OCR_DPPUE (1 << 4) /* D+ Pull Up Enable */
+#define UP2OCR_DMPUE (1 << 5) /* D- Pull Up Enable */
+#define UP2OCR_DPPUBE (1 << 6) /* D+ Pull Up Bypass Enable */
+#define UP2OCR_DMPUBE (1 << 7) /* 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) /* Transceiver Output Select */
+#define UP2OCR_HXOE (1 << 17) /* Transceiver Output Enable */
+#define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */
+
+#define UDCCSR0_SA (1 << 7) /* Setup Active */
+#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */
+#define UDCCSR0_FST (1 << 5) /* Force Stall */
+#define UDCCSR0_SST (1 << 4) /* Sent Stall */
+#define UDCCSR0_DME (1 << 3) /* DMA Enable */
+#define UDCCSR0_FTF (1 << 2) /* Flush Transmit FIFO */
+#define UDCCSR0_IPR (1 << 1) /* IN Packet Ready */
+#define UDCCSR0_OPC (1 << 0) /* OUT Packet Complete */
+
+#define UDCCSR_DPE (1 << 9) /* Data Packet Error */
+#define UDCCSR_FEF (1 << 8) /* Flush Endpoint FIFO */
+#define UDCCSR_SP (1 << 7) /* Short Packet Control/Status */
+#define UDCCSR_BNE (1 << 6) /* Buffer Not Empty (IN endpoints) */
+#define UDCCSR_BNF (1 << 6) /* Buffer Not Full (OUT endpoints) */
+#define UDCCSR_FST (1 << 5) /* Force STALL */
+#define UDCCSR_SST (1 << 4) /* Sent STALL */
+#define UDCCSR_DME (1 << 3) /* DMA Enable */
+#define UDCCSR_TRN (1 << 2) /* Tx/Rx NAK */
+#define UDCCSR_PC (1 << 1) /* Packet Complete */
+#define UDCCSR_FS (1 << 0) /* FIFO needs service */
+
+#define UDCCONR_CN (0x03 << 25) /* Configuration Number */
+#define UDCCONR_CN_S 25
+#define UDCCONR_IN (0x07 << 22) /* Interface Number */
+#define UDCCONR_IN_S 22
+#define UDCCONR_AISN (0x07 << 19) /* Alternate Interface Number */
+#define UDCCONR_AISN_S 19
+#define UDCCONR_EN (0x0f << 15) /* Endpoint Number */
+#define UDCCONR_EN_S 15
+#define UDCCONR_ET (0x03 << 13) /* Endpoint Type: */
+#define UDCCONR_ET_S 13
+#define UDCCONR_ET_INT (0x03 << 13) /* Interrupt */
+#define UDCCONR_ET_BULK (0x02 << 13) /* Bulk */
+#define UDCCONR_ET_ISO (0x01 << 13) /* Isochronous */
+#define UDCCONR_ET_NU (0x00 << 13) /* Not used */
+#define UDCCONR_ED (1 << 12) /* Endpoint Direction */
+#define UDCCONR_MPS (0x3ff << 2) /* Maximum Packet Size */
+#define UDCCONR_MPS_S 2
+#define UDCCONR_DE (1 << 1) /* Double Buffering Enable */
+#define UDCCONR_EE (1 << 0) /* Endpoint Enable */
+
+#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_SMAC | UDCCR_UDR | UDCCR_UDE)
+#define UDCCSR_WR_MASK (UDCCSR_DME | UDCCSR_FST)
+#define UDC_FNR_MASK (0x7ff)
+#define UDC_BCR_MASK (0x3ff)
+
+/*
+ * UDCCR = UDC Endpoint Configuration Registers
+ * UDCCSR = UDC Control/Status Register for this EP
+ * UDCBCR = UDC Byte Count Remaining (contents of OUT fifo)
+ * UDCDR = UDC Endpoint Data Register (the fifo)
+ */
+#define ofs_UDCCR(ep) (UDCCRn(ep->idx))
+#define ofs_UDCCSR(ep) (UDCCSRn(ep->idx))
+#define ofs_UDCBCR(ep) (UDCBCRn(ep->idx))
+#define ofs_UDCDR(ep) (UDCDRn(ep->idx))
+
+/* Register access macros */
+#define udc_ep_readl(ep, reg) \
+ __raw_readl((ep)->dev->regs + ofs_##reg(ep))
+#define udc_ep_writel(ep, reg, value) \
+ __raw_writel((value), ep->dev->regs + ofs_##reg(ep))
+#define udc_ep_readb(ep, reg) \
+ __raw_readb((ep)->dev->regs + ofs_##reg(ep))
+#define udc_ep_writeb(ep, reg, value) \
+ __raw_writeb((value), ep->dev->regs + ofs_##reg(ep))
+#define udc_readl(dev, reg) \
+ __raw_readl((dev)->regs + (reg))
+#define udc_writel(udc, reg, value) \
+ __raw_writel((value), (udc)->regs + (reg))
+
+#define UDCCSR_MASK (UDCCSR_FST | UDCCSR_DME)
+#define UDCCISR0_EP_MASK ~0
+#define UDCCISR1_EP_MASK 0xffff
+#define UDCCSR0_CTRL_REQ_MASK (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)
+
+#define EPIDX(ep) (ep->idx)
+#define EPADDR(ep) (ep->addr)
+#define EPXFERTYPE(ep) (ep->type)
+#define EPNAME(ep) (ep->name)
+#define is_ep0(ep) (!ep->idx)
+#define EPXFERTYPE_is_ISO(ep) (EPXFERTYPE(ep) == USB_ENDPOINT_XFER_ISOC)
+
+/*
+ * Endpoint definitions
+ *
+ * Once enabled, pxa endpoint configuration is freezed, and cannot change
+ * unless a reset happens or the udc is disabled.
+ * Therefore, we must define all pxa potential endpoint definitions needed for
+ * all gadget and set them up before the udc is enabled.
+ *
+ * As the architecture chosen is fully static, meaning the pxa endpoint
+ * configurations are set up once and for all, we must provide a way to match
+ * one usb endpoint (usb_ep) to several pxa endpoints. The reason is that gadget
+ * layer autoconf doesn't choose the usb_ep endpoint on (config, interface, alt)
+ * criteria, while the pxa architecture requires that.
+ *
+ * The solution is to define several pxa endpoints matching one usb_ep. Ex:
+ * - "ep1-in" matches pxa endpoint EPA (which is an IN ep at addr 1, when
+ * the udc talks on (config=3, interface=0, alt=0)
+ * - "ep1-in" matches pxa endpoint EPB (which is an IN ep at addr 1, when
+ * the udc talks on (config=3, interface=0, alt=1)
+ * - "ep1-in" matches pxa endpoint EPC (which is an IN ep at addr 1, when
+ * the udc talks on (config=2, interface=0, alt=0)
+ *
+ * We'll define the pxa endpoint by its index (EPA => idx=1, EPB => idx=2, ...)
+ */
+
+/*
+ * Endpoint definition helpers
+ */
+#define USB_EP_DEF(addr, bname, dir, type, maxpkt) \
+{ .usb_ep = { .name = bname, .ops = &pxa_ep_ops, .maxpacket = maxpkt, }, \
+ .desc = { .bEndpointAddress = addr | (dir ? USB_DIR_IN : 0), \
+ .bmAttributes = type, \
+ .wMaxPacketSize = maxpkt, }, \
+ .dev = &memory \
+}
+#define USB_EP_BULK(addr, bname, dir) \
+ USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE)
+#define USB_EP_ISO(addr, bname, dir) \
+ USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE)
+#define USB_EP_INT(addr, bname, dir) \
+ USB_EP_DEF(addr, bname, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE)
+#define USB_EP_IN_BULK(n) USB_EP_BULK(n, "ep" #n "in-bulk", 1)
+#define USB_EP_OUT_BULK(n) USB_EP_BULK(n, "ep" #n "out-bulk", 0)
+#define USB_EP_IN_ISO(n) USB_EP_ISO(n, "ep" #n "in-iso", 1)
+#define USB_EP_OUT_ISO(n) USB_EP_ISO(n, "ep" #n "out-iso", 0)
+#define USB_EP_IN_INT(n) USB_EP_INT(n, "ep" #n "in-int", 1)
+#define USB_EP_CTRL USB_EP_DEF(0, "ep0", 0, 0, EP0_FIFO_SIZE)
+
+#define PXA_EP_DEF(_idx, _addr, dir, _type, maxpkt, _config, iface, altset) \
+{ \
+ .dev = &memory, \
+ .name = "ep" #_idx, \
+ .idx = _idx, .enabled = 0, \
+ .dir_in = dir, .addr = _addr, \
+ .config = _config, .interface = iface, .alternate = altset, \
+ .type = _type, .fifo_size = maxpkt, \
+}
+#define PXA_EP_BULK(_idx, addr, dir, config, iface, alt) \
+ PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_BULK, BULK_FIFO_SIZE, \
+ config, iface, alt)
+#define PXA_EP_ISO(_idx, addr, dir, config, iface, alt) \
+ PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_ISOC, ISO_FIFO_SIZE, \
+ config, iface, alt)
+#define PXA_EP_INT(_idx, addr, dir, config, iface, alt) \
+ PXA_EP_DEF(_idx, addr, dir, USB_ENDPOINT_XFER_INT, INT_FIFO_SIZE, \
+ config, iface, alt)
+#define PXA_EP_IN_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 1, c, f, a)
+#define PXA_EP_OUT_BULK(i, adr, c, f, a) PXA_EP_BULK(i, adr, 0, c, f, a)
+#define PXA_EP_IN_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 1, c, f, a)
+#define PXA_EP_OUT_ISO(i, adr, c, f, a) PXA_EP_ISO(i, adr, 0, c, f, a)
+#define PXA_EP_IN_INT(i, adr, c, f, a) PXA_EP_INT(i, adr, 1, c, f, a)
+#define PXA_EP_CTRL PXA_EP_DEF(0, 0, 0, 0, EP0_FIFO_SIZE, 0, 0, 0)
+
+struct pxa27x_udc;
+
+struct stats {
+ unsigned long in_ops;
+ unsigned long out_ops;
+ unsigned long in_bytes;
+ unsigned long out_bytes;
+ unsigned long irqs;
+};
+
+/**
+ * struct udc_usb_ep - container of each usb_ep structure
+ * @usb_ep: usb endpoint
+ * @desc: usb descriptor, especially type and address
+ * @dev: udc managing this endpoint
+ * @pxa_ep: matching pxa_ep (cache of find_pxa_ep() call)
+ */
+struct udc_usb_ep {
+ struct usb_ep usb_ep;
+ struct usb_endpoint_descriptor desc;
+ struct pxa_udc *dev;
+ struct pxa_ep *pxa_ep;
+};
+
+/**
+ * struct pxa_ep - pxa endpoint
+ * @dev: udc device
+ * @queue: requests queue
+ * @lock: lock to pxa_ep data (queues and stats)
+ * @enabled: true when endpoint enabled (not stopped by gadget layer)
+ * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX)
+ * @name: endpoint name (for trace/debug purpose)
+ * @dir_in: 1 if IN endpoint, 0 if OUT endpoint
+ * @addr: usb endpoint number
+ * @config: configuration in which this endpoint is active
+ * @interface: interface in which this endpoint is active
+ * @alternate: altsetting in which this endpoitn is active
+ * @fifo_size: max packet size in the endpoint fifo
+ * @type: endpoint type (bulk, iso, int, ...)
+ * @udccsr_value: save register of UDCCSR0 for suspend/resume
+ * @udccr_value: save register of UDCCR for suspend/resume
+ * @stats: endpoint statistics
+ *
+ * The *PROBLEM* is that pxa's endpoint configuration scheme is both misdesigned
+ * (cares about config/interface/altsetting, thus placing needless limits on
+ * device capability) and full of implementation bugs forcing it to be set up
+ * for use more or less like a pxa255.
+ *
+ * As we define the pxa_ep statically, we must guess all needed pxa_ep for all
+ * gadget which may work with this udc driver.
+ */
+struct pxa_ep {
+ struct pxa_udc *dev;
+
+ struct list_head queue;
+ spinlock_t lock; /* Protects this structure */
+ /* (queues, stats) */
+ unsigned enabled:1;
+
+ unsigned idx:5;
+ char *name;
+
+ /*
+ * Specific pxa endpoint data, needed for hardware initialization
+ */
+ unsigned dir_in:1;
+ unsigned addr:3;
+ unsigned config:2;
+ unsigned interface:3;
+ unsigned alternate:3;
+ unsigned fifo_size;
+ unsigned type;
+
+#ifdef CONFIG_PM
+ u32 udccsr_value;
+ u32 udccr_value;
+#endif
+ struct stats stats;
+};
+
+/**
+ * struct pxa27x_request - container of each usb_request structure
+ * @req: usb request
+ * @udc_usb_ep: usb endpoint the request was submitted on
+ * @in_use: sanity check if request already queued on an pxa_ep
+ * @queue: linked list of requests, linked on pxa_ep->queue
+ */
+struct pxa27x_request {
+ struct usb_request req;
+ struct udc_usb_ep *udc_usb_ep;
+ unsigned in_use:1;
+ struct list_head queue;
+};
+
+enum ep0_state {
+ WAIT_FOR_SETUP,
+ SETUP_STAGE,
+ IN_DATA_STAGE,
+ OUT_DATA_STAGE,
+ IN_STATUS_STAGE,
+ OUT_STATUS_STAGE,
+ STALL,
+ WAIT_ACK_SET_CONF_INTERF
+};
+
+static char *ep0_state_name[] = {
+ "WAIT_FOR_SETUP", "SETUP_STAGE", "IN_DATA_STAGE", "OUT_DATA_STAGE",
+ "IN_STATUS_STAGE", "OUT_STATUS_STAGE", "STALL",
+ "WAIT_ACK_SET_CONF_INTERF"
+};
+#define EP0_STNAME(udc) ep0_state_name[(udc)->ep0state]
+
+#define EP0_FIFO_SIZE 16U
+#define BULK_FIFO_SIZE 64U
+#define ISO_FIFO_SIZE 256U
+#define INT_FIFO_SIZE 16U
+
+struct udc_stats {
+ unsigned long irqs_reset;
+ unsigned long irqs_suspend;
+ unsigned long irqs_resume;
+ unsigned long irqs_reconfig;
+};
+
+#define NR_USB_ENDPOINTS (1 + 5) /* ep0 + ep1in-bulk + .. + ep3in-iso */
+#define NR_PXA_ENDPOINTS (1 + 14) /* ep0 + epA + epB + .. + epX */
+
+/**
+ * struct pxa_udc - udc structure
+ * @regs: mapped IO space
+ * @irq: udc irq
+ * @clk: udc clock
+ * @usb_gadget: udc gadget structure
+ * @driver: bound gadget (zero, g_ether, g_file_storage, ...)
+ * @dev: device
+ * @mach: machine info, used to activate specific GPIO
+ * @ep0state: control endpoint state machine state
+ * @stats: statistics on udc usage
+ * @udc_usb_ep: array of usb endpoints offered by the gadget
+ * @pxa_ep: array of pxa available endpoints
+ * @config: UDC active configuration
+ * @last_interface: UDC interface of the last SET_INTERFACE host request
+ * @last_alternate: UDC altsetting of the last SET_INTERFACE host request
+ * @udccsr0: save of udccsr0 in case of suspend
+ * @debugfs_root: root entry of debug filesystem
+ * @debugfs_state: debugfs entry for "udcstate"
+ * @debugfs_queues: debugfs entry for "queues"
+ * @debugfs_eps: debugfs entry for "epstate"
+ */
+struct pxa_udc {
+ void __iomem *regs;
+ int irq;
+ struct clk *clk;
+
+ struct usb_gadget gadget;
+ struct usb_gadget_driver *driver;
+ struct device *dev;
+ struct pxa2xx_udc_mach_info *mach;
+
+ enum ep0_state ep0state;
+ struct udc_stats stats;
+
+ struct udc_usb_ep udc_usb_ep[NR_USB_ENDPOINTS];
+ struct pxa_ep pxa_ep[NR_PXA_ENDPOINTS];
+
+ unsigned config:2;
+ unsigned last_interface:3;
+ unsigned last_alternate:3;
+
+#ifdef CONFIG_PM
+ unsigned udccsr0;
+#endif
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+ struct dentry *debugfs_root;
+ struct dentry *debugfs_state;
+ struct dentry *debugfs_queues;
+ struct dentry *debugfs_eps;
+#endif
+};
+
+static inline struct pxa_udc *to_gadget_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct pxa_udc, gadget);
+}
+
+/*
+ * Debugging/message support
+ */
+#define ep_dbg(ep, fmt, arg...) \
+ dev_dbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_vdbg(ep, fmt, arg...) \
+ dev_vdbg(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_err(ep, fmt, arg...) \
+ dev_err(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_info(ep, fmt, arg...) \
+ dev_info(ep->dev->dev, "%s:%s: " fmt, EPNAME(ep), __func__, ## arg)
+#define ep_warn(ep, fmt, arg...) \
+ dev_warn(ep->dev->dev, "%s:%s:" fmt, EPNAME(ep), __func__, ## arg)
+
+#endif /* __LINUX_USB_GADGET_PXA27X_H */
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index bd58dd5..d0677f5 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -183,14 +183,10 @@
DBG("query OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
DBG("%03d: %08x %08x %08x %08x\n", i,
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 4])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 8])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 12])));
+ get_unaligned_le32(&buf[i]),
+ get_unaligned_le32(&buf[i + 4]),
+ get_unaligned_le32(&buf[i + 8]),
+ get_unaligned_le32(&buf[i + 12]));
}
}
@@ -666,7 +662,7 @@
break;
case OID_PNP_QUERY_POWER:
DBG("%s: OID_PNP_QUERY_POWER D%d\n", __func__,
- le32_to_cpu(get_unaligned((__le32 *)buf)) - 1);
+ get_unaligned_le32(buf) - 1);
/* only suspend is a real power state, and
* it can't be entered by OID_PNP_SET_POWER...
*/
@@ -705,14 +701,10 @@
DBG("set OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
DBG("%03d: %08x %08x %08x %08x\n", i,
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 4])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 8])),
- le32_to_cpu(get_unaligned((__le32 *)
- &buf[i + 12])));
+ get_unaligned_le32(&buf[i]),
+ get_unaligned_le32(&buf[i + 4]),
+ get_unaligned_le32(&buf[i + 8]),
+ get_unaligned_le32(&buf[i + 12]));
}
}
@@ -726,8 +718,7 @@
* PROMISCUOUS, DIRECTED,
* MULTICAST, ALL_MULTICAST, BROADCAST
*/
- *params->filter = (u16) le32_to_cpu(get_unaligned(
- (__le32 *)buf));
+ *params->filter = (u16)get_unaligned_le32(buf);
DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__func__, *params->filter);
@@ -777,7 +768,7 @@
* resuming, Windows forces a reset, and then SET_POWER D0.
* FIXME ... then things go batty; Windows wedges itself.
*/
- i = le32_to_cpu(get_unaligned((__le32 *)buf));
+ i = get_unaligned_le32(buf);
DBG("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1);
switch (i) {
case NdisDeviceStateD0:
@@ -1064,8 +1055,8 @@
return -ENOMEM;
tmp = (__le32 *) buf;
- MsgType = le32_to_cpu(get_unaligned(tmp++));
- MsgLength = le32_to_cpu(get_unaligned(tmp++));
+ MsgType = get_unaligned_le32(tmp++);
+ MsgLength = get_unaligned_le32(tmp++);
if (configNr >= RNDIS_MAX_CONFIGS)
return -ENOTSUPP;
@@ -1296,10 +1287,9 @@
tmp++;
/* DataOffset, DataLength */
- if (!skb_pull(skb, le32_to_cpu(get_unaligned(tmp++))
- + 8 /* offset of DataOffset */))
+ if (!skb_pull(skb, get_unaligned_le32(tmp++) + 8))
return -EOVERFLOW;
- skb_trim(skb, le32_to_cpu(get_unaligned(tmp++)));
+ skb_trim(skb, get_unaligned_le32(tmp++));
return 0;
}
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 433b3f4..54cdd6f 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -135,7 +135,10 @@
int port_in_use; /* open/close in progress */
wait_queue_head_t port_write_wait;/* waiting to write */
struct gs_buf *port_write_buf;
- struct usb_cdc_line_coding port_line_coding;
+ struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
+ u16 port_handshake_bits;
+#define RS232_RTS (1 << 1)
+#define RS232_DTE (1 << 0)
};
/* the device structure holds info for the USB device */
@@ -170,7 +173,7 @@
static void gs_close(struct tty_struct *tty, struct file *file);
static int gs_write(struct tty_struct *tty,
const unsigned char *buf, int count);
-static void gs_put_char(struct tty_struct *tty, unsigned char ch);
+static int gs_put_char(struct tty_struct *tty, unsigned char ch);
static void gs_flush_chars(struct tty_struct *tty);
static int gs_write_room(struct tty_struct *tty);
static int gs_chars_in_buffer(struct tty_struct *tty);
@@ -199,6 +202,8 @@
static int gs_setup_class(struct usb_gadget *gadget,
const struct usb_ctrlrequest *ctrl);
static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
+static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+ struct usb_request *req);
static void gs_disconnect(struct usb_gadget *gadget);
static int gs_set_config(struct gs_dev *dev, unsigned config);
static void gs_reset_config(struct gs_dev *dev);
@@ -406,7 +411,7 @@
.bLength = sizeof(gs_acm_descriptor),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ACM_TYPE,
- .bmCapabilities = 0,
+ .bmCapabilities = (1 << 1),
};
static const struct usb_cdc_union_desc gs_union_desc = {
@@ -883,14 +888,15 @@
/*
* gs_put_char
*/
-static void gs_put_char(struct tty_struct *tty, unsigned char ch)
+static int gs_put_char(struct tty_struct *tty, unsigned char ch)
{
unsigned long flags;
struct gs_port *port = tty->driver_data;
+ int ret = 0;
if (port == NULL) {
pr_err("gs_put_char: NULL port pointer\n");
- return;
+ return 0;
}
gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
@@ -910,10 +916,11 @@
goto exit;
}
- gs_buf_put(port->port_write_buf, &ch, 1);
+ ret = gs_buf_put(port->port_write_buf, &ch, 1);
exit:
spin_unlock_irqrestore(&port->port_lock, flags);
+ return ret;
}
/*
@@ -1500,6 +1507,8 @@
u16 wValue = le16_to_cpu(ctrl->wValue);
u16 wLength = le16_to_cpu(ctrl->wLength);
+ req->complete = gs_setup_complete;
+
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
ret = gs_setup_standard(gadget,ctrl);
@@ -1677,18 +1686,14 @@
switch (ctrl->bRequest) {
case USB_CDC_REQ_SET_LINE_CODING:
- /* FIXME Submit req to read the data; have its completion
- * handler copy that data to port->port_line_coding (iff
- * it's valid) and maybe pass it on. Until then, fail.
- */
- pr_warning("gs_setup: set_line_coding "
- "unuspported\n");
+ if (wLength != sizeof(struct usb_cdc_line_coding))
+ break;
+ ret = wLength;
+ req->complete = gs_setup_complete_set_line_coding;
break;
case USB_CDC_REQ_GET_LINE_CODING:
- port = dev->dev_port[0]; /* ACM only has one port */
- ret = min(wLength,
- (u16)sizeof(struct usb_cdc_line_coding));
+ ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding));
if (port) {
spin_lock(&port->port_lock);
memcpy(req->buf, &port->port_line_coding, ret);
@@ -1697,15 +1702,27 @@
break;
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- /* FIXME Submit req to read the data; have its completion
- * handler use that to set the state (iff it's valid) and
- * maybe pass it on. Until then, fail.
- */
- pr_warning("gs_setup: set_control_line_state "
- "unuspported\n");
+ if (wLength != 0)
+ break;
+ ret = 0;
+ if (port) {
+ /* REVISIT: we currently just remember this data.
+ * If we change that, update whatever hardware needs
+ * updating.
+ */
+ spin_lock(&port->port_lock);
+ port->port_handshake_bits = wValue;
+ spin_unlock(&port->port_lock);
+ }
break;
default:
+ /* NOTE: strictly speaking, we should accept AT-commands
+ * using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE.
+ * But our call management descriptor says we don't handle
+ * call management, so we should be able to get by without
+ * handling those "required" commands (except by stalling).
+ */
pr_err("gs_setup: unknown class request, "
"type=%02x, request=%02x, value=%04x, "
"index=%04x, length=%d\n",
@@ -1717,6 +1734,42 @@
return ret;
}
+static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
+ struct usb_request *req)
+{
+ struct gs_dev *dev = ep->driver_data;
+ struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
+
+ switch (req->status) {
+ case 0:
+ /* normal completion */
+ if (req->actual != sizeof(port->port_line_coding))
+ usb_ep_set_halt(ep);
+ else if (port) {
+ struct usb_cdc_line_coding *value = req->buf;
+
+ /* REVISIT: we currently just remember this data.
+ * If we change that, (a) validate it first, then
+ * (b) update whatever hardware needs updating.
+ */
+ spin_lock(&port->port_lock);
+ port->port_line_coding = *value;
+ spin_unlock(&port->port_lock);
+ }
+ break;
+
+ case -ESHUTDOWN:
+ /* disconnect */
+ gs_free_req(ep, req);
+ break;
+
+ default:
+ /* unexpected */
+ break;
+ }
+ return;
+}
+
/*
* gs_setup_complete
*/
@@ -1904,6 +1957,11 @@
}
}
+ /* REVISIT the ACM mode should be able to actually *issue* some
+ * notifications, for at least serial state change events if
+ * not also for network connection; say so in bmCapabilities.
+ */
+
pr_info("gs_set_config: %s configured, %s speed %s config\n",
GS_LONG_NAME,
gadget->speed == USB_SPEED_HIGH ? "high" : "full",
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 878e428..4154be3 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -74,7 +74,7 @@
goto fail;
} else
uchar = c;
- put_unaligned (cpu_to_le16 (uchar), cp++);
+ put_unaligned_le16(uchar, cp++);
count++;
len--;
}
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index d3d4f40..fce4924 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -23,9 +23,7 @@
/*
* Gadget Zero only needs two bulk endpoints, and is an example of how you
* can write a hardware-agnostic gadget driver running inside a USB device.
- *
- * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
- * affect most of the driver.
+ * Some hardware details are visible, but don't affect most of the driver.
*
* Use it with the Linux host/master side "usbtest" driver to get a basic
* functional test of your device-side usb stack, or with "usb-skeleton".
@@ -37,6 +35,7 @@
* buflen=N default N=4096, buffer size used
* qlen=N default N=32, how many buffers in the loopback queue
* loopdefault default false, list loopback config first
+ * autoresume=N default N=0, seconds before triggering remote wakeup
*
* Many drivers will only have one configuration, letting them be much
* simpler if they also don't support high speed operation (like this
@@ -62,13 +61,13 @@
/*-------------------------------------------------------------------------*/
-#define DRIVER_VERSION "Lughnasadh, 2007"
+#define DRIVER_VERSION "Earth Day 2008"
-static const char shortname [] = "zero";
-static const char longname [] = "Gadget Zero";
+static const char shortname[] = "zero";
+static const char longname[] = "Gadget Zero";
-static const char source_sink [] = "source and sink data";
-static const char loopback [] = "loop input to output";
+static const char source_sink[] = "source and sink data";
+static const char loopback[] = "loop input to output";
/*-------------------------------------------------------------------------*/
@@ -120,16 +119,16 @@
static unsigned qlen = 32;
static unsigned pattern = 0;
-module_param (buflen, uint, S_IRUGO);
-module_param (qlen, uint, S_IRUGO);
-module_param (pattern, uint, S_IRUGO|S_IWUSR);
+module_param(buflen, uint, S_IRUGO);
+module_param(qlen, uint, S_IRUGO);
+module_param(pattern, uint, S_IRUGO|S_IWUSR);
/*
* if it's nonzero, autoresume says how many seconds to wait
* before trying to wake up the host after suspend.
*/
static unsigned autoresume = 0;
-module_param (autoresume, uint, 0);
+module_param(autoresume, uint, 0);
/*
* Normally the "loopback" configuration is second (index 1) so
@@ -138,8 +137,7 @@
* Or controllers (like superh) that only support one config.
*/
static int loopdefault = 0;
-
-module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
+module_param(loopdefault, bool, S_IRUGO|S_IWUSR);
/*-------------------------------------------------------------------------*/
@@ -176,24 +174,22 @@
#define CONFIG_SOURCE_SINK 3
#define CONFIG_LOOPBACK 2
-static struct usb_device_descriptor
-device_desc = {
+static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = __constant_cpu_to_le16 (0x0200),
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
- .idVendor = __constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
- .idProduct = __constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
+ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+ .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
.iManufacturer = STRING_MANUFACTURER,
.iProduct = STRING_PRODUCT,
.iSerialNumber = STRING_SERIAL,
.bNumConfigurations = 2,
};
-static struct usb_config_descriptor
-source_sink_config = {
+static struct usb_config_descriptor source_sink_config = {
.bLength = sizeof source_sink_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -205,8 +201,7 @@
.bMaxPower = 1, /* self-powered */
};
-static struct usb_config_descriptor
-loopback_config = {
+static struct usb_config_descriptor loopback_config = {
.bLength = sizeof loopback_config,
.bDescriptorType = USB_DT_CONFIG,
@@ -218,8 +213,7 @@
.bMaxPower = 1, /* self-powered */
};
-static struct usb_otg_descriptor
-otg_descriptor = {
+static struct usb_otg_descriptor otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
@@ -228,8 +222,7 @@
/* one interface in each configuration */
-static const struct usb_interface_descriptor
-source_sink_intf = {
+static const struct usb_interface_descriptor source_sink_intf = {
.bLength = sizeof source_sink_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -238,8 +231,7 @@
.iInterface = STRING_SOURCE_SINK,
};
-static const struct usb_interface_descriptor
-loopback_intf = {
+static const struct usb_interface_descriptor loopback_intf = {
.bLength = sizeof loopback_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -250,8 +242,7 @@
/* two full speed bulk endpoints; their use is config-dependent */
-static struct usb_endpoint_descriptor
-fs_source_desc = {
+static struct usb_endpoint_descriptor fs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -259,8 +250,7 @@
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor
-fs_sink_desc = {
+static struct usb_endpoint_descriptor fs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -268,7 +258,7 @@
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static const struct usb_descriptor_header *fs_source_sink_function [] = {
+static const struct usb_descriptor_header *fs_source_sink_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &fs_sink_desc,
@@ -276,7 +266,7 @@
NULL,
};
-static const struct usb_descriptor_header *fs_loopback_function [] = {
+static const struct usb_descriptor_header *fs_loopback_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &fs_sink_desc,
@@ -293,36 +283,33 @@
* for the config descriptor.
*/
-static struct usb_endpoint_descriptor
-hs_source_desc = {
+static struct usb_endpoint_descriptor hs_source_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = __constant_cpu_to_le16 (512),
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor
-hs_sink_desc = {
+static struct usb_endpoint_descriptor hs_sink_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = __constant_cpu_to_le16 (512),
+ .wMaxPacketSize = __constant_cpu_to_le16(512),
};
-static struct usb_qualifier_descriptor
-dev_qualifier = {
+static struct usb_qualifier_descriptor dev_qualifier = {
.bLength = sizeof dev_qualifier,
.bDescriptorType = USB_DT_DEVICE_QUALIFIER,
- .bcdUSB = __constant_cpu_to_le16 (0x0200),
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
.bDeviceClass = USB_CLASS_VENDOR_SPEC,
.bNumConfigurations = 2,
};
-static const struct usb_descriptor_header *hs_source_sink_function [] = {
+static const struct usb_descriptor_header *hs_source_sink_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &source_sink_intf,
(struct usb_descriptor_header *) &hs_source_desc,
@@ -330,7 +317,7 @@
NULL,
};
-static const struct usb_descriptor_header *hs_loopback_function [] = {
+static const struct usb_descriptor_header *hs_loopback_function[] = {
(struct usb_descriptor_header *) &otg_descriptor,
(struct usb_descriptor_header *) &loopback_intf,
(struct usb_descriptor_header *) &hs_source_desc,
@@ -355,7 +342,7 @@
/* static strings, in UTF-8 */
-static struct usb_string strings [] = {
+static struct usb_string strings[] = {
{ STRING_MANUFACTURER, manufacturer, },
{ STRING_PRODUCT, longname, },
{ STRING_SERIAL, serial, },
@@ -364,7 +351,7 @@
{ } /* end of list */
};
-static struct usb_gadget_strings stringtab = {
+static struct usb_gadget_strings stringtab = {
.language = 0x0409, /* en-us */
.strings = strings,
};
@@ -387,8 +374,7 @@
* high bandwidth modes at high speed. (Maybe work like Intel's test
* device?)
*/
-static int
-config_buf (struct usb_gadget *gadget,
+static int config_buf(struct usb_gadget *gadget,
u8 *buf, u8 type, unsigned index)
{
int is_source_sink;
@@ -419,7 +405,7 @@
if (!gadget_is_otg(gadget))
function++;
- len = usb_gadget_config_buf (is_source_sink
+ len = usb_gadget_config_buf(is_source_sink
? &source_sink_config
: &loopback_config,
buf, USB_BUFSIZ, function);
@@ -431,27 +417,26 @@
/*-------------------------------------------------------------------------*/
-static struct usb_request *
-alloc_ep_req (struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
{
struct usb_request *req;
- req = usb_ep_alloc_request (ep, GFP_ATOMIC);
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
if (req) {
req->length = length;
req->buf = kmalloc(length, GFP_ATOMIC);
if (!req->buf) {
- usb_ep_free_request (ep, req);
+ usb_ep_free_request(ep, req);
req = NULL;
}
}
return req;
}
-static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
+static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
{
kfree(req->buf);
- usb_ep_free_request (ep, req);
+ usb_ep_free_request(ep, req);
}
/*-------------------------------------------------------------------------*/
@@ -472,7 +457,7 @@
/* optionally require specific source/sink data patterns */
static int
-check_read_data (
+check_read_data(
struct zero_dev *dev,
struct usb_ep *ep,
struct usb_request *req
@@ -498,8 +483,8 @@
continue;
break;
}
- ERROR (dev, "bad OUT byte, buf [%d] = %d\n", i, *buf);
- usb_ep_set_halt (ep);
+ ERROR(dev, "bad OUT byte, buf[%d] = %d\n", i, *buf);
+ usb_ep_set_halt(ep);
return -EINVAL;
}
return 0;
@@ -512,7 +497,7 @@
switch (pattern) {
case 0:
- memset (req->buf, 0, req->length);
+ memset(req->buf, 0, req->length);
break;
case 1:
for (i = 0; i < req->length; i++)
@@ -525,7 +510,7 @@
* irq delay between end of one request and start of the next.
* that prevents using hardware dma queues.
*/
-static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
+static void source_sink_complete(struct usb_ep *ep, struct usb_request *req)
{
struct zero_dev *dev = ep->driver_data;
int status = req->status;
@@ -534,8 +519,8 @@
case 0: /* normal completion? */
if (ep == dev->out_ep) {
- check_read_data (dev, ep, req);
- memset (req->buf, 0x55, req->length);
+ check_read_data(dev, ep, req);
+ memset(req->buf, 0x55, req->length);
} else
reinit_write_data(ep, req);
break;
@@ -544,11 +529,11 @@
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
- VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
+ VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
req->actual, req->length);
if (ep == dev->out_ep)
- check_read_data (dev, ep, req);
- free_ep_req (ep, req);
+ check_read_data(dev, ep, req);
+ free_ep_req(ep, req);
return;
case -EOVERFLOW: /* buffer overrun on read means that
@@ -557,18 +542,18 @@
*/
default:
#if 1
- DBG (dev, "%s complete --> %d, %d/%d\n", ep->name,
+ DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
#endif
case -EREMOTEIO: /* short read */
break;
}
- status = usb_ep_queue (ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
- ERROR (dev, "kill %s: resubmit %d bytes --> %d\n",
+ ERROR(dev, "kill %s: resubmit %d bytes --> %d\n",
ep->name, req->length, status);
- usb_ep_set_halt (ep);
+ usb_ep_set_halt(ep);
/* FIXME recover later ... somehow */
}
}
@@ -578,24 +563,24 @@
struct usb_request *req;
int status;
- req = alloc_ep_req (ep, buflen);
+ req = alloc_ep_req(ep, buflen);
if (!req)
return NULL;
- memset (req->buf, 0, req->length);
+ memset(req->buf, 0, req->length);
req->complete = source_sink_complete;
- if (strcmp (ep->name, EP_IN_NAME) == 0)
+ if (strcmp(ep->name, EP_IN_NAME) == 0)
reinit_write_data(ep, req);
else
- memset (req->buf, 0x55, req->length);
+ memset(req->buf, 0x55, req->length);
status = usb_ep_queue(ep, req, GFP_ATOMIC);
if (status) {
struct zero_dev *dev = ep->driver_data;
- ERROR (dev, "start %s --> %d\n", ep->name, status);
- free_ep_req (ep, req);
+ ERROR(dev, "start %s --> %d\n", ep->name, status);
+ free_ep_req(ep, req);
req = NULL;
}
@@ -608,34 +593,34 @@
struct usb_ep *ep;
struct usb_gadget *gadget = dev->gadget;
- gadget_for_each_ep (ep, gadget) {
+ gadget_for_each_ep(ep, gadget) {
const struct usb_endpoint_descriptor *d;
/* one endpoint writes (sources) zeroes in (to the host) */
- if (strcmp (ep->name, EP_IN_NAME) == 0) {
- d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
- result = usb_ep_enable (ep, d);
+ if (strcmp(ep->name, EP_IN_NAME) == 0) {
+ d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
if (source_sink_start_ep(ep) != NULL) {
dev->in_ep = ep;
continue;
}
- usb_ep_disable (ep);
+ usb_ep_disable(ep);
result = -EIO;
}
/* one endpoint reads (sinks) anything out (from the host) */
- } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
- d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
- result = usb_ep_enable (ep, d);
+ } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+ d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
if (source_sink_start_ep(ep) != NULL) {
dev->out_ep = ep;
continue;
}
- usb_ep_disable (ep);
+ usb_ep_disable(ep);
result = -EIO;
}
@@ -644,11 +629,11 @@
continue;
/* stop on error */
- ERROR (dev, "can't start %s, result %d\n", ep->name, result);
+ ERROR(dev, "can't start %s, result %d\n", ep->name, result);
break;
}
if (result == 0)
- DBG (dev, "buflen %d\n", buflen);
+ DBG(dev, "buflen %d\n", buflen);
/* caller is responsible for cleanup on error */
return result;
@@ -656,7 +641,7 @@
/*-------------------------------------------------------------------------*/
-static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
+static void loopback_complete(struct usb_ep *ep, struct usb_request *req)
{
struct zero_dev *dev = ep->driver_data;
int status = req->status;
@@ -668,19 +653,19 @@
/* loop this OUT packet back IN to the host */
req->zero = (req->actual < req->length);
req->length = req->actual;
- status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC);
if (status == 0)
return;
/* "should never get here" */
- ERROR (dev, "can't loop %s to %s: %d\n",
+ ERROR(dev, "can't loop %s to %s: %d\n",
ep->name, dev->in_ep->name,
status);
}
/* queue the buffer for some later OUT packet */
req->length = buflen;
- status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
+ status = usb_ep_queue(dev->out_ep, req, GFP_ATOMIC);
if (status == 0)
return;
@@ -688,7 +673,7 @@
/* FALLTHROUGH */
default:
- ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name,
+ ERROR(dev, "%s loop complete --> %d, %d/%d\n", ep->name,
status, req->actual, req->length);
/* FALLTHROUGH */
@@ -700,7 +685,7 @@
case -ECONNABORTED: /* hardware forced ep reset */
case -ECONNRESET: /* request dequeued */
case -ESHUTDOWN: /* disconnect from host */
- free_ep_req (ep, req);
+ free_ep_req(ep, req);
return;
}
}
@@ -711,13 +696,13 @@
struct usb_ep *ep;
struct usb_gadget *gadget = dev->gadget;
- gadget_for_each_ep (ep, gadget) {
+ gadget_for_each_ep(ep, gadget) {
const struct usb_endpoint_descriptor *d;
/* one endpoint writes data back IN to the host */
- if (strcmp (ep->name, EP_IN_NAME) == 0) {
- d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
- result = usb_ep_enable (ep, d);
+ if (strcmp(ep->name, EP_IN_NAME) == 0) {
+ d = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
dev->in_ep = ep;
@@ -725,9 +710,9 @@
}
/* one endpoint just reads OUT packets */
- } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
- d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
- result = usb_ep_enable (ep, d);
+ } else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
+ d = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
+ result = usb_ep_enable(ep, d);
if (result == 0) {
ep->driver_data = dev;
dev->out_ep = ep;
@@ -739,7 +724,7 @@
continue;
/* stop on error */
- ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
+ ERROR(dev, "can't enable %s, result %d\n", ep->name, result);
break;
}
@@ -753,19 +738,19 @@
ep = dev->out_ep;
for (i = 0; i < qlen && result == 0; i++) {
- req = alloc_ep_req (ep, buflen);
+ req = alloc_ep_req(ep, buflen);
if (req) {
req->complete = loopback_complete;
- result = usb_ep_queue (ep, req, GFP_ATOMIC);
+ result = usb_ep_queue(ep, req, GFP_ATOMIC);
if (result)
- DBG (dev, "%s queue req --> %d\n",
+ DBG(dev, "%s queue req --> %d\n",
ep->name, result);
} else
result = -ENOMEM;
}
}
if (result == 0)
- DBG (dev, "qlen %d, buflen %d\n", qlen, buflen);
+ DBG(dev, "qlen %d, buflen %d\n", qlen, buflen);
/* caller is responsible for cleanup on error */
return result;
@@ -773,26 +758,26 @@
/*-------------------------------------------------------------------------*/
-static void zero_reset_config (struct zero_dev *dev)
+static void zero_reset_config(struct zero_dev *dev)
{
if (dev->config == 0)
return;
- DBG (dev, "reset config\n");
+ DBG(dev, "reset config\n");
/* just disable endpoints, forcing completion of pending i/o.
* all our completion handlers free their requests in this case.
*/
if (dev->in_ep) {
- usb_ep_disable (dev->in_ep);
+ usb_ep_disable(dev->in_ep);
dev->in_ep = NULL;
}
if (dev->out_ep) {
- usb_ep_disable (dev->out_ep);
+ usb_ep_disable(dev->out_ep);
dev->out_ep = NULL;
}
dev->config = 0;
- del_timer (&dev->resume);
+ del_timer(&dev->resume);
}
/* change our operational config. this code must agree with the code
@@ -813,12 +798,12 @@
if (number == dev->config)
return 0;
- if (gadget_is_sa1100 (gadget) && dev->config) {
+ if (gadget_is_sa1100(gadget) && dev->config) {
/* tx fifo is full, but we can't clear it...*/
ERROR(dev, "can't change configurations\n");
return -ESPIPE;
}
- zero_reset_config (dev);
+ zero_reset_config(dev);
switch (number) {
case CONFIG_SOURCE_SINK:
@@ -837,7 +822,7 @@
if (!result && (!dev->in_ep || !dev->out_ep))
result = -ENODEV;
if (result)
- zero_reset_config (dev);
+ zero_reset_config(dev);
else {
char *speed;
@@ -849,7 +834,7 @@
}
dev->config = number;
- INFO (dev, "%s speed config #%d: %s\n", speed, number,
+ INFO(dev, "%s speed config #%d: %s\n", speed, number,
(number == CONFIG_SOURCE_SINK)
? source_sink : loopback);
}
@@ -858,10 +843,10 @@
/*-------------------------------------------------------------------------*/
-static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
+static void zero_setup_complete(struct usb_ep *ep, struct usb_request *req)
{
if (req->status || req->actual != req->length)
- DBG ((struct zero_dev *) ep->driver_data,
+ DBG((struct zero_dev *) ep->driver_data,
"setup complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
}
@@ -874,9 +859,9 @@
* the work is in config-specific setup.
*/
static int
-zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+zero_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
@@ -895,14 +880,14 @@
switch (w_value >> 8) {
case USB_DT_DEVICE:
- value = min (w_length, (u16) sizeof device_desc);
- memcpy (req->buf, &device_desc, value);
+ value = min(w_length, (u16) sizeof device_desc);
+ memcpy(req->buf, &device_desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
if (!gadget_is_dualspeed(gadget))
break;
- value = min (w_length, (u16) sizeof dev_qualifier);
- memcpy (req->buf, &dev_qualifier, value);
+ value = min(w_length, (u16) sizeof dev_qualifier);
+ memcpy(req->buf, &dev_qualifier, value);
break;
case USB_DT_OTHER_SPEED_CONFIG:
@@ -910,11 +895,11 @@
break;
// FALLTHROUGH
case USB_DT_CONFIG:
- value = config_buf (gadget, req->buf,
+ value = config_buf(gadget, req->buf,
w_value >> 8,
w_value & 0xff);
if (value >= 0)
- value = min (w_length, (u16) value);
+ value = min(w_length, (u16) value);
break;
case USB_DT_STRING:
@@ -923,10 +908,10 @@
* add string tables for other languages, using
* any UTF-8 characters
*/
- value = usb_gadget_get_string (&stringtab,
+ value = usb_gadget_get_string(&stringtab,
w_value & 0xff, req->buf);
if (value >= 0)
- value = min (w_length, (u16) value);
+ value = min(w_length, (u16) value);
break;
}
break;
@@ -936,20 +921,20 @@
if (ctrl->bRequestType != 0)
goto unknown;
if (gadget->a_hnp_support)
- DBG (dev, "HNP available\n");
+ DBG(dev, "HNP available\n");
else if (gadget->a_alt_hnp_support)
- DBG (dev, "HNP needs a different root port\n");
+ DBG(dev, "HNP needs a different root port\n");
else
- VDBG (dev, "HNP inactive\n");
- spin_lock (&dev->lock);
+ VDBG(dev, "HNP inactive\n");
+ spin_lock(&dev->lock);
value = zero_set_config(dev, w_value);
- spin_unlock (&dev->lock);
+ spin_unlock(&dev->lock);
break;
case USB_REQ_GET_CONFIGURATION:
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
*(u8 *)req->buf = dev->config;
- value = min (w_length, (u16) 1);
+ value = min(w_length, (u16) 1);
break;
/* until we add altsetting support, or other interfaces,
@@ -959,7 +944,7 @@
case USB_REQ_SET_INTERFACE:
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
goto unknown;
- spin_lock (&dev->lock);
+ spin_lock(&dev->lock);
if (dev->config && w_index == 0 && w_value == 0) {
u8 config = dev->config;
@@ -970,11 +955,11 @@
* if we had more than one interface we couldn't
* use this "reset the config" shortcut.
*/
- zero_reset_config (dev);
+ zero_reset_config(dev);
zero_set_config(dev, config);
value = 0;
}
- spin_unlock (&dev->lock);
+ spin_unlock(&dev->lock);
break;
case USB_REQ_GET_INTERFACE:
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
@@ -986,7 +971,7 @@
break;
}
*(u8 *)req->buf = 0;
- value = min (w_length, (u16) 1);
+ value = min(w_length, (u16) 1);
break;
/*
@@ -1018,7 +1003,7 @@
default:
unknown:
- VDBG (dev,
+ VDBG(dev,
"unknown control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
@@ -1028,11 +1013,11 @@
if (value >= 0) {
req->length = value;
req->zero = value < w_length;
- value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+ value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
if (value < 0) {
- DBG (dev, "ep_queue --> %d\n", value);
+ DBG(dev, "ep_queue --> %d\n", value);
req->status = 0;
- zero_setup_complete (gadget->ep0, req);
+ zero_setup_complete(gadget->ep0, req);
}
}
@@ -1040,28 +1025,26 @@
return value;
}
-static void
-zero_disconnect (struct usb_gadget *gadget)
+static void zero_disconnect(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
unsigned long flags;
- spin_lock_irqsave (&dev->lock, flags);
- zero_reset_config (dev);
+ spin_lock_irqsave(&dev->lock, flags);
+ zero_reset_config(dev);
/* a more significant application might have some non-usb
* activities to quiesce here, saving resources like power
* or pushing the notification up a network stack.
*/
- spin_unlock_irqrestore (&dev->lock, flags);
+ spin_unlock_irqrestore(&dev->lock, flags);
/* next we may get setup() calls to enumerate new connections;
* or an unbind() during shutdown (including removing module).
*/
}
-static void
-zero_autoresume (unsigned long _dev)
+static void zero_autoresume(unsigned long _dev)
{
struct zero_dev *dev = (struct zero_dev *) _dev;
int status;
@@ -1070,32 +1053,30 @@
* more significant than just a timer firing...
*/
if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
- status = usb_gadget_wakeup (dev->gadget);
- DBG (dev, "wakeup --> %d\n", status);
+ status = usb_gadget_wakeup(dev->gadget);
+ DBG(dev, "wakeup --> %d\n", status);
}
}
/*-------------------------------------------------------------------------*/
-static void /* __init_or_exit */
-zero_unbind (struct usb_gadget *gadget)
+static void zero_unbind(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
- DBG (dev, "unbind\n");
+ DBG(dev, "unbind\n");
/* we've already been disconnected ... no i/o is active */
if (dev->req) {
dev->req->length = USB_BUFSIZ;
- free_ep_req (gadget->ep0, dev->req);
+ free_ep_req(gadget->ep0, dev->req);
}
- del_timer_sync (&dev->resume);
- kfree (dev);
- set_gadget_data (gadget, NULL);
+ del_timer_sync(&dev->resume);
+ kfree(dev);
+ set_gadget_data(gadget, NULL);
}
-static int __init
-zero_bind (struct usb_gadget *gadget)
+static int __init zero_bind(struct usb_gadget *gadget)
{
struct zero_dev *dev;
struct usb_ep *ep;
@@ -1111,8 +1092,8 @@
* autoconfigure on any sane usb controller driver,
* but there may also be important quirks to address.
*/
- usb_ep_autoconfig_reset (gadget);
- ep = usb_ep_autoconfig (gadget, &fs_source_desc);
+ usb_ep_autoconfig_reset(gadget);
+ ep = usb_ep_autoconfig(gadget, &fs_source_desc);
if (!ep) {
autoconf_fail:
pr_err("%s: can't autoconfigure on %s\n",
@@ -1122,15 +1103,15 @@
EP_IN_NAME = ep->name;
ep->driver_data = ep; /* claim */
- ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
+ ep = usb_ep_autoconfig(gadget, &fs_sink_desc);
if (!ep)
goto autoconf_fail;
EP_OUT_NAME = ep->name;
ep->driver_data = ep; /* claim */
- gcnum = usb_gadget_controller_number (gadget);
+ gcnum = usb_gadget_controller_number(gadget);
if (gcnum >= 0)
- device_desc.bcdDevice = cpu_to_le16 (0x0200 + gcnum);
+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
else {
/* gadget zero is so simple (for now, no altsettings) that
* it SHOULD NOT have problems with bulk-capable hardware.
@@ -1141,7 +1122,7 @@
*/
pr_warning("%s: controller '%s' not recognized\n",
shortname, gadget->name);
- device_desc.bcdDevice = __constant_cpu_to_le16 (0x9999);
+ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
}
@@ -1149,12 +1130,16 @@
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- spin_lock_init (&dev->lock);
+ spin_lock_init(&dev->lock);
dev->gadget = gadget;
- set_gadget_data (gadget, dev);
+ set_gadget_data(gadget, dev);
+
+ init_timer(&dev->resume);
+ dev->resume.function = zero_autoresume;
+ dev->resume.data = (unsigned long) dev;
/* preallocate control response and buffer */
- dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+ dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
if (!dev->req)
goto enomem;
dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
@@ -1182,11 +1167,8 @@
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
- usb_gadget_set_selfpowered (gadget);
+ usb_gadget_set_selfpowered(gadget);
- init_timer (&dev->resume);
- dev->resume.function = zero_autoresume;
- dev->resume.data = (unsigned long) dev;
if (autoresume) {
source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1194,45 +1176,43 @@
gadget->ep0->driver_data = dev;
- INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
- INFO (dev, "using %s, OUT %s IN %s\n", gadget->name,
+ INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
+ INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
EP_OUT_NAME, EP_IN_NAME);
- snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
+ snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
gadget->name);
return 0;
enomem:
- zero_unbind (gadget);
+ zero_unbind(gadget);
return -ENOMEM;
}
/*-------------------------------------------------------------------------*/
-static void
-zero_suspend (struct usb_gadget *gadget)
+static void zero_suspend(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
if (gadget->speed == USB_SPEED_UNKNOWN)
return;
if (autoresume) {
- mod_timer (&dev->resume, jiffies + (HZ * autoresume));
- DBG (dev, "suspend, wakeup in %d seconds\n", autoresume);
+ mod_timer(&dev->resume, jiffies + (HZ * autoresume));
+ DBG(dev, "suspend, wakeup in %d seconds\n", autoresume);
} else
- DBG (dev, "suspend\n");
+ DBG(dev, "suspend\n");
}
-static void
-zero_resume (struct usb_gadget *gadget)
+static void zero_resume(struct usb_gadget *gadget)
{
- struct zero_dev *dev = get_gadget_data (gadget);
+ struct zero_dev *dev = get_gadget_data(gadget);
- DBG (dev, "resume\n");
- del_timer (&dev->resume);
+ DBG(dev, "resume\n");
+ del_timer(&dev->resume);
}
@@ -1264,15 +1244,15 @@
MODULE_LICENSE("GPL");
-static int __init init (void)
+static int __init init(void)
{
- return usb_gadget_register_driver (&zero_driver);
+ return usb_gadget_register_driver(&zero_driver);
}
-module_init (init);
+module_init(init);
-static void __exit cleanup (void)
+static void __exit cleanup(void)
{
- usb_gadget_unregister_driver (&zero_driver);
+ usb_gadget_unregister_driver(&zero_driver);
}
-module_exit (cleanup);
+module_exit(cleanup);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 0b87480..33b467a 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -4,6 +4,19 @@
comment "USB Host Controller Drivers"
depends on USB
+config USB_C67X00_HCD
+ tristate "Cypress C67x00 HCD support"
+ depends on USB
+ help
+ The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role
+ host/peripheral/OTG USB controllers.
+
+ Enable this option to support this chip in host controller mode.
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called c67x00.
+
config USB_EHCI_HCD
tristate "EHCI HCD (USB 2.0) support"
depends on USB && USB_ARCH_HAS_EHCI
@@ -95,6 +108,32 @@
To compile this driver as a module, choose M here: the
module will be called isp116x-hcd.
+config USB_ISP1760_HCD
+ tristate "ISP 1760 HCD support"
+ depends on USB && EXPERIMENTAL
+ ---help---
+ The ISP1760 chip is a USB 2.0 host controller.
+
+ This driver does not support isochronous transfers or OTG.
+
+ To compile this driver as a module, choose M here: the
+ module will be called isp1760-hcd.
+
+config USB_ISP1760_PCI
+ bool "Support for the PCI bus"
+ depends on USB_ISP1760_HCD && PCI
+ ---help---
+ Enables support for the device present on the PCI bus.
+ This should only be required if you happen to have the eval kit from
+ NXP and you are going to test it.
+
+config USB_ISP1760_OF
+ bool "Support for the OF platform bus"
+ depends on USB_ISP1760_HCD && OF
+ ---help---
+ Enables support for the device present on the PowerPC
+ OpenFirmware platform bus.
+
config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index bb8e9d4..f1edda2 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -6,6 +6,8 @@
EXTRA_CFLAGS += -DDEBUG
endif
+isp1760-objs := isp1760-hcd.o isp1760-if.o
+
obj-$(CONFIG_PCI) += pci-quirks.o
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
@@ -16,4 +18,4 @@
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-
+obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index f13d102..382587c 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -770,7 +770,7 @@
if (status & ~0xffff) /* only if wPortChange is interesting */
#endif
dbg_port (ehci, "GetStatus", wIndex + 1, temp);
- put_unaligned(cpu_to_le32 (status), (__le32 *) buf);
+ put_unaligned_le32(status, buf);
break;
case SetHubFeature:
switch (wValue) {
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
new file mode 100644
index 0000000..4ba96c1
--- /dev/null
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -0,0 +1,2231 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * However, the code might contain some bugs. What doesn't work for sure is:
+ * - ISO
+ * - OTG
+ e The interrupt line is configured as active low, level.
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <asm/unaligned.h>
+
+#include "../core/hcd.h"
+#include "isp1760-hcd.h"
+
+static struct kmem_cache *qtd_cachep;
+static struct kmem_cache *qh_cachep;
+
+struct isp1760_hcd {
+ u32 hcs_params;
+ spinlock_t lock;
+ struct inter_packet_info atl_ints[32];
+ struct inter_packet_info int_ints[32];
+ struct memory_chunk memory_pool[BLOCKS];
+
+ /* periodic schedule support */
+#define DEFAULT_I_TDPS 1024
+ unsigned periodic_size;
+ unsigned i_thresh;
+ unsigned long reset_done;
+ unsigned long next_statechange;
+};
+
+static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
+{
+ return (struct isp1760_hcd *) (hcd->hcd_priv);
+}
+static inline struct usb_hcd *priv_to_hcd(struct isp1760_hcd *priv)
+{
+ return container_of((void *) priv, struct usb_hcd, hcd_priv);
+}
+
+/* Section 2.2 Host Controller Capability Registers */
+#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
+#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
+#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
+#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
+#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
+
+/* Section 2.3 Host Controller Operational Registers */
+#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
+#define CMD_RESET (1<<1) /* reset HC not bus */
+#define CMD_RUN (1<<0) /* start/stop HC */
+#define STS_PCD (1<<2) /* port change detect */
+#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
+
+#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
+#define PORT_POWER (1<<12) /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
+#define PORT_RESET (1<<8) /* reset port */
+#define PORT_SUSPEND (1<<7) /* suspend port */
+#define PORT_RESUME (1<<6) /* resume it */
+#define PORT_PE (1<<2) /* port enable */
+#define PORT_CSC (1<<1) /* connect status change */
+#define PORT_CONNECT (1<<0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC)
+
+struct isp1760_qtd {
+ struct isp1760_qtd *hw_next;
+ u8 packet_type;
+ u8 toggle;
+
+ void *data_buffer;
+ /* the rest is HCD-private */
+ struct list_head qtd_list;
+ struct urb *urb;
+ size_t length;
+
+ /* isp special*/
+ u32 status;
+#define URB_COMPLETE_NOTIFY (1 << 0)
+#define URB_ENQUEUED (1 << 1)
+#define URB_TYPE_ATL (1 << 2)
+#define URB_TYPE_INT (1 << 3)
+};
+
+struct isp1760_qh {
+ /* first part defined by EHCI spec */
+ struct list_head qtd_list;
+ struct isp1760_hcd *priv;
+
+ /* periodic schedule info */
+ unsigned short period; /* polling interval */
+ struct usb_device *dev;
+
+ u32 toggle;
+ u32 ping;
+};
+
+#define ehci_port_speed(priv, portsc) (1 << USB_PORT_FEAT_HIGHSPEED)
+
+static unsigned int isp1760_readl(__u32 __iomem *regs)
+{
+ return readl(regs);
+}
+
+static void isp1760_writel(const unsigned int val, __u32 __iomem *regs)
+{
+ writel(val, regs);
+}
+
+/*
+ * The next two copy via MMIO data to/from the device. memcpy_{to|from}io()
+ * doesn't quite work because some people have to enforce 32-bit access
+ */
+static void priv_read_copy(struct isp1760_hcd *priv, u32 *src,
+ __u32 __iomem *dst, u32 offset, u32 len)
+{
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+ u32 val;
+ u8 *buff8;
+
+ if (!src) {
+ printk(KERN_ERR "ERROR: buffer: %p len: %d\n", src, len);
+ return;
+ }
+ isp1760_writel(offset, hcd->regs + HC_MEMORY_REG);
+ /* XXX
+ * 90nsec delay, the spec says something how this could be avoided.
+ */
+ mdelay(1);
+
+ while (len >= 4) {
+ *src = __raw_readl(dst);
+ len -= 4;
+ src++;
+ dst++;
+ }
+
+ if (!len)
+ return;
+
+ /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully
+ * allocated.
+ */
+ val = isp1760_readl(dst);
+
+ buff8 = (u8 *)src;
+ while (len) {
+
+ *buff8 = val;
+ val >>= 8;
+ len--;
+ buff8++;
+ }
+}
+
+static void priv_write_copy(const struct isp1760_hcd *priv, const u32 *src,
+ __u32 __iomem *dst, u32 len)
+{
+ while (len >= 4) {
+ __raw_writel(*src, dst);
+ len -= 4;
+ src++;
+ dst++;
+ }
+
+ if (!len)
+ return;
+ /* in case we have 3, 2 or 1 by left. The buffer is allocated and the
+ * extra bytes should not be read by the HW
+ */
+
+ __raw_writel(*src, dst);
+}
+
+/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
+static void init_memory(struct isp1760_hcd *priv)
+{
+ int i;
+ u32 payload;
+
+ payload = 0x1000;
+ for (i = 0; i < BLOCK_1_NUM; i++) {
+ priv->memory_pool[i].start = payload;
+ priv->memory_pool[i].size = BLOCK_1_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload += priv->memory_pool[i].size;
+ }
+
+
+ for (i = BLOCK_1_NUM; i < BLOCK_1_NUM + BLOCK_2_NUM; i++) {
+ priv->memory_pool[i].start = payload;
+ priv->memory_pool[i].size = BLOCK_2_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload += priv->memory_pool[i].size;
+ }
+
+
+ for (i = BLOCK_1_NUM + BLOCK_2_NUM; i < BLOCKS; i++) {
+ priv->memory_pool[i].start = payload;
+ priv->memory_pool[i].size = BLOCK_3_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload += priv->memory_pool[i].size;
+ }
+
+ BUG_ON(payload - priv->memory_pool[i - 1].size > PAYLOAD_SIZE);
+}
+
+static u32 alloc_mem(struct isp1760_hcd *priv, u32 size)
+{
+ int i;
+
+ if (!size)
+ return ISP1760_NULL_POINTER;
+
+ for (i = 0; i < BLOCKS; i++) {
+ if (priv->memory_pool[i].size >= size &&
+ priv->memory_pool[i].free) {
+
+ priv->memory_pool[i].free = 0;
+ return priv->memory_pool[i].start;
+ }
+ }
+
+ printk(KERN_ERR "ISP1760 MEM: can not allocate %d bytes of memory\n",
+ size);
+ printk(KERN_ERR "Current memory map:\n");
+ for (i = 0; i < BLOCKS; i++) {
+ printk(KERN_ERR "Pool %2d size %4d status: %d\n",
+ i, priv->memory_pool[i].size,
+ priv->memory_pool[i].free);
+ }
+ /* XXX maybe -ENOMEM could be possible */
+ BUG();
+ return 0;
+}
+
+static void free_mem(struct isp1760_hcd *priv, u32 mem)
+{
+ int i;
+
+ if (mem == ISP1760_NULL_POINTER)
+ return;
+
+ for (i = 0; i < BLOCKS; i++) {
+ if (priv->memory_pool[i].start == mem) {
+
+ BUG_ON(priv->memory_pool[i].free);
+
+ priv->memory_pool[i].free = 1;
+ return ;
+ }
+ }
+
+ printk(KERN_ERR "Trying to free not-here-allocated memory :%08x\n",
+ mem);
+ BUG();
+}
+
+static void isp1760_init_regs(struct usb_hcd *hcd)
+{
+ isp1760_writel(0, hcd->regs + HC_BUFFER_STATUS_REG);
+ isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+ isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+ isp1760_writel(NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ISO_PTD_SKIPMAP_REG);
+
+ isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ATL_PTD_DONEMAP_REG);
+ isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_INT_PTD_DONEMAP_REG);
+ isp1760_writel(~NO_TRANSFER_ACTIVE, hcd->regs +
+ HC_ISO_PTD_DONEMAP_REG);
+}
+
+static int handshake(struct isp1760_hcd *priv, void __iomem *ptr,
+ u32 mask, u32 done, int usec)
+{
+ u32 result;
+
+ do {
+ result = isp1760_readl(ptr);
+ if (result == ~0)
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+ return -ETIMEDOUT;
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset(struct isp1760_hcd *priv)
+{
+ int retval;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+ u32 command = isp1760_readl(hcd->regs + HC_USBCMD);
+
+ command |= CMD_RESET;
+ isp1760_writel(command, hcd->regs + HC_USBCMD);
+ hcd->state = HC_STATE_HALT;
+ priv->next_statechange = jiffies;
+ retval = handshake(priv, hcd->regs + HC_USBCMD,
+ CMD_RESET, 0, 250 * 1000);
+ return retval;
+}
+
+static void qh_destroy(struct isp1760_qh *qh)
+{
+ BUG_ON(!list_empty(&qh->qtd_list));
+ kmem_cache_free(qh_cachep, qh);
+}
+
+static struct isp1760_qh *isp1760_qh_alloc(struct isp1760_hcd *priv,
+ gfp_t flags)
+{
+ struct isp1760_qh *qh;
+
+ qh = kmem_cache_zalloc(qh_cachep, flags);
+ if (!qh)
+ return qh;
+
+ INIT_LIST_HEAD(&qh->qtd_list);
+ qh->priv = priv;
+ return qh;
+}
+
+/* magic numbers that can affect system performance */
+#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
+#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
+#define EHCI_TUNE_RL_TT 0
+#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
+#define EHCI_TUNE_MULT_TT 1
+#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
+
+/* one-time init, only for memory state */
+static int priv_init(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 hcc_params;
+
+ spin_lock_init(&priv->lock);
+
+ /*
+ * hw default: 1K periodic list heads, one per frame.
+ * periodic_size can shrink by USBCMD update if hcc_params allows.
+ */
+ priv->periodic_size = DEFAULT_I_TDPS;
+
+ /* controllers may cache some of the periodic schedule ... */
+ hcc_params = isp1760_readl(hcd->regs + HC_HCCPARAMS);
+ /* full frame cache */
+ if (HCC_ISOC_CACHE(hcc_params))
+ priv->i_thresh = 8;
+ else /* N microframes cached */
+ priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+
+ return 0;
+}
+
+static int isp1760_hc_setup(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int result;
+ u32 scratch;
+
+ isp1760_writel(0xdeadbabe, hcd->regs + HC_SCRATCH_REG);
+ scratch = isp1760_readl(hcd->regs + HC_SCRATCH_REG);
+ if (scratch != 0xdeadbabe) {
+ printk(KERN_ERR "ISP1760: Scratch test failed.\n");
+ return -ENODEV;
+ }
+
+ /* pre reset */
+ isp1760_init_regs(hcd);
+
+ /* reset */
+ isp1760_writel(SW_RESET_RESET_ALL, hcd->regs + HC_RESET_REG);
+ mdelay(100);
+
+ isp1760_writel(SW_RESET_RESET_HC, hcd->regs + HC_RESET_REG);
+ mdelay(100);
+
+ result = ehci_reset(priv);
+ if (result)
+ return result;
+
+ /* Step 11 passed */
+
+ isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_REG);
+ isp1760_writel(INTERRUPT_ENABLE_MASK, hcd->regs + HC_INTERRUPT_ENABLE);
+
+ /* ATL reset */
+ scratch = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
+ isp1760_writel(scratch | ALL_ATX_RESET, hcd->regs + HC_HW_MODE_CTRL);
+ mdelay(10);
+ isp1760_writel(scratch, hcd->regs + HC_HW_MODE_CTRL);
+
+ isp1760_writel(PORT1_POWER | PORT1_INIT2, hcd->regs + HC_PORT1_CTRL);
+ mdelay(10);
+
+ priv->hcs_params = isp1760_readl(hcd->regs + HC_HCSPARAMS);
+
+ return priv_init(hcd);
+}
+
+static void isp1760_init_maps(struct usb_hcd *hcd)
+{
+ /*set last maps, for iso its only 1, else 32 tds bitmap*/
+ isp1760_writel(0x80000000, hcd->regs + HC_ATL_PTD_LASTPTD_REG);
+ isp1760_writel(0x80000000, hcd->regs + HC_INT_PTD_LASTPTD_REG);
+ isp1760_writel(0x00000001, hcd->regs + HC_ISO_PTD_LASTPTD_REG);
+}
+
+static void isp1760_enable_interrupts(struct usb_hcd *hcd)
+{
+ isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_AND_REG);
+ isp1760_writel(0, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+ isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_AND_REG);
+ isp1760_writel(0, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+ isp1760_writel(0, hcd->regs + HC_ISO_IRQ_MASK_AND_REG);
+ isp1760_writel(0xffffffff, hcd->regs + HC_ISO_IRQ_MASK_OR_REG);
+ /* step 23 passed */
+}
+
+static int isp1760_run(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int retval;
+ u32 temp;
+ u32 command;
+ u32 chipid;
+
+ hcd->uses_new_polling = 1;
+ hcd->poll_rh = 0;
+
+ hcd->state = HC_STATE_RUNNING;
+ isp1760_enable_interrupts(hcd);
+ temp = isp1760_readl(hcd->regs + HC_HW_MODE_CTRL);
+ temp |= FINAL_HW_CONFIG;
+ isp1760_writel(temp, hcd->regs + HC_HW_MODE_CTRL);
+
+ command = isp1760_readl(hcd->regs + HC_USBCMD);
+ command &= ~(CMD_LRESET|CMD_RESET);
+ command |= CMD_RUN;
+ isp1760_writel(command, hcd->regs + HC_USBCMD);
+
+ retval = handshake(priv, hcd->regs + HC_USBCMD, CMD_RUN, CMD_RUN,
+ 250 * 1000);
+ if (retval)
+ return retval;
+
+ /*
+ * XXX
+ * Spec says to write FLAG_CF as last config action, priv code grabs
+ * the semaphore while doing so.
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+ isp1760_writel(FLAG_CF, hcd->regs + HC_CONFIGFLAG);
+
+ retval = handshake(priv, hcd->regs + HC_CONFIGFLAG, FLAG_CF, FLAG_CF,
+ 250 * 1000);
+ up_write(&ehci_cf_port_reset_rwsem);
+ if (retval)
+ return retval;
+
+ chipid = isp1760_readl(hcd->regs + HC_CHIP_ID_REG);
+ isp1760_info(priv, "USB ISP %04x HW rev. %d started\n", chipid & 0xffff,
+ chipid >> 16);
+
+ /* PTD Register Init Part 2, Step 28 */
+ /* enable INTs */
+ isp1760_init_maps(hcd);
+
+ /* GRR this is run-once init(), being done every time the HC starts.
+ * So long as they're part of class devices, we can't do it init()
+ * since the class device isn't created that early.
+ */
+ return 0;
+}
+
+static u32 base_to_chip(u32 base)
+{
+ return ((base - 0x400) >> 3);
+}
+
+static void transform_into_atl(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct urb *urb,
+ u32 payload, struct ptd *ptd)
+{
+ u32 dw0;
+ u32 dw1;
+ u32 dw2;
+ u32 dw3;
+ u32 maxpacket;
+ u32 multi;
+ u32 pid_code;
+ u32 rl = RL_COUNTER;
+ u32 nak = NAK_COUNTER;
+
+ /* according to 3.6.2, max packet len can not be > 0x400 */
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ multi = 1 + ((maxpacket >> 11) & 0x3);
+ maxpacket &= 0x7ff;
+
+ /* DW0 */
+ dw0 = PTD_VALID;
+ dw0 |= PTD_LENGTH(qtd->length);
+ dw0 |= PTD_MAXPACKET(maxpacket);
+ dw0 |= PTD_ENDPOINT(usb_pipeendpoint(urb->pipe));
+ dw1 = usb_pipeendpoint(urb->pipe) >> 1;
+
+ /* DW1 */
+ dw1 |= PTD_DEVICE_ADDR(usb_pipedevice(urb->pipe));
+
+ pid_code = qtd->packet_type;
+ dw1 |= PTD_PID_TOKEN(pid_code);
+
+ if (usb_pipebulk(urb->pipe))
+ dw1 |= PTD_TRANS_BULK;
+ else if (usb_pipeint(urb->pipe))
+ dw1 |= PTD_TRANS_INT;
+
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /* split transaction */
+
+ dw1 |= PTD_TRANS_SPLIT;
+ if (urb->dev->speed == USB_SPEED_LOW)
+ dw1 |= PTD_SE_USB_LOSPEED;
+
+ dw1 |= PTD_PORT_NUM(urb->dev->ttport);
+ dw1 |= PTD_HUB_NUM(urb->dev->tt->hub->devnum);
+
+ /* SE bit for Split INT transfers */
+ if (usb_pipeint(urb->pipe) &&
+ (urb->dev->speed == USB_SPEED_LOW))
+ dw1 |= 2 << 16;
+
+ dw3 = 0;
+ rl = 0;
+ nak = 0;
+ } else {
+ dw0 |= PTD_MULTI(multi);
+ if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe))
+ dw3 = qh->ping;
+ else
+ dw3 = 0;
+ }
+ /* DW2 */
+ dw2 = 0;
+ dw2 |= PTD_DATA_START_ADDR(base_to_chip(payload));
+ dw2 |= PTD_RL_CNT(rl);
+ dw3 |= PTD_NAC_CNT(nak);
+
+ /* DW3 */
+ if (usb_pipecontrol(urb->pipe))
+ dw3 |= PTD_DATA_TOGGLE(qtd->toggle);
+ else
+ dw3 |= qh->toggle;
+
+
+ dw3 |= PTD_ACTIVE;
+ /* Cerr */
+ dw3 |= PTD_CERR(ERR_COUNTER);
+
+ memset(ptd, 0, sizeof(*ptd));
+
+ ptd->dw0 = cpu_to_le32(dw0);
+ ptd->dw1 = cpu_to_le32(dw1);
+ ptd->dw2 = cpu_to_le32(dw2);
+ ptd->dw3 = cpu_to_le32(dw3);
+}
+
+static void transform_add_int(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct urb *urb,
+ u32 payload, struct ptd *ptd)
+{
+ u32 maxpacket;
+ u32 multi;
+ u32 numberofusofs;
+ u32 i;
+ u32 usofmask, usof;
+ u32 period;
+
+ maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+ multi = 1 + ((maxpacket >> 11) & 0x3);
+ maxpacket &= 0x7ff;
+ /* length of the data per uframe */
+ maxpacket = multi * maxpacket;
+
+ numberofusofs = urb->transfer_buffer_length / maxpacket;
+ if (urb->transfer_buffer_length % maxpacket)
+ numberofusofs += 1;
+
+ usofmask = 1;
+ usof = 0;
+ for (i = 0; i < numberofusofs; i++) {
+ usof |= usofmask;
+ usofmask <<= 1;
+ }
+
+ if (urb->dev->speed != USB_SPEED_HIGH) {
+ /* split */
+ ptd->dw5 = __constant_cpu_to_le32(0x1c);
+
+ if (qh->period >= 32)
+ period = qh->period / 2;
+ else
+ period = qh->period;
+
+ } else {
+
+ if (qh->period >= 8)
+ period = qh->period/8;
+ else
+ period = qh->period;
+
+ if (period >= 32)
+ period = 16;
+
+ if (qh->period >= 8) {
+ /* millisecond period */
+ period = (period << 3);
+ } else {
+ /* usof based tranmsfers */
+ /* minimum 4 usofs */
+ usof = 0x11;
+ }
+ }
+
+ ptd->dw2 |= cpu_to_le32(period);
+ ptd->dw4 = cpu_to_le32(usof);
+}
+
+static void transform_into_int(struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct urb *urb,
+ u32 payload, struct ptd *ptd)
+{
+ transform_into_atl(priv, qh, qtd, urb, payload, ptd);
+ transform_add_int(priv, qh, qtd, urb, payload, ptd);
+}
+
+static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len,
+ u32 token)
+{
+ int count;
+
+ qtd->data_buffer = databuffer;
+ qtd->packet_type = GET_QTD_TOKEN_TYPE(token);
+ qtd->toggle = GET_DATA_TOGGLE(token);
+
+ if (len > HC_ATL_PL_SIZE)
+ count = HC_ATL_PL_SIZE;
+ else
+ count = len;
+
+ qtd->length = count;
+ return count;
+}
+
+static int check_error(struct ptd *ptd)
+{
+ int error = 0;
+ u32 dw3;
+
+ dw3 = le32_to_cpu(ptd->dw3);
+ if (dw3 & DW3_HALT_BIT)
+ error = -EPIPE;
+
+ if (dw3 & DW3_ERROR_BIT) {
+ printk(KERN_ERR "error bit is set in DW3\n");
+ error = -EPIPE;
+ }
+
+ if (dw3 & DW3_QTD_ACTIVE) {
+ printk(KERN_ERR "transfer active bit is set DW3\n");
+ printk(KERN_ERR "nak counter: %d, rl: %d\n", (dw3 >> 19) & 0xf,
+ (le32_to_cpu(ptd->dw2) >> 25) & 0xf);
+ }
+
+ return error;
+}
+
+static void check_int_err_status(u32 dw4)
+{
+ u32 i;
+
+ dw4 >>= 8;
+
+ for (i = 0; i < 8; i++) {
+ switch (dw4 & 0x7) {
+ case INT_UNDERRUN:
+ printk(KERN_ERR "ERROR: under run , %d\n", i);
+ break;
+
+ case INT_EXACT:
+ printk(KERN_ERR "ERROR: transaction error, %d\n", i);
+ break;
+
+ case INT_BABBLE:
+ printk(KERN_ERR "ERROR: babble error, %d\n", i);
+ break;
+ }
+ dw4 >>= 3;
+ }
+}
+
+static void enqueue_one_qtd(struct isp1760_qtd *qtd, struct isp1760_hcd *priv,
+ u32 payload)
+{
+ u32 token;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+
+ token = qtd->packet_type;
+
+ if (qtd->length && (qtd->length <= HC_ATL_PL_SIZE)) {
+ switch (token) {
+ case IN_PID:
+ break;
+ case OUT_PID:
+ case SETUP_PID:
+ priv_write_copy(priv, qtd->data_buffer,
+ hcd->regs + payload,
+ qtd->length);
+ }
+ }
+}
+
+static void enqueue_one_atl_qtd(u32 atl_regs, u32 payload,
+ struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct urb *urb, u32 slot, struct isp1760_qtd *qtd)
+{
+ struct ptd ptd;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+
+ transform_into_atl(priv, qh, qtd, urb, payload, &ptd);
+ priv_write_copy(priv, (u32 *)&ptd, hcd->regs + atl_regs, sizeof(ptd));
+ enqueue_one_qtd(qtd, priv, payload);
+
+ priv->atl_ints[slot].urb = urb;
+ priv->atl_ints[slot].qh = qh;
+ priv->atl_ints[slot].qtd = qtd;
+ priv->atl_ints[slot].data_buffer = qtd->data_buffer;
+ priv->atl_ints[slot].payload = payload;
+ qtd->status |= URB_ENQUEUED | URB_TYPE_ATL;
+ qtd->status |= slot << 16;
+}
+
+static void enqueue_one_int_qtd(u32 int_regs, u32 payload,
+ struct isp1760_hcd *priv, struct isp1760_qh *qh,
+ struct urb *urb, u32 slot, struct isp1760_qtd *qtd)
+{
+ struct ptd ptd;
+ struct usb_hcd *hcd = priv_to_hcd(priv);
+
+ transform_into_int(priv, qh, qtd, urb, payload, &ptd);
+ priv_write_copy(priv, (u32 *)&ptd, hcd->regs + int_regs, sizeof(ptd));
+ enqueue_one_qtd(qtd, priv, payload);
+
+ priv->int_ints[slot].urb = urb;
+ priv->int_ints[slot].qh = qh;
+ priv->int_ints[slot].qtd = qtd;
+ priv->int_ints[slot].data_buffer = qtd->data_buffer;
+ priv->int_ints[slot].payload = payload;
+ qtd->status |= URB_ENQUEUED | URB_TYPE_INT;
+ qtd->status |= slot << 16;
+}
+
+void enqueue_an_ATL_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 skip_map, or_map;
+ u32 queue_entry;
+ u32 slot;
+ u32 atl_regs, payload;
+ u32 buffstatus;
+
+ skip_map = isp1760_readl(hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+ BUG_ON(!skip_map);
+ slot = __ffs(skip_map);
+ queue_entry = 1 << slot;
+
+ atl_regs = ATL_REGS_OFFSET + slot * sizeof(struct ptd);
+
+ payload = alloc_mem(priv, qtd->length);
+
+ enqueue_one_atl_qtd(atl_regs, payload, priv, qh, qtd->urb, slot, qtd);
+
+ or_map = isp1760_readl(hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+ or_map |= queue_entry;
+ isp1760_writel(or_map, hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+ skip_map &= ~queue_entry;
+ isp1760_writel(skip_map, hcd->regs + HC_ATL_PTD_SKIPMAP_REG);
+
+ buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG);
+ buffstatus |= ATL_BUFFER;
+ isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+void enqueue_an_INT_packet(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 skip_map, or_map;
+ u32 queue_entry;
+ u32 slot;
+ u32 int_regs, payload;
+ u32 buffstatus;
+
+ skip_map = isp1760_readl(hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+ BUG_ON(!skip_map);
+ slot = __ffs(skip_map);
+ queue_entry = 1 << slot;
+
+ int_regs = INT_REGS_OFFSET + slot * sizeof(struct ptd);
+
+ payload = alloc_mem(priv, qtd->length);
+
+ enqueue_one_int_qtd(int_regs, payload, priv, qh, qtd->urb, slot, qtd);
+
+ or_map = isp1760_readl(hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+ or_map |= queue_entry;
+ isp1760_writel(or_map, hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+ skip_map &= ~queue_entry;
+ isp1760_writel(skip_map, hcd->regs + HC_INT_PTD_SKIPMAP_REG);
+
+ buffstatus = isp1760_readl(hcd->regs + HC_BUFFER_STATUS_REG);
+ buffstatus |= INT_BUFFER;
+ isp1760_writel(buffstatus, hcd->regs + HC_BUFFER_STATUS_REG);
+}
+
+static void isp1760_urb_done(struct isp1760_hcd *priv, struct urb *urb, int status)
+__releases(priv->lock)
+__acquires(priv->lock)
+{
+ if (!urb->unlinked) {
+ if (status == -EINPROGRESS)
+ status = 0;
+ }
+
+ /* complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+ spin_unlock(&priv->lock);
+ usb_hcd_giveback_urb(priv_to_hcd(priv), urb, status);
+ spin_lock(&priv->lock);
+}
+
+static void isp1760_qtd_free(struct isp1760_qtd *qtd)
+{
+ kmem_cache_free(qtd_cachep, qtd);
+}
+
+static struct isp1760_qtd *clean_this_qtd(struct isp1760_qtd *qtd)
+{
+ struct isp1760_qtd *tmp_qtd;
+
+ tmp_qtd = qtd->hw_next;
+ list_del(&qtd->qtd_list);
+ isp1760_qtd_free(qtd);
+ return tmp_qtd;
+}
+
+/*
+ * Remove this QTD from the QH list and free its memory. If this QTD
+ * isn't the last one than remove also his successor(s).
+ * Returns the QTD which is part of an new URB and should be enqueued.
+ */
+static struct isp1760_qtd *clean_up_qtdlist(struct isp1760_qtd *qtd)
+{
+ struct isp1760_qtd *tmp_qtd;
+ int last_one;
+
+ do {
+ tmp_qtd = qtd->hw_next;
+ last_one = qtd->status & URB_COMPLETE_NOTIFY;
+ list_del(&qtd->qtd_list);
+ isp1760_qtd_free(qtd);
+ qtd = tmp_qtd;
+ } while (!last_one && qtd);
+
+ return qtd;
+}
+
+static void do_atl_int(struct usb_hcd *usb_hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ u32 done_map, skip_map;
+ struct ptd ptd;
+ struct urb *urb = NULL;
+ u32 atl_regs_base;
+ u32 atl_regs;
+ u32 queue_entry;
+ u32 payload;
+ u32 length;
+ u32 or_map;
+ u32 status = -EINVAL;
+ int error;
+ struct isp1760_qtd *qtd;
+ struct isp1760_qh *qh;
+ u32 rl;
+ u32 nakcount;
+
+ done_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_PTD_DONEMAP_REG);
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+
+ or_map = isp1760_readl(usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+ or_map &= ~done_map;
+ isp1760_writel(or_map, usb_hcd->regs + HC_ATL_IRQ_MASK_OR_REG);
+
+ atl_regs_base = ATL_REGS_OFFSET;
+ while (done_map) {
+ u32 dw1;
+ u32 dw2;
+ u32 dw3;
+
+ status = 0;
+
+ queue_entry = __ffs(done_map);
+ done_map &= ~(1 << queue_entry);
+ skip_map |= 1 << queue_entry;
+
+ atl_regs = atl_regs_base + queue_entry * sizeof(struct ptd);
+
+ urb = priv->atl_ints[queue_entry].urb;
+ qtd = priv->atl_ints[queue_entry].qtd;
+ qh = priv->atl_ints[queue_entry].qh;
+ payload = priv->atl_ints[queue_entry].payload;
+
+ if (!qh) {
+ printk(KERN_ERR "qh is 0\n");
+ continue;
+ }
+ priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + atl_regs,
+ atl_regs, sizeof(ptd));
+
+ dw1 = le32_to_cpu(ptd.dw1);
+ dw2 = le32_to_cpu(ptd.dw2);
+ dw3 = le32_to_cpu(ptd.dw3);
+ rl = (dw2 >> 25) & 0x0f;
+ nakcount = (dw3 >> 19) & 0xf;
+
+ /* Transfer Error, *but* active and no HALT -> reload */
+ if ((dw3 & DW3_ERROR_BIT) && (dw3 & DW3_QTD_ACTIVE) &&
+ !(dw3 & DW3_HALT_BIT)) {
+
+ /* according to ppriv code, we have to
+ * reload this one if trasfered bytes != requested bytes
+ * else act like everything went smooth..
+ * XXX This just doesn't feel right and hasn't
+ * triggered so far.
+ */
+
+ length = PTD_XFERRED_LENGTH(dw3);
+ printk(KERN_ERR "Should reload now.... transfered %d "
+ "of %zu\n", length, qtd->length);
+ BUG();
+ }
+
+ if (!nakcount && (dw3 & DW3_QTD_ACTIVE)) {
+ u32 buffstatus;
+
+ /* XXX
+ * NAKs are handled in HW by the chip. Usually if the
+ * device is not able to send data fast enough.
+ * This did not trigger for a long time now.
+ */
+ printk(KERN_ERR "Reloading ptd %p/%p... qh %p readed: "
+ "%d of %d done: %08x cur: %08x\n", qtd,
+ urb, qh, PTD_XFERRED_LENGTH(dw3),
+ qtd->length, done_map,
+ (1 << queue_entry));
+
+ /* RL counter = ERR counter */
+ dw3 &= ~(0xf << 19);
+ dw3 |= rl << 19;
+ dw3 &= ~(3 << (55 - 32));
+ dw3 |= ERR_COUNTER << (55 - 32);
+
+ /*
+ * It is not needed to write skip map back because it
+ * is unchanged. Just make sure that this entry is
+ * unskipped once it gets written to the HW.
+ */
+ skip_map &= ~(1 << queue_entry);
+ or_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_IRQ_MASK_OR_REG);
+ or_map |= 1 << queue_entry;
+ isp1760_writel(or_map, usb_hcd->regs +
+ HC_ATL_IRQ_MASK_OR_REG);
+
+ ptd.dw3 = cpu_to_le32(dw3);
+ priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
+ atl_regs, sizeof(ptd));
+
+ ptd.dw0 |= __constant_cpu_to_le32(PTD_VALID);
+ priv_write_copy(priv, (u32 *)&ptd, usb_hcd->regs +
+ atl_regs, sizeof(ptd));
+
+ buffstatus = isp1760_readl(usb_hcd->regs +
+ HC_BUFFER_STATUS_REG);
+ buffstatus |= ATL_BUFFER;
+ isp1760_writel(buffstatus, usb_hcd->regs +
+ HC_BUFFER_STATUS_REG);
+ continue;
+ }
+
+ error = check_error(&ptd);
+ if (error) {
+ status = error;
+ priv->atl_ints[queue_entry].qh->toggle = 0;
+ priv->atl_ints[queue_entry].qh->ping = 0;
+ urb->status = -EPIPE;
+
+#if 0
+ printk(KERN_ERR "Error in %s().\n", __func__);
+ printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
+ "dw3: %08x dw4: %08x dw5: %08x dw6: "
+ "%08x dw7: %08x\n",
+ ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
+ ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
+#endif
+ } else {
+ if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+ priv->atl_ints[queue_entry].qh->toggle = dw3 &
+ (1 << 25);
+ priv->atl_ints[queue_entry].qh->ping = dw3 &
+ (1 << 26);
+ }
+ }
+
+ length = PTD_XFERRED_LENGTH(dw3);
+ if (length) {
+ switch (DW1_GET_PID(dw1)) {
+ case IN_PID:
+ priv_read_copy(priv,
+ priv->atl_ints[queue_entry].data_buffer,
+ usb_hcd->regs + payload, payload,
+ length);
+
+ case OUT_PID:
+
+ urb->actual_length += length;
+
+ case SETUP_PID:
+ break;
+ }
+ }
+
+ priv->atl_ints[queue_entry].data_buffer = NULL;
+ priv->atl_ints[queue_entry].urb = NULL;
+ priv->atl_ints[queue_entry].qtd = NULL;
+ priv->atl_ints[queue_entry].qh = NULL;
+
+ free_mem(priv, payload);
+
+ isp1760_writel(skip_map, usb_hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+
+ if (urb->status == -EPIPE) {
+ /* HALT was received */
+
+ qtd = clean_up_qtdlist(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else if (usb_pipebulk(urb->pipe) && (length < qtd->length)) {
+ /* short BULK received */
+
+ printk(KERN_ERR "short bulk, %d instead %d\n", length,
+ qtd->length);
+ if (urb->transfer_flags & URB_SHORT_NOT_OK) {
+ urb->status = -EREMOTEIO;
+ printk(KERN_ERR "not okey\n");
+ }
+
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+
+ qtd = clean_up_qtdlist(qtd);
+
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else if (qtd->status & URB_COMPLETE_NOTIFY) {
+ /* that was the last qtd of that URB */
+
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+
+ qtd = clean_this_qtd(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else {
+ /* next QTD of this URB */
+
+ qtd = clean_this_qtd(qtd);
+ BUG_ON(!qtd);
+ }
+
+ if (qtd)
+ enqueue_an_ATL_packet(usb_hcd, qh, qtd);
+
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_ATL_PTD_SKIPMAP_REG);
+ }
+}
+
+static void do_intl_int(struct usb_hcd *usb_hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ u32 done_map, skip_map;
+ struct ptd ptd;
+ struct urb *urb = NULL;
+ u32 int_regs;
+ u32 int_regs_base;
+ u32 payload;
+ u32 length;
+ u32 or_map;
+ int error;
+ u32 queue_entry;
+ struct isp1760_qtd *qtd;
+ struct isp1760_qh *qh;
+
+ done_map = isp1760_readl(usb_hcd->regs +
+ HC_INT_PTD_DONEMAP_REG);
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+
+ or_map = isp1760_readl(usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+ or_map &= ~done_map;
+ isp1760_writel(or_map, usb_hcd->regs + HC_INT_IRQ_MASK_OR_REG);
+
+ int_regs_base = INT_REGS_OFFSET;
+
+ while (done_map) {
+ u32 dw1;
+ u32 dw3;
+
+ queue_entry = __ffs(done_map);
+ done_map &= ~(1 << queue_entry);
+ skip_map |= 1 << queue_entry;
+
+ int_regs = int_regs_base + queue_entry * sizeof(struct ptd);
+ urb = priv->int_ints[queue_entry].urb;
+ qtd = priv->int_ints[queue_entry].qtd;
+ qh = priv->int_ints[queue_entry].qh;
+ payload = priv->int_ints[queue_entry].payload;
+
+ if (!qh) {
+ printk(KERN_ERR "(INT) qh is 0\n");
+ continue;
+ }
+
+ priv_read_copy(priv, (u32 *)&ptd, usb_hcd->regs + int_regs,
+ int_regs, sizeof(ptd));
+ dw1 = le32_to_cpu(ptd.dw1);
+ dw3 = le32_to_cpu(ptd.dw3);
+ check_int_err_status(le32_to_cpu(ptd.dw4));
+
+ error = check_error(&ptd);
+ if (error) {
+#if 0
+ printk(KERN_ERR "Error in %s().\n", __func__);
+ printk(KERN_ERR "IN dw0: %08x dw1: %08x dw2: %08x "
+ "dw3: %08x dw4: %08x dw5: %08x dw6: "
+ "%08x dw7: %08x\n",
+ ptd.dw0, ptd.dw1, ptd.dw2, ptd.dw3,
+ ptd.dw4, ptd.dw5, ptd.dw6, ptd.dw7);
+#endif
+ urb->status = -EPIPE;
+ priv->int_ints[queue_entry].qh->toggle = 0;
+ priv->int_ints[queue_entry].qh->ping = 0;
+
+ } else {
+ priv->int_ints[queue_entry].qh->toggle =
+ dw3 & (1 << 25);
+ priv->int_ints[queue_entry].qh->ping = dw3 & (1 << 26);
+ }
+
+ if (urb->dev->speed != USB_SPEED_HIGH)
+ length = PTD_XFERRED_LENGTH_LO(dw3);
+ else
+ length = PTD_XFERRED_LENGTH(dw3);
+
+ if (length) {
+ switch (DW1_GET_PID(dw1)) {
+ case IN_PID:
+ priv_read_copy(priv,
+ priv->int_ints[queue_entry].data_buffer,
+ usb_hcd->regs + payload , payload,
+ length);
+ case OUT_PID:
+
+ urb->actual_length += length;
+
+ case SETUP_PID:
+ break;
+ }
+ }
+
+ priv->int_ints[queue_entry].data_buffer = NULL;
+ priv->int_ints[queue_entry].urb = NULL;
+ priv->int_ints[queue_entry].qtd = NULL;
+ priv->int_ints[queue_entry].qh = NULL;
+
+ isp1760_writel(skip_map, usb_hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+ free_mem(priv, payload);
+
+ if (urb->status == -EPIPE) {
+ /* HALT received */
+
+ qtd = clean_up_qtdlist(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else if (qtd->status & URB_COMPLETE_NOTIFY) {
+
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+
+ qtd = clean_this_qtd(qtd);
+ isp1760_urb_done(priv, urb, urb->status);
+
+ } else {
+ /* next QTD of this URB */
+
+ qtd = clean_this_qtd(qtd);
+ BUG_ON(!qtd);
+ }
+
+ if (qtd)
+ enqueue_an_INT_packet(usb_hcd, qh, qtd);
+
+ skip_map = isp1760_readl(usb_hcd->regs +
+ HC_INT_PTD_SKIPMAP_REG);
+ }
+}
+
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+static struct isp1760_qh *qh_make(struct isp1760_hcd *priv, struct urb *urb,
+ gfp_t flags)
+{
+ struct isp1760_qh *qh;
+ int is_input, type;
+
+ qh = isp1760_qh_alloc(priv, flags);
+ if (!qh)
+ return qh;
+
+ /*
+ * init endpoint/device data for this QH
+ */
+ is_input = usb_pipein(urb->pipe);
+ type = usb_pipetype(urb->pipe);
+
+ if (type == PIPE_INTERRUPT) {
+
+ if (urb->dev->speed == USB_SPEED_HIGH) {
+
+ qh->period = urb->interval >> 3;
+ if (qh->period == 0 && urb->interval != 1) {
+ /* NOTE interval 2 or 4 uframes could work.
+ * But interval 1 scheduling is simpler, and
+ * includes high bandwidth.
+ */
+ printk(KERN_ERR "intr period %d uframes, NYET!",
+ urb->interval);
+ qh_destroy(qh);
+ return NULL;
+ }
+ } else {
+ qh->period = urb->interval;
+ }
+ }
+
+ /* support for tt scheduling, and access to toggles */
+ qh->dev = urb->dev;
+
+ if (!usb_pipecontrol(urb->pipe))
+ usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), !is_input,
+ 1);
+ return qh;
+}
+
+/*
+ * For control/bulk/interrupt, return QH with these TDs appended.
+ * Allocates and initializes the QH if necessary.
+ * Returns null if it can't allocate a QH it needs to.
+ * If the QH has TDs (urbs) already, that's great.
+ */
+static struct isp1760_qh *qh_append_tds(struct isp1760_hcd *priv,
+ struct urb *urb, struct list_head *qtd_list, int epnum,
+ void **ptr)
+{
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+ struct isp1760_qtd *prev_qtd;
+
+ qh = (struct isp1760_qh *)*ptr;
+ if (!qh) {
+ /* can't sleep here, we have priv->lock... */
+ qh = qh_make(priv, urb, GFP_ATOMIC);
+ if (!qh)
+ return qh;
+ *ptr = qh;
+ }
+
+ qtd = list_entry(qtd_list->next, struct isp1760_qtd,
+ qtd_list);
+ if (!list_empty(&qh->qtd_list))
+ prev_qtd = list_entry(qh->qtd_list.prev,
+ struct isp1760_qtd, qtd_list);
+ else
+ prev_qtd = NULL;
+
+ list_splice(qtd_list, qh->qtd_list.prev);
+ if (prev_qtd) {
+ BUG_ON(prev_qtd->hw_next);
+ prev_qtd->hw_next = qtd;
+ }
+
+ urb->hcpriv = qh;
+ return qh;
+}
+
+static void qtd_list_free(struct isp1760_hcd *priv, struct urb *urb,
+ struct list_head *qtd_list)
+{
+ struct list_head *entry, *temp;
+
+ list_for_each_safe(entry, temp, qtd_list) {
+ struct isp1760_qtd *qtd;
+
+ qtd = list_entry(entry, struct isp1760_qtd, qtd_list);
+ list_del(&qtd->qtd_list);
+ isp1760_qtd_free(qtd);
+ }
+}
+
+static int isp1760_prepare_enqueue(struct isp1760_hcd *priv, struct urb *urb,
+ struct list_head *qtd_list, gfp_t mem_flags, packet_enqueue *p)
+{
+ struct isp1760_qtd *qtd;
+ int epnum;
+ unsigned long flags;
+ struct isp1760_qh *qh = NULL;
+ int rc;
+ int qh_busy;
+
+ qtd = list_entry(qtd_list->next, struct isp1760_qtd, qtd_list);
+ epnum = urb->ep->desc.bEndpointAddress;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &priv_to_hcd(priv)->flags)) {
+ rc = -ESHUTDOWN;
+ goto done;
+ }
+ rc = usb_hcd_link_urb_to_ep(priv_to_hcd(priv), urb);
+ if (rc)
+ goto done;
+
+ qh = urb->ep->hcpriv;
+ if (qh)
+ qh_busy = !list_empty(&qh->qtd_list);
+ else
+ qh_busy = 0;
+
+ qh = qh_append_tds(priv, urb, qtd_list, epnum, &urb->ep->hcpriv);
+ if (!qh) {
+ usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
+ rc = -ENOMEM;
+ goto done;
+ }
+
+ if (!qh_busy)
+ p(priv_to_hcd(priv), qh, qtd);
+
+done:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ if (!qh)
+ qtd_list_free(priv, urb, qtd_list);
+ return rc;
+}
+
+static struct isp1760_qtd *isp1760_qtd_alloc(struct isp1760_hcd *priv,
+ gfp_t flags)
+{
+ struct isp1760_qtd *qtd;
+
+ qtd = kmem_cache_zalloc(qtd_cachep, flags);
+ if (qtd)
+ INIT_LIST_HEAD(&qtd->qtd_list);
+
+ return qtd;
+}
+
+/*
+ * create a list of filled qtds for this URB; won't link into qh.
+ */
+static struct list_head *qh_urb_transaction(struct isp1760_hcd *priv,
+ struct urb *urb, struct list_head *head, gfp_t flags)
+{
+ struct isp1760_qtd *qtd, *qtd_prev;
+ void *buf;
+ int len, maxpacket;
+ int is_input;
+ u32 token;
+
+ /*
+ * URBs map to sequences of QTDs: one logical transaction
+ */
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ return NULL;
+
+ list_add_tail(&qtd->qtd_list, head);
+ qtd->urb = urb;
+ urb->status = -EINPROGRESS;
+
+ token = 0;
+ /* for split transactions, SplitXState initialized to zero */
+
+ len = urb->transfer_buffer_length;
+ is_input = usb_pipein(urb->pipe);
+ if (usb_pipecontrol(urb->pipe)) {
+ /* SETUP pid */
+ qtd_fill(qtd, urb->setup_packet,
+ sizeof(struct usb_ctrlrequest),
+ token | SETUP_PID);
+
+ /* ... and always at least one more pid */
+ token ^= DATA_TOGGLE;
+ qtd_prev = qtd;
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = qtd;
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* for zero length DATA stages, STATUS is always IN */
+ if (len == 0)
+ token |= IN_PID;
+ }
+
+ /*
+ * data transfer stage: buffer setup
+ */
+ buf = urb->transfer_buffer;
+
+ if (is_input)
+ token |= IN_PID;
+ else
+ token |= OUT_PID;
+
+ maxpacket = max_packet(usb_maxpacket(urb->dev, urb->pipe, !is_input));
+
+ /*
+ * buffer gets wrapped in one or more qtds;
+ * last one may be "short" (including zero len)
+ * and may serve as a control status ack
+ */
+ for (;;) {
+ int this_qtd_len;
+
+ if (!buf && len) {
+ /* XXX This looks like usb storage / SCSI bug */
+ printk(KERN_ERR "buf is null, dma is %08lx len is %d\n",
+ (long unsigned)urb->transfer_dma, len);
+ WARN_ON(1);
+ }
+
+ this_qtd_len = qtd_fill(qtd, buf, len, token);
+ len -= this_qtd_len;
+ buf += this_qtd_len;
+
+ /* qh makes control packets use qtd toggle; maybe switch it */
+ if ((maxpacket & (this_qtd_len + (maxpacket - 1))) == 0)
+ token ^= DATA_TOGGLE;
+
+ if (len <= 0)
+ break;
+
+ qtd_prev = qtd;
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = qtd;
+ list_add_tail(&qtd->qtd_list, head);
+ }
+
+ /*
+ * control requests may need a terminating data "status" ack;
+ * bulk ones may need a terminating short packet (zero length).
+ */
+ if (urb->transfer_buffer_length != 0) {
+ int one_more = 0;
+
+ if (usb_pipecontrol(urb->pipe)) {
+ one_more = 1;
+ /* "in" <--> "out" */
+ token ^= IN_PID;
+ /* force DATA1 */
+ token |= DATA_TOGGLE;
+ } else if (usb_pipebulk(urb->pipe)
+ && (urb->transfer_flags & URB_ZERO_PACKET)
+ && !(urb->transfer_buffer_length % maxpacket)) {
+ one_more = 1;
+ }
+ if (one_more) {
+ qtd_prev = qtd;
+ qtd = isp1760_qtd_alloc(priv, flags);
+ if (!qtd)
+ goto cleanup;
+ qtd->urb = urb;
+ qtd_prev->hw_next = qtd;
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* never any data in such packets */
+ qtd_fill(qtd, NULL, 0, token);
+ }
+ }
+
+ qtd->status = URB_COMPLETE_NOTIFY;
+ return head;
+
+cleanup:
+ qtd_list_free(priv, urb, head);
+ return NULL;
+}
+
+static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct list_head qtd_list;
+ packet_enqueue *pe;
+
+ INIT_LIST_HEAD(&qtd_list);
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+
+ if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ pe = enqueue_an_ATL_packet;
+ break;
+
+ case PIPE_INTERRUPT:
+ if (!qh_urb_transaction(priv, urb, &qtd_list, mem_flags))
+ return -ENOMEM;
+ pe = enqueue_an_INT_packet;
+ break;
+
+ case PIPE_ISOCHRONOUS:
+ printk(KERN_ERR "PIPE_ISOCHRONOUS ain't supported\n");
+ default:
+ return -EPIPE;
+ }
+
+ isp1760_prepare_enqueue(priv, urb, &qtd_list, mem_flags, pe);
+ return 0;
+}
+
+static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct inter_packet_info *ints;
+ u32 i;
+ u32 reg_base, or_reg, skip_reg;
+ int flags;
+ struct ptd ptd;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_ISOCHRONOUS:
+ return -EPIPE;
+ break;
+
+ case PIPE_INTERRUPT:
+ ints = priv->int_ints;
+ reg_base = INT_REGS_OFFSET;
+ or_reg = HC_INT_IRQ_MASK_OR_REG;
+ skip_reg = HC_INT_PTD_SKIPMAP_REG;
+ break;
+
+ default:
+ ints = priv->atl_ints;
+ reg_base = ATL_REGS_OFFSET;
+ or_reg = HC_ATL_IRQ_MASK_OR_REG;
+ skip_reg = HC_ATL_PTD_SKIPMAP_REG;
+ break;
+ }
+
+ memset(&ptd, 0, sizeof(ptd));
+ spin_lock_irqsave(&priv->lock, flags);
+
+ for (i = 0; i < 32; i++) {
+ if (ints->urb == urb) {
+ u32 skip_map;
+ u32 or_map;
+ struct isp1760_qtd *qtd;
+
+ skip_map = isp1760_readl(hcd->regs + skip_reg);
+ skip_map |= 1 << i;
+ isp1760_writel(skip_map, hcd->regs + skip_reg);
+
+ or_map = isp1760_readl(hcd->regs + or_reg);
+ or_map &= ~(1 << i);
+ isp1760_writel(or_map, hcd->regs + or_reg);
+
+ priv_write_copy(priv, (u32 *)&ptd, hcd->regs + reg_base
+ + i * sizeof(ptd), sizeof(ptd));
+ qtd = ints->qtd;
+
+ clean_up_qtdlist(qtd);
+
+ free_mem(priv, ints->payload);
+
+ ints->urb = NULL;
+ ints->qh = NULL;
+ ints->qtd = NULL;
+ ints->data_buffer = NULL;
+ ints->payload = 0;
+
+ isp1760_urb_done(priv, urb, status);
+ break;
+ }
+ ints++;
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+}
+
+static irqreturn_t isp1760_irq(struct usb_hcd *usb_hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ u32 imask;
+ irqreturn_t irqret = IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ if (!(usb_hcd->state & HC_STATE_RUNNING))
+ goto leave;
+
+ imask = isp1760_readl(usb_hcd->regs + HC_INTERRUPT_REG);
+ if (unlikely(!imask))
+ goto leave;
+
+ isp1760_writel(imask, usb_hcd->regs + HC_INTERRUPT_REG);
+ if (imask & HC_ATL_INT)
+ do_atl_int(usb_hcd);
+
+ if (imask & HC_INTL_INT)
+ do_intl_int(usb_hcd);
+
+ irqret = IRQ_HANDLED;
+leave:
+ spin_unlock(&priv->lock);
+ return irqret;
+}
+
+static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 temp, status = 0;
+ u32 mask;
+ int retval = 1;
+ unsigned long flags;
+
+ /* if !USB_SUSPEND, root hub timers won't get shut down ... */
+ if (!HC_IS_RUNNING(hcd->state))
+ return 0;
+
+ /* init status to no-changes */
+ buf[0] = 0;
+ mask = PORT_CSC;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ temp = isp1760_readl(hcd->regs + HC_PORTSC1);
+
+ if (temp & PORT_OWNER) {
+ if (temp & PORT_CSC) {
+ temp &= ~PORT_CSC;
+ isp1760_writel(temp, hcd->regs + HC_PORTSC1);
+ goto done;
+ }
+ }
+
+ /*
+ * Return status information even for ports with OWNER set.
+ * Otherwise khubd wouldn't see the disconnect event when a
+ * high-speed device is switched over to the companion
+ * controller by the user.
+ */
+
+ if ((temp & mask) != 0
+ || ((temp & PORT_RESUME) != 0
+ && time_after_eq(jiffies,
+ priv->reset_done))) {
+ buf [0] |= 1 << (0 + 1);
+ status = STS_PCD;
+ }
+ /* FIXME autosuspend idle root hubs */
+done:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return status ? retval : 0;
+}
+
+static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+ struct usb_hub_descriptor *desc)
+{
+ int ports = HCS_N_PORTS(priv->hcs_params);
+ u16 temp;
+
+ desc->bDescriptorType = 0x29;
+ /* priv 1.0, 2.3.9 says 20ms max */
+ desc->bPwrOn2PwrGood = 10;
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = ports;
+ temp = 1 + (ports / 8);
+ desc->bDescLength = 7 + 2 * temp;
+
+ /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+ memset(&desc->bitmap[0], 0, temp);
+ memset(&desc->bitmap[temp], 0xff, temp);
+
+ /* per-port overcurrent reporting */
+ temp = 0x0008;
+ if (HCS_PPC(priv->hcs_params))
+ /* per-port power control */
+ temp |= 0x0001;
+ else
+ /* no power switching */
+ temp |= 0x0002;
+ desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+static int check_reset_complete(struct isp1760_hcd *priv, int index,
+ u32 __iomem *status_reg, int port_status)
+{
+ if (!(port_status & PORT_CONNECT))
+ return port_status;
+
+ /* if reset finished and it's still not enabled -- handoff */
+ if (!(port_status & PORT_PE)) {
+
+ printk(KERN_ERR "port %d full speed --> companion\n",
+ index + 1);
+
+ port_status |= PORT_OWNER;
+ port_status &= ~PORT_RWC_BITS;
+ isp1760_writel(port_status, status_reg);
+
+ } else
+ printk(KERN_ERR "port %d high speed\n", index + 1);
+
+ return port_status;
+}
+
+static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int ports = HCS_N_PORTS(priv->hcs_params);
+ u32 __iomem *status_reg = hcd->regs + HC_PORTSC1;
+ u32 temp, status;
+ unsigned long flags;
+ int retval = 0;
+ unsigned selector;
+
+ /*
+ * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+ * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+ * (track current state ourselves) ... blink for diagnostics,
+ * power, "this is the one", etc. EHCI spec supports this.
+ */
+
+ spin_lock_irqsave(&priv->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = isp1760_readl(status_reg);
+
+ /*
+ * Even if OWNER is set, so the port is owned by the
+ * companion controller, khubd needs to be able to clear
+ * the port-change status bits (especially
+ * USB_PORT_FEAT_C_CONNECTION).
+ */
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ isp1760_writel(temp & ~PORT_PE, status_reg);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ /* XXX error? */
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ if (temp & PORT_RESET)
+ goto error;
+
+ if (temp & PORT_SUSPEND) {
+ if ((temp & PORT_PE) == 0)
+ goto error;
+ /* resume signaling for 20 msec */
+ temp &= ~(PORT_RWC_BITS);
+ isp1760_writel(temp | PORT_RESUME,
+ status_reg);
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(20);
+ }
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ /* we auto-clear this feature */
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(priv->hcs_params))
+ isp1760_writel(temp & ~PORT_POWER, status_reg);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ isp1760_writel(temp | PORT_CSC,
+ status_reg);
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ /* XXX error ?*/
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ /* GetPortStatus clears reset */
+ break;
+ default:
+ goto error;
+ }
+ isp1760_readl(hcd->regs + HC_USBCMD);
+ break;
+ case GetHubDescriptor:
+ isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
+ buf);
+ break;
+ case GetHubStatus:
+ /* no hub-wide feature/status flags */
+ memset(buf, 0, 4);
+ break;
+ case GetPortStatus:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ status = 0;
+ temp = isp1760_readl(status_reg);
+
+ /* wPortChange bits */
+ if (temp & PORT_CSC)
+ status |= 1 << USB_PORT_FEAT_C_CONNECTION;
+
+
+ /* whoever resumes must GetPortStatus to complete it!! */
+ if (temp & PORT_RESUME) {
+ printk(KERN_ERR "Port resume should be skipped.\n");
+
+ /* Remote Wakeup received? */
+ if (!priv->reset_done) {
+ /* resume signaling for 20 msec */
+ priv->reset_done = jiffies
+ + msecs_to_jiffies(20);
+ /* check the port again */
+ mod_timer(&priv_to_hcd(priv)->rh_timer,
+ priv->reset_done);
+ }
+
+ /* resume completed? */
+ else if (time_after_eq(jiffies,
+ priv->reset_done)) {
+ status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+ priv->reset_done = 0;
+
+ /* stop resume signaling */
+ temp = isp1760_readl(status_reg);
+ isp1760_writel(
+ temp & ~(PORT_RWC_BITS | PORT_RESUME),
+ status_reg);
+ retval = handshake(priv, status_reg,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ isp1760_err(priv,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ }
+ }
+
+ /* whoever resets must GetPortStatus to complete it!! */
+ if ((temp & PORT_RESET)
+ && time_after_eq(jiffies,
+ priv->reset_done)) {
+ status |= 1 << USB_PORT_FEAT_C_RESET;
+ priv->reset_done = 0;
+
+ /* force reset to complete */
+ isp1760_writel(temp & ~PORT_RESET,
+ status_reg);
+ /* REVISIT: some hardware needs 550+ usec to clear
+ * this bit; seems too long to spin routinely...
+ */
+ retval = handshake(priv, status_reg,
+ PORT_RESET, 0, 750);
+ if (retval != 0) {
+ isp1760_err(priv, "port %d reset error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+
+ /* see what we found out */
+ temp = check_reset_complete(priv, wIndex, status_reg,
+ isp1760_readl(status_reg));
+ }
+ /*
+ * Even if OWNER is set, there's no harm letting khubd
+ * see the wPortStatus values (they should all be 0 except
+ * for PORT_POWER anyway).
+ */
+
+ if (temp & PORT_OWNER)
+ printk(KERN_ERR "Warning: PORT_OWNER is set\n");
+
+ if (temp & PORT_CONNECT) {
+ status |= 1 << USB_PORT_FEAT_CONNECTION;
+ /* status may be from integrated TT */
+ status |= ehci_port_speed(priv, temp);
+ }
+ if (temp & PORT_PE)
+ status |= 1 << USB_PORT_FEAT_ENABLE;
+ if (temp & (PORT_SUSPEND|PORT_RESUME))
+ status |= 1 << USB_PORT_FEAT_SUSPEND;
+ if (temp & PORT_RESET)
+ status |= 1 << USB_PORT_FEAT_RESET;
+ if (temp & PORT_POWER)
+ status |= 1 << USB_PORT_FEAT_POWER;
+
+ put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case SetPortFeature:
+ selector = wIndex >> 8;
+ wIndex &= 0xff;
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = isp1760_readl(status_reg);
+ if (temp & PORT_OWNER)
+ break;
+
+/* temp &= ~PORT_RWC_BITS; */
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ isp1760_writel(temp | PORT_PE, status_reg);
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+ if ((temp & PORT_PE) == 0
+ || (temp & PORT_RESET) != 0)
+ goto error;
+
+ isp1760_writel(temp | PORT_SUSPEND, status_reg);
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(priv->hcs_params))
+ isp1760_writel(temp | PORT_POWER,
+ status_reg);
+ break;
+ case USB_PORT_FEAT_RESET:
+ if (temp & PORT_RESUME)
+ goto error;
+ /* line status bits may report this as low speed,
+ * which can be fine if this root hub has a
+ * transaction translator built in.
+ */
+ if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+ && PORT_USB11(temp)) {
+ temp |= PORT_OWNER;
+ } else {
+ temp |= PORT_RESET;
+ temp &= ~PORT_PE;
+
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 spec says 50 ms resets on root
+ */
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(50);
+ }
+ isp1760_writel(temp, status_reg);
+ break;
+ default:
+ goto error;
+ }
+ isp1760_readl(hcd->regs + HC_USBCMD);
+ break;
+
+ default:
+error:
+ /* "stall" on error */
+ retval = -EPIPE;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return retval;
+}
+
+static void isp1760_endpoint_disable(struct usb_hcd *usb_hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(usb_hcd);
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+ u32 flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ qh = ep->hcpriv;
+ if (!qh)
+ goto out;
+
+ ep->hcpriv = NULL;
+ do {
+ /* more than entry might get removed */
+ if (list_empty(&qh->qtd_list))
+ break;
+
+ qtd = list_first_entry(&qh->qtd_list, struct isp1760_qtd,
+ qtd_list);
+
+ if (qtd->status & URB_ENQUEUED) {
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+ isp1760_urb_dequeue(usb_hcd, qtd->urb, -ECONNRESET);
+ spin_lock_irqsave(&priv->lock, flags);
+ } else {
+ struct urb *urb;
+
+ urb = qtd->urb;
+ clean_up_qtdlist(qtd);
+ isp1760_urb_done(priv, urb, -ECONNRESET);
+ }
+ } while (1);
+
+ qh_destroy(qh);
+ /* remove requests and leak them.
+ * ATL are pretty fast done, INT could take a while...
+ * The latter shoule be removed
+ */
+out:
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int isp1760_get_frame(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 fr;
+
+ fr = isp1760_readl(hcd->regs + HC_FRINDEX);
+ return (fr >> 3) % priv->periodic_size;
+}
+
+static void isp1760_stop(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
+ NULL, 0);
+ mdelay(20);
+
+ spin_lock_irq(&priv->lock);
+ ehci_reset(priv);
+ /* Disable IRQ */
+ isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL);
+ spin_unlock_irq(&priv->lock);
+
+ isp1760_writel(0, hcd->regs + HC_CONFIGFLAG);
+}
+
+static void isp1760_shutdown(struct usb_hcd *hcd)
+{
+ u32 command;
+
+ isp1760_stop(hcd);
+ isp1760_writel(HW_DATA_BUS_32BIT, hcd->regs + HC_HW_MODE_CTRL);
+
+ command = isp1760_readl(hcd->regs + HC_USBCMD);
+ command &= ~CMD_RUN;
+ isp1760_writel(command, hcd->regs + HC_USBCMD);
+}
+
+static const struct hc_driver isp1760_hc_driver = {
+ .description = "isp1760-hcd",
+ .product_desc = "NXP ISP1760 USB Host Controller",
+ .hcd_priv_size = sizeof(struct isp1760_hcd),
+ .irq = isp1760_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = isp1760_hc_setup,
+ .start = isp1760_run,
+ .stop = isp1760_stop,
+ .shutdown = isp1760_shutdown,
+ .urb_enqueue = isp1760_urb_enqueue,
+ .urb_dequeue = isp1760_urb_dequeue,
+ .endpoint_disable = isp1760_endpoint_disable,
+ .get_frame_number = isp1760_get_frame,
+ .hub_status_data = isp1760_hub_status_data,
+ .hub_control = isp1760_hub_control,
+};
+
+int __init init_kmem_once(void)
+{
+ qtd_cachep = kmem_cache_create("isp1760_qtd",
+ sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
+ SLAB_MEM_SPREAD, NULL);
+
+ if (!qtd_cachep)
+ return -ENOMEM;
+
+ qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh),
+ 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
+
+ if (!qh_cachep) {
+ kmem_cache_destroy(qtd_cachep);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void deinit_kmem_cache(void)
+{
+ kmem_cache_destroy(qtd_cachep);
+ kmem_cache_destroy(qh_cachep);
+}
+
+struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
+ u64 irqflags, struct device *dev, const char *busname)
+{
+ struct usb_hcd *hcd;
+ struct isp1760_hcd *priv;
+ int ret;
+
+ if (usb_disabled())
+ return ERR_PTR(-ENODEV);
+
+ /* prevent usb-core allocating DMA pages */
+ dev->dma_mask = NULL;
+
+ hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev->bus_id);
+ if (!hcd)
+ return ERR_PTR(-ENOMEM);
+
+ priv = hcd_to_priv(hcd);
+ init_memory(priv);
+ hcd->regs = ioremap(res_start, res_len);
+ if (!hcd->regs) {
+ ret = -EIO;
+ goto err_put;
+ }
+
+ ret = usb_add_hcd(hcd, irq, irqflags);
+ if (ret)
+ goto err_unmap;
+
+ hcd->irq = irq;
+ hcd->rsrc_start = res_start;
+ hcd->rsrc_len = res_len;
+
+ return hcd;
+
+err_unmap:
+ iounmap(hcd->regs);
+
+err_put:
+ usb_put_hcd(hcd);
+
+ return ERR_PTR(ret);
+}
+
+MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
+MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
new file mode 100644
index 0000000..3d86d0f
--- /dev/null
+++ b/drivers/usb/host/isp1760-hcd.h
@@ -0,0 +1,206 @@
+#ifndef _ISP1760_HCD_H_
+#define _ISP1760_HCD_H_
+
+/* exports for if */
+struct usb_hcd *isp1760_register(u64 res_start, u64 res_len, int irq,
+ u64 irqflags, struct device *dev, const char *busname);
+int init_kmem_once(void);
+void deinit_kmem_cache(void);
+
+/* EHCI capability registers */
+#define HC_CAPLENGTH 0x00
+#define HC_HCSPARAMS 0x04
+#define HC_HCCPARAMS 0x08
+
+/* EHCI operational registers */
+#define HC_USBCMD 0x20
+#define HC_USBSTS 0x24
+#define HC_FRINDEX 0x2c
+#define HC_CONFIGFLAG 0x60
+#define HC_PORTSC1 0x64
+#define HC_ISO_PTD_DONEMAP_REG 0x130
+#define HC_ISO_PTD_SKIPMAP_REG 0x134
+#define HC_ISO_PTD_LASTPTD_REG 0x138
+#define HC_INT_PTD_DONEMAP_REG 0x140
+#define HC_INT_PTD_SKIPMAP_REG 0x144
+#define HC_INT_PTD_LASTPTD_REG 0x148
+#define HC_ATL_PTD_DONEMAP_REG 0x150
+#define HC_ATL_PTD_SKIPMAP_REG 0x154
+#define HC_ATL_PTD_LASTPTD_REG 0x158
+
+/* Configuration Register */
+#define HC_HW_MODE_CTRL 0x300
+#define ALL_ATX_RESET (1 << 31)
+#define HW_DATA_BUS_32BIT (1 << 8)
+#define HW_DACK_POL_HIGH (1 << 6)
+#define HW_DREQ_POL_HIGH (1 << 5)
+#define HW_INTR_HIGH_ACT (1 << 2)
+#define HW_INTR_EDGE_TRIG (1 << 1)
+#define HW_GLOBAL_INTR_EN (1 << 0)
+
+#define HC_CHIP_ID_REG 0x304
+#define HC_SCRATCH_REG 0x308
+
+#define HC_RESET_REG 0x30c
+#define SW_RESET_RESET_HC (1 << 1)
+#define SW_RESET_RESET_ALL (1 << 0)
+
+#define HC_BUFFER_STATUS_REG 0x334
+#define ATL_BUFFER 0x1
+#define INT_BUFFER 0x2
+#define ISO_BUFFER 0x4
+#define BUFFER_MAP 0x7
+
+#define HC_MEMORY_REG 0x33c
+#define HC_PORT1_CTRL 0x374
+#define PORT1_POWER (3 << 3)
+#define PORT1_INIT1 (1 << 7)
+#define PORT1_INIT2 (1 << 23)
+
+/* Interrupt Register */
+#define HC_INTERRUPT_REG 0x310
+
+#define HC_INTERRUPT_ENABLE 0x314
+#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT | HC_EOT_INT)
+#define FINAL_HW_CONFIG (HW_GLOBAL_INTR_EN | HW_DATA_BUS_32BIT)
+
+#define HC_ISO_INT (1 << 9)
+#define HC_ATL_INT (1 << 8)
+#define HC_INTL_INT (1 << 7)
+#define HC_EOT_INT (1 << 3)
+#define HC_SOT_INT (1 << 1)
+
+#define HC_ISO_IRQ_MASK_OR_REG 0x318
+#define HC_INT_IRQ_MASK_OR_REG 0x31C
+#define HC_ATL_IRQ_MASK_OR_REG 0x320
+#define HC_ISO_IRQ_MASK_AND_REG 0x324
+#define HC_INT_IRQ_MASK_AND_REG 0x328
+#define HC_ATL_IRQ_MASK_AND_REG 0x32C
+
+/* Register sets */
+#define HC_BEGIN_OF_ATL 0x0c00
+#define HC_BEGIN_OF_INT 0x0800
+#define HC_BEGIN_OF_ISO 0x0400
+#define HC_BEGIN_OF_PAYLOAD 0x1000
+
+/* urb state*/
+#define DELETE_URB (0x0008)
+#define NO_TRANSFER_ACTIVE (0xffffffff)
+
+#define ATL_REGS_OFFSET (0xc00)
+#define INT_REGS_OFFSET (0x800)
+
+/* Philips Transfer Descriptor (PTD) */
+struct ptd {
+ __le32 dw0;
+ __le32 dw1;
+ __le32 dw2;
+ __le32 dw3;
+ __le32 dw4;
+ __le32 dw5;
+ __le32 dw6;
+ __le32 dw7;
+};
+
+struct inter_packet_info {
+ void *data_buffer;
+ u32 payload;
+#define PTD_FIRE_NEXT (1 << 0)
+#define PTD_URB_FINISHED (1 << 1)
+ struct urb *urb;
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+};
+
+
+typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd);
+
+#define isp1760_info(priv, fmt, args...) \
+ dev_info(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+#define isp1760_err(priv, fmt, args...) \
+ dev_err(priv_to_hcd(priv)->self.controller, fmt, ##args)
+
+/* chip memory management */
+struct memory_chunk {
+ unsigned int start;
+ unsigned int size;
+ unsigned int free;
+};
+
+/*
+ * 60kb divided in:
+ * - 32 blocks @ 256 bytes
+ * - 20 blocks @ 1024 bytes
+ * - 4 blocks @ 8192 bytes
+ */
+
+#define BLOCK_1_NUM 32
+#define BLOCK_2_NUM 20
+#define BLOCK_3_NUM 4
+
+#define BLOCK_1_SIZE 256
+#define BLOCK_2_SIZE 1024
+#define BLOCK_3_SIZE 8192
+#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
+#define PAYLOAD_SIZE 0xf000
+
+/* I saw if some reloads if the pointer was negative */
+#define ISP1760_NULL_POINTER (0x400)
+
+/* ATL */
+/* DW0 */
+#define PTD_VALID 1
+#define PTD_LENGTH(x) (((u32) x) << 3)
+#define PTD_MAXPACKET(x) (((u32) x) << 18)
+#define PTD_MULTI(x) (((u32) x) << 29)
+#define PTD_ENDPOINT(x) (((u32) x) << 31)
+/* DW1 */
+#define PTD_DEVICE_ADDR(x) (((u32) x) << 3)
+#define PTD_PID_TOKEN(x) (((u32) x) << 10)
+#define PTD_TRANS_BULK ((u32) 2 << 12)
+#define PTD_TRANS_INT ((u32) 3 << 12)
+#define PTD_TRANS_SPLIT ((u32) 1 << 14)
+#define PTD_SE_USB_LOSPEED ((u32) 2 << 16)
+#define PTD_PORT_NUM(x) (((u32) x) << 18)
+#define PTD_HUB_NUM(x) (((u32) x) << 25)
+#define PTD_PING(x) (((u32) x) << 26)
+/* DW2 */
+#define PTD_RL_CNT(x) (((u32) x) << 25)
+#define PTD_DATA_START_ADDR(x) (((u32) x) << 8)
+#define BASE_ADDR 0x1000
+/* DW3 */
+#define PTD_CERR(x) (((u32) x) << 23)
+#define PTD_NAC_CNT(x) (((u32) x) << 19)
+#define PTD_ACTIVE ((u32) 1 << 31)
+#define PTD_DATA_TOGGLE(x) (((u32) x) << 25)
+
+#define DW3_HALT_BIT (1 << 30)
+#define DW3_ERROR_BIT (1 << 28)
+#define DW3_QTD_ACTIVE (1 << 31)
+
+#define INT_UNDERRUN (1 << 2)
+#define INT_BABBLE (1 << 1)
+#define INT_EXACT (1 << 0)
+
+#define DW1_GET_PID(x) (((x) >> 10) & 0x3)
+#define PTD_XFERRED_LENGTH(x) ((x) & 0x7fff)
+#define PTD_XFERRED_LENGTH_LO(x) ((x) & 0x7ff)
+
+#define SETUP_PID (2)
+#define IN_PID (1)
+#define OUT_PID (0)
+#define GET_QTD_TOKEN_TYPE(x) ((x) & 0x3)
+
+#define DATA_TOGGLE (1 << 31)
+#define GET_DATA_TOGGLE(x) ((x) >> 31)
+
+/* Errata 1 */
+#define RL_COUNTER (0)
+#define NAK_COUNTER (0)
+#define ERR_COUNTER (2)
+
+#define HC_ATL_PL_SIZE (8192)
+
+#endif
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
new file mode 100644
index 0000000..73fb2a3
--- /dev/null
+++ b/drivers/usb/host/isp1760-if.c
@@ -0,0 +1,298 @@
+/*
+ * Glue code for the ISP1760 driver and bus
+ * Currently there is support for
+ * - OpenFirmware
+ * - PCI
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/io.h>
+
+#include "../core/hcd.h"
+#include "isp1760-hcd.h"
+
+#ifdef CONFIG_USB_ISP1760_OF
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#endif
+
+#ifdef CONFIG_USB_ISP1760_PCI
+#include <linux/pci.h>
+#endif
+
+#ifdef CONFIG_USB_ISP1760_OF
+static int of_isp1760_probe(struct of_device *dev,
+ const struct of_device_id *match)
+{
+ struct usb_hcd *hcd;
+ struct device_node *dp = dev->node;
+ struct resource *res;
+ struct resource memory;
+ struct of_irq oirq;
+ int virq;
+ u64 res_len;
+ int ret;
+
+ ret = of_address_to_resource(dp, 0, &memory);
+ if (ret)
+ return -ENXIO;
+
+ res = request_mem_region(memory.start, memory.end - memory.start + 1,
+ dev->dev.bus_id);
+ if (!res)
+ return -EBUSY;
+
+ res_len = memory.end - memory.start + 1;
+
+ if (of_irq_map_one(dp, 0, &oirq)) {
+ ret = -ENODEV;
+ goto release_reg;
+ }
+
+ virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
+ oirq.size);
+
+ hcd = isp1760_register(memory.start, res_len, virq,
+ IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
+ if (IS_ERR(hcd)) {
+ ret = PTR_ERR(hcd);
+ goto release_reg;
+ }
+
+ dev_set_drvdata(&dev->dev, hcd);
+ return ret;
+
+release_reg:
+ release_mem_region(memory.start, memory.end - memory.start + 1);
+ return ret;
+}
+
+static int of_isp1760_remove(struct of_device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(&dev->dev);
+
+ dev_set_drvdata(&dev->dev, NULL);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ return 0;
+}
+
+static struct of_device_id of_isp1760_match[] = {
+ {
+ .compatible = "nxp,usb-isp1760",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_isp1760_match);
+
+static struct of_platform_driver isp1760_of_driver = {
+ .name = "nxp-isp1760",
+ .match_table = of_isp1760_match,
+ .probe = of_isp1760_probe,
+ .remove = of_isp1760_remove,
+};
+#endif
+
+#ifdef CONFIG_USB_ISP1760_PCI
+static u32 nxp_pci_io_base;
+static u32 iolength;
+static u32 pci_mem_phy0;
+static u32 length;
+static u8 *chip_addr;
+static u8 *iobase;
+
+static int __devinit isp1761_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ u8 latency, limit;
+ __u32 reg_data;
+ int retry_count;
+ int length;
+ int status = 1;
+ struct usb_hcd *hcd;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ if (pci_enable_device(dev) < 0)
+ return -ENODEV;
+
+ if (!dev->irq)
+ return -ENODEV;
+
+ /* Grab the PLX PCI mem maped port start address we need */
+ nxp_pci_io_base = pci_resource_start(dev, 0);
+ iolength = pci_resource_len(dev, 0);
+
+ if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
+ printk(KERN_ERR "request region #1\n");
+ return -EBUSY;
+ }
+
+ iobase = ioremap_nocache(nxp_pci_io_base, iolength);
+ if (!iobase) {
+ printk(KERN_ERR "ioremap #1\n");
+ release_mem_region(nxp_pci_io_base, iolength);
+ return -ENOMEM;
+ }
+ /* Grab the PLX PCI shared memory of the ISP 1761 we need */
+ pci_mem_phy0 = pci_resource_start(dev, 3);
+ length = pci_resource_len(dev, 3);
+
+ if (length < 0xffff) {
+ printk(KERN_ERR "memory length for this resource is less than "
+ "required\n");
+ release_mem_region(nxp_pci_io_base, iolength);
+ iounmap(iobase);
+ return -ENOMEM;
+ }
+
+ if (!request_mem_region(pci_mem_phy0, length, "ISP-PCI")) {
+ printk(KERN_ERR "host controller already in use\n");
+ release_mem_region(nxp_pci_io_base, iolength);
+ iounmap(iobase);
+ return -EBUSY;
+ }
+
+ /* bad pci latencies can contribute to overruns */
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+ if (latency) {
+ pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
+ if (limit && limit < latency)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
+ }
+
+ /* Try to check whether we can access Scratch Register of
+ * Host Controller or not. The initial PCI access is retried until
+ * local init for the PCI bridge is completed
+ */
+ retry_count = 20;
+ reg_data = 0;
+ while ((reg_data != 0xFACE) && retry_count) {
+ /*by default host is in 16bit mode, so
+ * io operations at this stage must be 16 bit
+ * */
+ writel(0xface, chip_addr + HC_SCRATCH_REG);
+ udelay(100);
+ reg_data = readl(chip_addr + HC_SCRATCH_REG);
+ retry_count--;
+ }
+
+ /* Host Controller presence is detected by writing to scratch register
+ * and reading back and checking the contents are same or not
+ */
+ if (reg_data != 0xFACE) {
+ err("scratch register mismatch %x", reg_data);
+ goto clean;
+ }
+
+ pci_set_master(dev);
+
+ status = readl(iobase + 0x68);
+ status |= 0x900;
+ writel(status, iobase + 0x68);
+
+ dev->dev.dma_mask = NULL;
+ hcd = isp1760_register(pci_mem_phy0, length, dev->irq,
+ IRQF_SHARED | IRQF_DISABLED, &dev->dev, dev->dev.bus_id);
+ pci_set_drvdata(dev, hcd);
+ if (!hcd)
+ return 0;
+clean:
+ status = -ENODEV;
+ iounmap(iobase);
+ release_mem_region(pci_mem_phy0, length);
+ release_mem_region(nxp_pci_io_base, iolength);
+ return status;
+}
+static void isp1761_pci_remove(struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+
+ hcd = pci_get_drvdata(dev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ pci_disable_device(dev);
+
+ iounmap(iobase);
+ iounmap(chip_addr);
+
+ release_mem_region(nxp_pci_io_base, iolength);
+ release_mem_region(pci_mem_phy0, length);
+}
+
+static void isp1761_pci_shutdown(struct pci_dev *dev)
+{
+ printk(KERN_ERR "ips1761_pci_shutdown\n");
+}
+
+static const struct pci_device_id isp1760_plx [] = { {
+ /* handle any USB 2.0 EHCI controller */
+ PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_OTHER << 8) | (0x06 << 16)), ~0),
+ .driver_data = 0,
+},
+{ /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE(pci, isp1760_plx);
+
+static struct pci_driver isp1761_pci_driver = {
+ .name = "isp1760",
+ .id_table = isp1760_plx,
+ .probe = isp1761_pci_probe,
+ .remove = isp1761_pci_remove,
+ .shutdown = isp1761_pci_shutdown,
+};
+#endif
+
+static int __init isp1760_init(void)
+{
+ int ret;
+
+ init_kmem_once();
+
+#ifdef CONFIG_USB_ISP1760_OF
+ ret = of_register_platform_driver(&isp1760_of_driver);
+ if (ret) {
+ deinit_kmem_cache();
+ return ret;
+ }
+#endif
+#ifdef CONFIG_USB_ISP1760_PCI
+ ret = pci_register_driver(&isp1761_pci_driver);
+ if (ret)
+ goto unreg_of;
+#endif
+ return ret;
+
+#ifdef CONFIG_USB_ISP1760_PCI
+unreg_of:
+#endif
+#ifdef CONFIG_USB_ISP1760_OF
+ of_unregister_platform_driver(&isp1760_of_driver);
+#endif
+ deinit_kmem_cache();
+ return ret;
+}
+module_init(isp1760_init);
+
+static void __exit isp1760_exit(void)
+{
+#ifdef CONFIG_USB_ISP1760_OF
+ of_unregister_platform_driver(&isp1760_of_driver);
+#endif
+#ifdef CONFIG_USB_ISP1760_PCI
+ pci_unregister_driver(&isp1761_pci_driver);
+#endif
+ deinit_kmem_cache();
+}
+module_exit(isp1760_exit);
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 5be3bb3..79a7802 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -613,7 +613,7 @@
static inline int root_port_reset (struct ohci_hcd *ohci, unsigned port)
{
__hc32 __iomem *portstat = &ohci->regs->roothub.portstatus [port];
- u32 temp;
+ u32 temp = 0;
u16 now = ohci_readl(ohci, &ohci->regs->fmnumber);
u16 reset_done = now + PORT_RESET_MSEC;
int limit_1 = DIV_ROUND_UP(PORT_RESET_MSEC, PORT_RESET_HW_MSEC);
@@ -736,14 +736,14 @@
break;
case GetHubStatus:
temp = roothub_status (ohci) & ~(RH_HS_CRWE | RH_HS_DRWE);
- put_unaligned(cpu_to_le32 (temp), (__le32 *) buf);
+ put_unaligned_le32(temp, buf);
break;
case GetPortStatus:
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
temp = roothub_portstatus (ohci, wIndex);
- put_unaligned(cpu_to_le32 (temp), (__le32 *) buf);
+ put_unaligned_le32(temp, buf);
#ifndef OHCI_VERBOSE_DEBUG
if (*(u16*)(buf+2)) /* only if wPortChange is interesting */
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 3fd7a0c..4265752 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1506,15 +1506,7 @@
static void create_debug_file(struct sl811 *sl811)
{
- struct proc_dir_entry *pde;
-
- pde = create_proc_entry(proc_filename, 0, NULL);
- if (pde == NULL)
- return;
-
- pde->proc_fops = &proc_ops;
- pde->data = sl811;
- sl811->pde = pde;
+ sl811->pde = proc_create_data(proc_filename, 0, NULL, &proc_ops, sl811);
}
static void remove_debug_file(struct sl811 *sl811)
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index d3e0d8a..3a7bfe7 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -234,7 +234,7 @@
return 0;
}
-static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
+static int global_suspend_mode_is_broken(struct uhci_hcd *uhci)
{
int port;
const char *sys_info;
@@ -261,27 +261,60 @@
__acquires(uhci->lock)
{
int auto_stop;
- int int_enable, egsm_enable;
+ int int_enable, egsm_enable, wakeup_enable;
struct usb_device *rhdev = uhci_to_hcd(uhci)->self.root_hub;
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
dev_dbg(&rhdev->dev, "%s%s\n", __func__,
(auto_stop ? " (auto-stop)" : ""));
- /* Enable resume-detect interrupts if they work.
- * Then enter Global Suspend mode if _it_ works, still configured.
+ /* Start off by assuming Resume-Detect interrupts and EGSM work
+ * and that remote wakeups should be enabled.
*/
egsm_enable = USBCMD_EGSM;
- uhci->working_RD = 1;
+ uhci->RD_enable = 1;
int_enable = USBINTR_RESUME;
- if (remote_wakeup_is_broken(uhci))
- egsm_enable = 0;
- if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable ||
+ wakeup_enable = 1;
+
+ /* In auto-stop mode wakeups must always be detected, but
+ * Resume-Detect interrupts may be prohibited. (In the absence
+ * of CONFIG_PM, they are always disallowed.)
+ */
+ if (auto_stop) {
+ if (!device_may_wakeup(&rhdev->dev))
+ int_enable = 0;
+
+ /* In bus-suspend mode wakeups may be disabled, but if they are
+ * allowed then so are Resume-Detect interrupts.
+ */
+ } else {
#ifdef CONFIG_PM
- (!auto_stop && !rhdev->do_remote_wakeup) ||
+ if (!rhdev->do_remote_wakeup)
+ wakeup_enable = 0;
#endif
- (auto_stop && !device_may_wakeup(&rhdev->dev)))
- uhci->working_RD = int_enable = 0;
+ }
+
+ /* EGSM causes the root hub to echo a 'K' signal (resume) out any
+ * port which requests a remote wakeup. According to the USB spec,
+ * every hub is supposed to do this. But if we are ignoring
+ * remote-wakeup requests anyway then there's no point to it.
+ * We also shouldn't enable EGSM if it's broken.
+ */
+ if (!wakeup_enable || global_suspend_mode_is_broken(uhci))
+ egsm_enable = 0;
+
+ /* If we're ignoring wakeup events then there's no reason to
+ * enable Resume-Detect interrupts. We also shouldn't enable
+ * them if they are broken or disallowed.
+ *
+ * This logic may lead us to enabling RD but not EGSM. The UHCI
+ * spec foolishly says that RD works only when EGSM is on, but
+ * there's no harm in enabling it anyway -- perhaps some chips
+ * will implement it!
+ */
+ if (!wakeup_enable || resume_detect_interrupts_are_broken(uhci) ||
+ !int_enable)
+ uhci->RD_enable = int_enable = 0;
outw(int_enable, uhci->io_addr + USBINTR);
outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
@@ -308,7 +341,11 @@
uhci->rh_state = new_state;
uhci->is_stopped = UHCI_IS_STOPPED;
- uhci_to_hcd(uhci)->poll_rh = !int_enable;
+
+ /* If interrupts don't work and remote wakeup is enabled then
+ * the suspended root hub needs to be polled.
+ */
+ uhci_to_hcd(uhci)->poll_rh = (!int_enable && wakeup_enable);
uhci_scan_schedule(uhci);
uhci_fsbr_off(uhci);
@@ -344,9 +381,12 @@
* for 20 ms.
*/
if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+ unsigned egsm;
+
+ /* Keep EGSM on if it was set before */
+ egsm = inw(uhci->io_addr + USBCMD) & USBCMD_EGSM;
uhci->rh_state = UHCI_RH_RESUMING;
- outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
- uhci->io_addr + USBCMD);
+ outw(USBCMD_FGR | USBCMD_CF | egsm, uhci->io_addr + USBCMD);
spin_unlock_irq(&uhci->lock);
msleep(20);
spin_lock_irq(&uhci->lock);
@@ -801,8 +841,10 @@
spin_unlock_irq(&uhci->lock);
- if (!uhci->working_RD) {
- /* Suspended root hub needs to be polled */
+ /* If interrupts don't work and remote wakeup is enabled then
+ * the suspended root hub needs to be polled.
+ */
+ if (!uhci->RD_enable && hcd->self.root_hub->do_remote_wakeup) {
hcd->poll_rh = 1;
usb_hcd_poll_rh_status(hcd);
}
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 340d6ed..7d01c56 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -400,8 +400,9 @@
unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */
unsigned int dead:1; /* Controller has died */
- unsigned int working_RD:1; /* Suspended root hub doesn't
- need to be polled */
+ unsigned int RD_enable:1; /* Suspended root hub with
+ Resume-Detect interrupts
+ enabled */
unsigned int is_initialized:1; /* Data structure is usable */
unsigned int fsbr_is_on:1; /* FSBR is turned on */
unsigned int fsbr_is_wanted:1; /* Does any URB want FSBR? */
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index 11580e8..7aafd53 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -148,7 +148,7 @@
/* Structure to hold all of our device specific stuff */
struct ld_usb {
- struct semaphore sem; /* locks this structure */
+ struct mutex mutex; /* locks this structure */
struct usb_interface* intf; /* save off the usb interface pointer */
int open_count; /* number of times this port has been opened */
@@ -319,7 +319,7 @@
return -ENODEV;
/* lock this device */
- if (down_interruptible(&dev->sem))
+ if (mutex_lock_interruptible(&dev->mutex))
return -ERESTARTSYS;
/* allow opening only once */
@@ -358,7 +358,7 @@
file->private_data = dev;
unlock_exit:
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
return retval;
}
@@ -378,7 +378,7 @@
goto exit;
}
- if (down_interruptible(&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -389,7 +389,7 @@
}
if (dev->intf == NULL) {
/* the device was unplugged before the file was released */
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
/* unlock here as ld_usb_delete frees dev */
ld_usb_delete(dev);
goto exit;
@@ -402,7 +402,7 @@
dev->open_count = 0;
unlock_exit:
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
exit:
return retval;
@@ -448,7 +448,7 @@
goto exit;
/* lock this object */
- if (down_interruptible(&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -505,7 +505,7 @@
unlock_exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
exit:
return retval;
@@ -528,7 +528,7 @@
goto exit;
/* lock this object */
- if (down_interruptible(&dev->sem)) {
+ if (mutex_lock_interruptible(&dev->mutex)) {
retval = -ERESTARTSYS;
goto exit;
}
@@ -602,7 +602,7 @@
unlock_exit:
/* unlock the device */
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
exit:
return retval;
@@ -651,7 +651,7 @@
dev_err(&intf->dev, "Out of memory\n");
goto exit;
}
- init_MUTEX(&dev->sem);
+ mutex_init(&dev->mutex);
spin_lock_init(&dev->rbsl);
dev->intf = intf;
init_waitqueue_head(&dev->read_wait);
@@ -765,15 +765,15 @@
/* give back our minor */
usb_deregister_dev(intf, &ld_usb_class);
- down(&dev->sem);
+ mutex_lock(&dev->mutex);
/* if the device is not opened, then we clean up right now */
if (!dev->open_count) {
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
ld_usb_delete(dev);
} else {
dev->intf = NULL;
- up(&dev->sem);
+ mutex_unlock(&dev->mutex);
}
dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index a519838..742be3c 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -79,30 +79,10 @@
/* set up all urbs so they can be used with either bulk or interrupt */
#define INTERRUPT_RATE 1 /* msec/transfer */
-#define xprintk(tdev,level,fmt,args...) \
- dev_printk(level , &(tdev)->intf->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
- xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG DBG
-#else
-#define VDBG(dev,fmt,args...) \
- do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
- xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
- xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
- xprintk(dev , KERN_INFO , fmt , ## args)
+#define ERROR(tdev, fmt, args...) \
+ dev_err(&(tdev)->intf->dev , fmt , ## args)
+#define WARN(tdev, fmt, args...) \
+ dev_warn(&(tdev)->intf->dev , fmt , ## args)
/*-------------------------------------------------------------------------*/
@@ -236,7 +216,7 @@
static unsigned pattern = 0;
module_param (pattern, uint, S_IRUGO);
-// MODULE_PARM_DESC (pattern, "i/o pattern (0 == zeroes)");
+MODULE_PARM_DESC(pattern, "i/o pattern (0 == zeroes)");
static inline void simple_fill_buf (struct urb *urb)
{
@@ -257,7 +237,7 @@
}
}
-static inline int simple_check_buf (struct urb *urb)
+static inline int simple_check_buf(struct usbtest_dev *tdev, struct urb *urb)
{
unsigned i;
u8 expected;
@@ -285,7 +265,7 @@
}
if (*buf == expected)
continue;
- dbg ("buf[%d] = %d (not %d)", i, *buf, expected);
+ ERROR(tdev, "buf[%d] = %d (not %d)\n", i, *buf, expected);
return -EINVAL;
}
return 0;
@@ -299,6 +279,7 @@
}
static int simple_io (
+ struct usbtest_dev *tdev,
struct urb *urb,
int iterations,
int vary,
@@ -324,7 +305,7 @@
retval = urb->status;
urb->dev = udev;
if (retval == 0 && usb_pipein (urb->pipe))
- retval = simple_check_buf (urb);
+ retval = simple_check_buf(tdev, urb);
if (vary) {
int len = urb->transfer_buffer_length;
@@ -341,7 +322,7 @@
urb->transfer_buffer_length = max;
if (expected != retval)
- dev_dbg (&udev->dev,
+ dev_err(&udev->dev,
"%s failed, iterations left %d, status %d (not %d)\n",
label, iterations, retval, expected);
return retval;
@@ -357,7 +338,7 @@
static void free_sglist (struct scatterlist *sg, int nents)
{
unsigned i;
-
+
if (!sg)
return;
for (i = 0; i < nents; i++) {
@@ -415,7 +396,7 @@
}
static int perform_sglist (
- struct usb_device *udev,
+ struct usbtest_dev *tdev,
unsigned iterations,
int pipe,
struct usb_sg_request *req,
@@ -423,6 +404,7 @@
int nents
)
{
+ struct usb_device *udev = testdev_to_usbdev(tdev);
int retval = 0;
while (retval == 0 && iterations-- > 0) {
@@ -431,7 +413,7 @@
? (INTERRUPT_RATE << 3)
: INTERRUPT_RATE,
sg, nents, 0, GFP_KERNEL);
-
+
if (retval)
break;
usb_sg_wait (req);
@@ -446,7 +428,8 @@
// failure if retval is as we expected ...
if (retval)
- dbg ("perform_sglist failed, iterations left %d, status %d",
+ ERROR(tdev, "perform_sglist failed, "
+ "iterations left %d, status %d\n",
iterations, retval);
return retval;
}
@@ -505,28 +488,28 @@
alternate);
}
-static int is_good_config (char *buf, int len)
+static int is_good_config(struct usbtest_dev *tdev, int len)
{
struct usb_config_descriptor *config;
-
+
if (len < sizeof *config)
return 0;
- config = (struct usb_config_descriptor *) buf;
+ config = (struct usb_config_descriptor *) tdev->buf;
switch (config->bDescriptorType) {
case USB_DT_CONFIG:
case USB_DT_OTHER_SPEED_CONFIG:
if (config->bLength != 9) {
- dbg ("bogus config descriptor length");
+ ERROR(tdev, "bogus config descriptor length\n");
return 0;
}
/* this bit 'must be 1' but often isn't */
if (!realworld && !(config->bmAttributes & 0x80)) {
- dbg ("high bit of config attributes not set");
+ ERROR(tdev, "high bit of config attributes not set\n");
return 0;
}
if (config->bmAttributes & 0x1f) { /* reserved == 0 */
- dbg ("reserved config bits set");
+ ERROR(tdev, "reserved config bits set\n");
return 0;
}
break;
@@ -538,7 +521,7 @@
return 1;
if (le16_to_cpu(config->wTotalLength) >= TBUF_SIZE) /* max partial read */
return 1;
- dbg ("bogus config descriptor read size");
+ ERROR(tdev, "bogus config descriptor read size\n");
return 0;
}
@@ -571,7 +554,7 @@
/* 9.2.3 constrains the range here */
alt = iface->altsetting [i].desc.bAlternateSetting;
if (alt < 0 || alt >= iface->num_altsetting) {
- dev_dbg (&iface->dev,
+ dev_err(&iface->dev,
"invalid alt [%d].bAltSetting = %d\n",
i, alt);
}
@@ -583,7 +566,7 @@
/* [9.4.10] set_interface */
retval = set_altsetting (dev, alt);
if (retval) {
- dev_dbg (&iface->dev, "can't set_interface = %d, %d\n",
+ dev_err(&iface->dev, "can't set_interface = %d, %d\n",
alt, retval);
return retval;
}
@@ -591,7 +574,7 @@
/* [9.4.4] get_interface always works */
retval = get_altsetting (dev);
if (retval != alt) {
- dev_dbg (&iface->dev, "get alt should be %d, was %d\n",
+ dev_err(&iface->dev, "get alt should be %d, was %d\n",
alt, retval);
return (retval < 0) ? retval : -EDOM;
}
@@ -611,7 +594,7 @@
USB_DIR_IN | USB_RECIP_DEVICE,
0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
if (retval != 1 || dev->buf [0] != expected) {
- dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
+ dev_err(&iface->dev, "get config --> %d %d (1 %d)\n",
retval, dev->buf[0], expected);
return (retval < 0) ? retval : -EDOM;
}
@@ -621,7 +604,7 @@
retval = usb_get_descriptor (udev, USB_DT_DEVICE, 0,
dev->buf, sizeof udev->descriptor);
if (retval != sizeof udev->descriptor) {
- dev_dbg (&iface->dev, "dev descriptor --> %d\n", retval);
+ dev_err(&iface->dev, "dev descriptor --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
}
@@ -629,8 +612,8 @@
for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
retval = usb_get_descriptor (udev, USB_DT_CONFIG, i,
dev->buf, TBUF_SIZE);
- if (!is_good_config (dev->buf, retval)) {
- dev_dbg (&iface->dev,
+ if (!is_good_config(dev, retval)) {
+ dev_err(&iface->dev,
"config [%d] descriptor --> %d\n",
i, retval);
return (retval < 0) ? retval : -EDOM;
@@ -650,14 +633,14 @@
sizeof (struct usb_qualifier_descriptor));
if (retval == -EPIPE) {
if (udev->speed == USB_SPEED_HIGH) {
- dev_dbg (&iface->dev,
+ dev_err(&iface->dev,
"hs dev qualifier --> %d\n",
retval);
return (retval < 0) ? retval : -EDOM;
}
/* usb2.0 but not high-speed capable; fine */
} else if (retval != sizeof (struct usb_qualifier_descriptor)) {
- dev_dbg (&iface->dev, "dev qualifier --> %d\n", retval);
+ dev_err(&iface->dev, "dev qualifier --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
} else
d = (struct usb_qualifier_descriptor *) dev->buf;
@@ -669,8 +652,8 @@
retval = usb_get_descriptor (udev,
USB_DT_OTHER_SPEED_CONFIG, i,
dev->buf, TBUF_SIZE);
- if (!is_good_config (dev->buf, retval)) {
- dev_dbg (&iface->dev,
+ if (!is_good_config(dev, retval)) {
+ dev_err(&iface->dev,
"other speed config --> %d\n",
retval);
return (retval < 0) ? retval : -EDOM;
@@ -683,7 +666,7 @@
/* [9.4.5] get_status always works */
retval = usb_get_status (udev, USB_RECIP_DEVICE, 0, dev->buf);
if (retval != 2) {
- dev_dbg (&iface->dev, "get dev status --> %d\n", retval);
+ dev_err(&iface->dev, "get dev status --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
}
@@ -693,11 +676,11 @@
retval = usb_get_status (udev, USB_RECIP_INTERFACE,
iface->altsetting [0].desc.bInterfaceNumber, dev->buf);
if (retval != 2) {
- dev_dbg (&iface->dev, "get interface status --> %d\n", retval);
+ dev_err(&iface->dev, "get interface status --> %d\n", retval);
return (retval < 0) ? retval : -EDOM;
}
// FIXME get status for each endpoint in the interface
-
+
return 0;
}
@@ -752,8 +735,9 @@
*/
if (subcase->number > 0) {
if ((subcase->number - ctx->last) != 1) {
- dbg ("subcase %d completed out of order, last %d",
- subcase->number, ctx->last);
+ ERROR(ctx->dev,
+ "subcase %d completed out of order, last %d\n",
+ subcase->number, ctx->last);
status = -EDOM;
ctx->last = subcase->number;
goto error;
@@ -777,7 +761,7 @@
else if (subcase->number == 12 && status == -EPIPE)
status = 0;
else
- dbg ("subtest %d error, status %d",
+ ERROR(ctx->dev, "subtest %d error, status %d\n",
subcase->number, status);
}
@@ -788,9 +772,12 @@
int i;
ctx->status = status;
- info ("control queue %02x.%02x, err %d, %d left",
+ ERROR(ctx->dev, "control queue %02x.%02x, err %d, "
+ "%d left, subcase %d, len %d/%d\n",
reqp->bRequestType, reqp->bRequest,
- status, ctx->count);
+ status, ctx->count, subcase->number,
+ urb->actual_length,
+ urb->transfer_buffer_length);
/* FIXME this "unlink everything" exit route should
* be a separate test case.
@@ -799,7 +786,8 @@
/* unlink whatever's still pending */
for (i = 1; i < ctx->param->sglen; i++) {
struct urb *u = ctx->urb [
- (i + subcase->number) % ctx->param->sglen];
+ (i + subcase->number)
+ % ctx->param->sglen];
if (u == urb || !u->dev)
continue;
@@ -812,7 +800,8 @@
case -EIDRM:
continue;
default:
- dbg ("urb unlink --> %d", status);
+ ERROR(ctx->dev, "urb unlink --> %d\n",
+ status);
}
}
status = ctx->status;
@@ -822,14 +811,15 @@
/* resubmit if we need to, else mark this as done */
if ((status == 0) && (ctx->pending < ctx->count)) {
if ((status = usb_submit_urb (urb, GFP_ATOMIC)) != 0) {
- dbg ("can't resubmit ctrl %02x.%02x, err %d",
+ ERROR(ctx->dev,
+ "can't resubmit ctrl %02x.%02x, err %d\n",
reqp->bRequestType, reqp->bRequest, status);
urb->dev = NULL;
} else
ctx->pending++;
} else
urb->dev = NULL;
-
+
/* signal completion when nothing's queued */
if (ctx->pending == 0)
complete (&ctx->complete);
@@ -918,11 +908,11 @@
req.wValue = cpu_to_le16 (USB_DT_INTERFACE << 8);
// interface == 0
len = sizeof (struct usb_interface_descriptor);
- expected = EPIPE;
+ expected = -EPIPE;
break;
// NOTE: two consecutive stalls in the queue here.
// that tests fault recovery a bit more aggressively.
- case 8: // clear endpoint halt (USUALLY STALLS)
+ case 8: // clear endpoint halt (MAY STALL)
req.bRequest = USB_REQ_CLEAR_FEATURE;
req.bRequestType = USB_RECIP_ENDPOINT;
// wValue 0 == ep halt
@@ -965,7 +955,7 @@
break;
case 14: // short read; try to fill the last packet
req.wValue = cpu_to_le16 ((USB_DT_DEVICE << 8) | 0);
- // device descriptor size == 18 bytes
+ /* device descriptor size == 18 bytes */
len = udev->descriptor.bMaxPacketSize0;
switch (len) {
case 8: len = 24; break;
@@ -974,7 +964,7 @@
expected = -EREMOTEIO;
break;
default:
- err ("bogus number of ctrl queue testcases!");
+ ERROR(dev, "bogus number of ctrl queue testcases!\n");
context.status = -EINVAL;
goto cleanup;
}
@@ -1003,7 +993,7 @@
for (i = 0; i < param->sglen; i++) {
context.status = usb_submit_urb (urb [i], GFP_ATOMIC);
if (context.status != 0) {
- dbg ("can't submit urb[%d], status %d",
+ ERROR(dev, "can't submit urb[%d], status %d\n",
i, context.status);
context.count = context.pending;
break;
@@ -1070,7 +1060,7 @@
* due to errors, or is just NAKing requests.
*/
if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) {
- dev_dbg (&dev->intf->dev, "submit fail %d\n", retval);
+ dev_err(&dev->intf->dev, "submit fail %d\n", retval);
return retval;
}
@@ -1087,13 +1077,13 @@
* "normal" drivers would prevent resubmission, but
* since we're testing unlink paths, we can't.
*/
- dev_dbg (&dev->intf->dev, "unlink retry\n");
+ ERROR(dev, "unlink retry\n");
goto retry;
}
} else
usb_kill_urb (urb);
if (!(retval == 0 || retval == -EINPROGRESS)) {
- dev_dbg (&dev->intf->dev, "unlink fail %d\n", retval);
+ dev_err(&dev->intf->dev, "unlink fail %d\n", retval);
return retval;
}
@@ -1121,7 +1111,7 @@
/*-------------------------------------------------------------------------*/
-static int verify_not_halted (int ep, struct urb *urb)
+static int verify_not_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
u16 status;
@@ -1129,20 +1119,21 @@
/* shouldn't look or act halted */
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
if (retval < 0) {
- dbg ("ep %02x couldn't get no-halt status, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't get no-halt status, %d\n",
+ ep, retval);
return retval;
}
if (status != 0) {
- dbg ("ep %02x bogus status: %04x != 0", ep, status);
+ ERROR(tdev, "ep %02x bogus status: %04x != 0\n", ep, status);
return -EINVAL;
}
- retval = simple_io (urb, 1, 0, 0, __func__);
+ retval = simple_io(tdev, urb, 1, 0, 0, __func__);
if (retval != 0)
return -EINVAL;
return 0;
}
-static int verify_halted (int ep, struct urb *urb)
+static int verify_halted(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
u16 status;
@@ -1150,29 +1141,30 @@
/* should look and act halted */
retval = usb_get_status (urb->dev, USB_RECIP_ENDPOINT, ep, &status);
if (retval < 0) {
- dbg ("ep %02x couldn't get halt status, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't get halt status, %d\n",
+ ep, retval);
return retval;
}
le16_to_cpus(&status);
if (status != 1) {
- dbg ("ep %02x bogus status: %04x != 1", ep, status);
+ ERROR(tdev, "ep %02x bogus status: %04x != 1\n", ep, status);
return -EINVAL;
}
- retval = simple_io (urb, 1, 0, -EPIPE, __func__);
+ retval = simple_io(tdev, urb, 1, 0, -EPIPE, __func__);
if (retval != -EPIPE)
return -EINVAL;
- retval = simple_io (urb, 1, 0, -EPIPE, "verify_still_halted");
+ retval = simple_io(tdev, urb, 1, 0, -EPIPE, "verify_still_halted");
if (retval != -EPIPE)
return -EINVAL;
return 0;
}
-static int test_halt (int ep, struct urb *urb)
+static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb)
{
int retval;
/* shouldn't look or act halted now */
- retval = verify_not_halted (ep, urb);
+ retval = verify_not_halted(tdev, ep, urb);
if (retval < 0)
return retval;
@@ -1182,20 +1174,20 @@
USB_ENDPOINT_HALT, ep,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval < 0) {
- dbg ("ep %02x couldn't set halt, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't set halt, %d\n", ep, retval);
return retval;
}
- retval = verify_halted (ep, urb);
+ retval = verify_halted(tdev, ep, urb);
if (retval < 0)
return retval;
/* clear halt (tests API + protocol), verify it worked */
retval = usb_clear_halt (urb->dev, urb->pipe);
if (retval < 0) {
- dbg ("ep %02x couldn't clear halt, %d", ep, retval);
+ ERROR(tdev, "ep %02x couldn't clear halt, %d\n", ep, retval);
return retval;
}
- retval = verify_not_halted (ep, urb);
+ retval = verify_not_halted(tdev, ep, urb);
if (retval < 0)
return retval;
@@ -1217,7 +1209,7 @@
if (dev->in_pipe) {
ep = usb_pipeendpoint (dev->in_pipe) | USB_DIR_IN;
urb->pipe = dev->in_pipe;
- retval = test_halt (ep, urb);
+ retval = test_halt(dev, ep, urb);
if (retval < 0)
goto done;
}
@@ -1225,7 +1217,7 @@
if (dev->out_pipe) {
ep = usb_pipeendpoint (dev->out_pipe);
urb->pipe = dev->out_pipe;
- retval = test_halt (ep, urb);
+ retval = test_halt(dev, ep, urb);
}
done:
simple_free_urb (urb);
@@ -1275,7 +1267,7 @@
if (retval != len) {
what = "write";
if (retval >= 0) {
- INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
+ ERROR(dev, "ctrl_out, wlen %d (expected %d)\n",
retval, len);
retval = -EBADMSG;
}
@@ -1289,7 +1281,7 @@
if (retval != len) {
what = "read";
if (retval >= 0) {
- INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
+ ERROR(dev, "ctrl_out, rlen %d (expected %d)\n",
retval, len);
retval = -EBADMSG;
}
@@ -1299,7 +1291,7 @@
/* fail if we can't verify */
for (j = 0; j < len; j++) {
if (buf [j] != (u8) (i + j)) {
- INFO (dev, "ctrl_out, byte %d is %d not %d\n",
+ ERROR(dev, "ctrl_out, byte %d is %d not %d\n",
j, buf [j], (u8) i + j);
retval = -EBADMSG;
break;
@@ -1321,7 +1313,7 @@
}
if (retval < 0)
- INFO (dev, "ctrl_out %s failed, code %d, count %d\n",
+ ERROR (dev, "ctrl_out %s failed, code %d, count %d\n",
what, retval, i);
kfree (buf);
@@ -1366,7 +1358,7 @@
case 0:
goto done;
default:
- dev_dbg (&ctx->dev->intf->dev,
+ dev_err(&ctx->dev->intf->dev,
"iso resubmit err %d\n",
status);
/* FALLTHROUGH */
@@ -1381,7 +1373,7 @@
ctx->pending--;
if (ctx->pending == 0) {
if (ctx->errors)
- dev_dbg (&ctx->dev->intf->dev,
+ dev_err(&ctx->dev->intf->dev,
"iso test, %lu errors out of %lu\n",
ctx->errors, ctx->packet_count);
complete (&ctx->done);
@@ -1458,7 +1450,7 @@
memset (urbs, 0, sizeof urbs);
udev = testdev_to_usbdev (dev);
- dev_dbg (&dev->intf->dev,
+ dev_info(&dev->intf->dev,
"... iso period %d %sframes, wMaxPacket %04x\n",
1 << (desc->bInterval - 1),
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
@@ -1475,7 +1467,7 @@
urbs [i]->context = &context;
}
packets *= param->iterations;
- dev_dbg (&dev->intf->dev,
+ dev_info(&dev->intf->dev,
"... total %lu msec (%lu packets)\n",
(packets * (1 << (desc->bInterval - 1)))
/ ((udev->speed == USB_SPEED_HIGH) ? 8 : 1),
@@ -1537,6 +1529,13 @@
* except indirectly by consuming USB bandwidth and CPU resources for test
* threads and request completion. But the only way to know that for sure
* is to test when HC queues are in use by many devices.
+ *
+ * WARNING: Because usbfs grabs udev->dev.sem before calling this ioctl(),
+ * it locks out usbcore in certain code paths. Notably, if you disconnect
+ * the device-under-test, khubd will wait block forever waiting for the
+ * ioctl to complete ... so that usb_disconnect() can abort the pending
+ * urbs and then call usbtest_disconnect(). To abort a test, you're best
+ * off just killing the userspace task and waiting for it to exit.
*/
static int
@@ -1575,7 +1574,7 @@
* altsettings; force a default so most tests don't need to check.
*/
if (dev->info->alt >= 0) {
- int res;
+ int res;
if (intf->altsetting->desc.bInterfaceNumber) {
mutex_unlock(&dev->lock);
@@ -1604,7 +1603,7 @@
switch (param->test_num) {
case 0:
- dev_dbg (&intf->dev, "TEST 0: NOP\n");
+ dev_info(&intf->dev, "TEST 0: NOP\n");
retval = 0;
break;
@@ -1612,7 +1611,7 @@
case 1:
if (dev->out_pipe == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 1: write %d bytes %u times\n",
param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
@@ -1621,13 +1620,13 @@
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = simple_io (urb, param->iterations, 0, 0, "test1");
+ retval = simple_io(dev, urb, param->iterations, 0, 0, "test1");
simple_free_urb (urb);
break;
case 2:
if (dev->in_pipe == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 2: read %d bytes %u times\n",
param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
@@ -1636,13 +1635,13 @@
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = simple_io (urb, param->iterations, 0, 0, "test2");
+ retval = simple_io(dev, urb, param->iterations, 0, 0, "test2");
simple_free_urb (urb);
break;
case 3:
if (dev->out_pipe == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 3: write/%d 0..%d bytes %u times\n",
param->vary, param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->out_pipe, param->length);
@@ -1651,14 +1650,14 @@
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = simple_io (urb, param->iterations, param->vary,
+ retval = simple_io(dev, urb, param->iterations, param->vary,
0, "test3");
simple_free_urb (urb);
break;
case 4:
if (dev->in_pipe == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 4: read/%d 0..%d bytes %u times\n",
param->vary, param->length, param->iterations);
urb = simple_alloc_urb (udev, dev->in_pipe, param->length);
@@ -1667,7 +1666,7 @@
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = simple_io (urb, param->iterations, param->vary,
+ retval = simple_io(dev, urb, param->iterations, param->vary,
0, "test4");
simple_free_urb (urb);
break;
@@ -1676,7 +1675,7 @@
case 5:
if (dev->out_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 5: write %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1686,7 +1685,7 @@
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = perform_sglist (udev, param->iterations, dev->out_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->out_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
@@ -1694,7 +1693,7 @@
case 6:
if (dev->in_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 6: read %d sglists %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1704,14 +1703,14 @@
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = perform_sglist (udev, param->iterations, dev->in_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->in_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
case 7:
if (dev->out_pipe == 0 || param->sglen == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 7: write/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length);
@@ -1721,14 +1720,14 @@
break;
}
// FIRMWARE: bulk sink (maybe accepts short writes)
- retval = perform_sglist (udev, param->iterations, dev->out_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->out_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
case 8:
if (dev->in_pipe == 0 || param->sglen == 0 || param->vary == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 8: read/%d %d sglists %d entries 0..%d bytes\n",
param->vary, param->iterations,
param->sglen, param->length);
@@ -1738,7 +1737,7 @@
break;
}
// FIRMWARE: bulk source (maybe generates short writes)
- retval = perform_sglist (udev, param->iterations, dev->in_pipe,
+ retval = perform_sglist(dev, param->iterations, dev->in_pipe,
&req, sg, param->sglen);
free_sglist (sg, param->sglen);
break;
@@ -1746,13 +1745,14 @@
/* non-queued sanity tests for control (chapter 9 subset) */
case 9:
retval = 0;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 9: ch9 (subset) control tests, %d times\n",
param->iterations);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = ch9_postconfig (dev);
if (retval)
- dbg ("ch9 subset failed, iterations left %d", i);
+ dev_err(&intf->dev, "ch9 subset failed, "
+ "iterations left %d\n", i);
break;
/* queued control messaging */
@@ -1760,7 +1760,7 @@
if (param->sglen == 0)
break;
retval = 0;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 10: queue %d control calls, %d times\n",
param->sglen,
param->iterations);
@@ -1772,26 +1772,26 @@
if (dev->in_pipe == 0 || !param->length)
break;
retval = 0;
- dev_dbg (&intf->dev, "TEST 11: unlink %d reads of %d\n",
+ dev_info(&intf->dev, "TEST 11: unlink %d reads of %d\n",
param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->in_pipe,
param->length);
if (retval)
- dev_dbg (&intf->dev, "unlink reads failed %d, "
+ dev_err(&intf->dev, "unlink reads failed %d, "
"iterations left %d\n", retval, i);
break;
case 12:
if (dev->out_pipe == 0 || !param->length)
break;
retval = 0;
- dev_dbg (&intf->dev, "TEST 12: unlink %d writes of %d\n",
+ dev_info(&intf->dev, "TEST 12: unlink %d writes of %d\n",
param->iterations, param->length);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = unlink_simple (dev, dev->out_pipe,
param->length);
if (retval)
- dev_dbg (&intf->dev, "unlink writes failed %d, "
+ dev_err(&intf->dev, "unlink writes failed %d, "
"iterations left %d\n", retval, i);
break;
@@ -1800,24 +1800,24 @@
if (dev->out_pipe == 0 && dev->in_pipe == 0)
break;
retval = 0;
- dev_dbg (&intf->dev, "TEST 13: set/clear %d halts\n",
+ dev_info(&intf->dev, "TEST 13: set/clear %d halts\n",
param->iterations);
for (i = param->iterations; retval == 0 && i--; /* NOP */)
retval = halt_simple (dev);
-
+
if (retval)
- DBG (dev, "halts failed, iterations left %d\n", i);
+ ERROR(dev, "halts failed, iterations left %d\n", i);
break;
/* control write tests */
case 14:
if (!dev->info->ctrl_out)
break;
- dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
+ dev_info(&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
param->iterations,
realworld ? 1 : 0, param->length,
param->vary);
- retval = ctrl_out (dev, param->iterations,
+ retval = ctrl_out(dev, param->iterations,
param->length, param->vary);
break;
@@ -1825,7 +1825,7 @@
case 15:
if (dev->out_iso_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 15: write %d iso, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1838,7 +1838,7 @@
case 16:
if (dev->in_iso_pipe == 0 || param->sglen == 0)
break;
- dev_dbg (&intf->dev,
+ dev_info(&intf->dev,
"TEST 16: read %d iso, %d entries of %d bytes\n",
param->iterations,
param->sglen, param->length);
@@ -1898,7 +1898,8 @@
return -ENODEV;
if (product && le16_to_cpu(udev->descriptor.idProduct) != (u16)product)
return -ENODEV;
- dbg ("matched module params, vend=0x%04x prod=0x%04x",
+ dev_info(&intf->dev, "matched module params, "
+ "vend=0x%04x prod=0x%04x\n",
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct));
}
@@ -1940,7 +1941,8 @@
status = get_endpoints (dev, intf);
if (status < 0) {
- dbg ("couldn't get endpoints, %d\n", status);
+ WARN(dev, "couldn't get endpoints, %d\n",
+ status);
return status;
}
/* may find bulk or ISO pipes */
@@ -2082,21 +2084,9 @@
};
#endif
-// FIXME remove this
-static struct usbtest_info hact_info = {
- .name = "FX2/hact",
- //.ep_in = 6,
- .ep_out = 2,
- .alt = -1,
-};
-
static struct usb_device_id id_table [] = {
- { USB_DEVICE (0x0547, 0x1002),
- .driver_info = (unsigned long) &hact_info,
- },
-
/*-------------------------------------------------------------*/
/* EZ-USB devices which download firmware to replace (or in our
@@ -2185,7 +2175,7 @@
{
#ifdef GENERIC
if (vendor)
- dbg ("params: vend=0x%04x prod=0x%04x", vendor, product);
+ pr_debug("params: vend=0x%04x prod=0x%04x\n", vendor, product);
#endif
return usb_register (&usbtest_driver);
}
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 9b1bb34..db6f97a 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -147,7 +147,7 @@
*/
static int serial_buf_data_avail(struct circ_buf *cb)
{
- return CIRC_CNT(cb->head,cb->tail,AIRCABLE_BUF_SIZE);
+ return CIRC_CNT(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
}
/*
@@ -171,7 +171,7 @@
cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1);
buf += c;
count -= c;
- ret= c;
+ ret = c;
}
return ret;
}
@@ -197,7 +197,7 @@
cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
buf += c;
count -= c;
- ret= c;
+ ret = c;
}
return ret;
}
@@ -208,7 +208,7 @@
{
int count, result;
struct aircable_private *priv = usb_get_serial_port_data(port);
- unsigned char* buf;
+ unsigned char *buf;
__le16 *dbuf;
dbg("%s - port %d", __func__, port->number);
if (port->write_urb_busy)
@@ -229,7 +229,8 @@
buf[1] = TX_HEADER_1;
dbuf = (__le16 *)&buf[2];
*dbuf = cpu_to_le16((u16)count);
- serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
+ serial_buf_get(priv->tx_buf, buf + HCI_HEADER_LENGTH,
+ MAX_HCI_FRAMESIZE);
memcpy(port->write_urb->transfer_buffer, buf,
count + HCI_HEADER_LENGTH);
@@ -261,7 +262,7 @@
struct tty_struct *tty;
unsigned char *data;
int count;
- if (priv->rx_flags & THROTTLED){
+ if (priv->rx_flags & THROTTLED) {
if (priv->rx_flags & ACTUALLY_THROTTLED)
schedule_work(&priv->rx_work);
return;
@@ -282,10 +283,10 @@
count = min(64, serial_buf_data_avail(priv->rx_buf));
if (count <= 0)
- return; //We have finished sending everything.
+ return; /* We have finished sending everything. */
tty_prepare_flip_string(tty, &data, count);
- if (!data){
+ if (!data) {
err("%s- kzalloc(%d) failed.", __func__, count);
return;
}
@@ -304,9 +305,10 @@
static int aircable_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
- struct usb_host_interface *iface_desc = serial->interface->cur_altsetting;
+ struct usb_host_interface *iface_desc = serial->interface->
+ cur_altsetting;
struct usb_endpoint_descriptor *endpoint;
- int num_bulk_out=0;
+ int num_bulk_out = 0;
int i;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
@@ -325,13 +327,13 @@
return 0;
}
-static int aircable_attach (struct usb_serial *serial)
+static int aircable_attach(struct usb_serial *serial)
{
struct usb_serial_port *port = serial->port[0];
struct aircable_private *priv;
priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
- if (!priv){
+ if (!priv) {
err("%s- kmalloc(%Zd) failed.", __func__,
sizeof(struct aircable_private));
return -ENOMEM;
@@ -392,7 +394,7 @@
usb_serial_debug_data(debug, &port->dev, __func__, count, source);
- if (!count){
+ if (!count) {
dbg("%s - write request of 0 bytes", __func__);
return count;
}
@@ -418,31 +420,31 @@
/* This has been taken from cypress_m8.c cypress_write_int_callback */
switch (status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, status);
- port->write_urb_busy = 0;
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d",
+ __func__, status);
+ port->write_urb_busy = 0;
+ return;
+ default:
+ /* error in the urb, so we have to resubmit it */
+ dbg("%s - Overflow in write", __func__);
+ dbg("%s - nonzero write bulk status received: %d",
+ __func__, status);
+ port->write_urb->transfer_buffer_length = 1;
+ port->write_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting write urb, error %d\n",
+ __func__, result);
+ else
return;
- default:
- /* error in the urb, so we have to resubmit it */
- dbg("%s - Overflow in write", __func__);
- dbg("%s - nonzero write bulk status received: %d",
- __func__, status);
- port->write_urb->transfer_buffer_length = 1;
- port->write_urb->dev = port->serial->dev;
- result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (result)
- dev_err(&urb->dev->dev,
- "%s - failed resubmitting write urb, error %d\n",
- __func__, result);
- else
- return;
}
port->write_urb_busy = 0;
@@ -472,11 +474,11 @@
dbg("%s - caught -EPROTO, resubmitting the urb",
__func__);
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
- usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- aircable_read_bulk_callback, port);
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ aircable_read_bulk_callback, port);
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
@@ -490,7 +492,7 @@
}
usb_serial_debug_data(debug, &port->dev, __func__,
- urb->actual_length,urb->transfer_buffer);
+ urb->actual_length, urb->transfer_buffer);
tty = port->tty;
if (tty && urb->actual_length) {
@@ -507,9 +509,9 @@
no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
- no_packages+=1;
+ no_packages++;
- for (i = 0; i < no_packages ;i++) {
+ for (i = 0; i < no_packages; i++) {
if (remaining > (HCI_COMPLETE_FRAME))
package_length = HCI_COMPLETE_FRAME;
else
@@ -529,7 +531,7 @@
if (port->open_count) {
usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev,
- port->bulk_in_endpointAddress),
+ port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer,
port->read_urb->transfer_buffer_length,
aircable_read_bulk_callback, port);
@@ -602,7 +604,7 @@
.unthrottle = aircable_unthrottle,
};
-static int __init aircable_init (void)
+static int __init aircable_init(void)
{
int retval;
retval = usb_serial_register(&aircable_device);
@@ -619,7 +621,7 @@
return retval;
}
-static void __exit aircable_exit (void)
+static void __exit aircable_exit(void)
{
usb_deregister(&aircable_driver);
usb_serial_deregister(&aircable_device);
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 725b6b9..0798c14 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -68,8 +68,9 @@
val |= 0x02;
return usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev, 0),
- 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+ usb_rcvctrlpipe(serial->dev, 0),
+ 0x22, 0x21, val, 0, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
}
return 0;
@@ -90,17 +91,19 @@
__func__, status);
return;
}
- usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __func__,
+ urb->actual_length, data);
tty = port->tty;
if (tty && urb->actual_length) {
- tty_insert_flip_string (tty, data, urb->actual_length);
- tty_flip_buffer_push (tty);
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_flip_buffer_push(tty);
}
- result = usb_submit_urb (urb, GFP_ATOMIC);
+ result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
__func__, result);
return;
}
@@ -115,7 +118,7 @@
dbg("%s - port %d", __func__, port->number);
/* free up the transfer buffer, as usb_free_urb() does not do this */
- kfree (urb->transfer_buffer);
+ kfree(urb->transfer_buffer);
if (status)
dbg("%s - nonzero write bulk status received: %d",
@@ -171,7 +174,7 @@
}
usb_fill_bulk_urb(urb, serial->dev,
usb_rcvbulkpipe(serial->dev,
- port->bulk_out_endpointAddress),
+ port->bulk_out_endpointAddress),
buffer, buffer_size,
airprime_read_bulk_callback, port);
result = usb_submit_urb(urb, GFP_KERNEL);
@@ -183,7 +186,8 @@
__func__, i, port->number, result);
goto errout;
}
- /* remember this urb so we can kill it when the port is closed */
+ /* remember this urb so we can kill it when the
+ port is closed */
priv->read_urbp[i] = urb;
}
@@ -192,22 +196,22 @@
goto out;
errout:
- /* some error happened, cancel any submitted urbs and clean up anything that
- got allocated successfully */
+ /* some error happened, cancel any submitted urbs and clean up
+ anything that got allocated successfully */
while (i-- != 0) {
urb = priv->read_urbp[i];
buffer = urb->transfer_buffer;
- usb_kill_urb (urb);
- usb_free_urb (urb);
- kfree (buffer);
+ usb_kill_urb(urb);
+ usb_free_urb(urb);
+ kfree(buffer);
}
out:
return result;
}
-static void airprime_close(struct usb_serial_port *port, struct file * filp)
+static void airprime_close(struct usb_serial_port *port, struct file *filp)
{
struct airprime_private *priv = usb_get_serial_port_data(port);
int i;
@@ -220,16 +224,16 @@
mutex_lock(&port->serial->disc_mutex);
if (!port->serial->disconnected)
airprime_send_setup(port);
- mutex_lock(&port->serial->disc_mutex);
+ mutex_unlock(&port->serial->disc_mutex);
for (i = 0; i < NUM_READ_URBS; ++i) {
- usb_kill_urb (priv->read_urbp[i]);
- kfree (priv->read_urbp[i]->transfer_buffer);
- usb_free_urb (priv->read_urbp[i]);
+ usb_kill_urb(priv->read_urbp[i]);
+ kfree(priv->read_urbp[i]->transfer_buffer);
+ usb_free_urb(priv->read_urbp[i]);
}
/* free up private structure */
- kfree (priv);
+ kfree(priv);
usb_set_serial_port_data(port, NULL);
}
@@ -259,10 +263,10 @@
urb = usb_alloc_urb(0, GFP_ATOMIC);
if (!urb) {
dev_err(&port->dev, "no more free urbs\n");
- kfree (buffer);
+ kfree(buffer);
return -ENOMEM;
}
- memcpy (buffer, buf, count);
+ memcpy(buffer, buf, count);
usb_serial_debug_data(debug, &port->dev, __func__, count, buffer);
@@ -279,7 +283,7 @@
"%s - usb_submit_urb(write bulk) failed with status = %d\n",
__func__, status);
count = status;
- kfree (buffer);
+ kfree(buffer);
} else {
spin_lock_irqsave(&priv->lock, flags);
++priv->outstanding_urbs;
@@ -287,7 +291,7 @@
}
/* we are done with this urb, so let the host driver
* really free it when it is finished with it */
- usb_free_urb (urb);
+ usb_free_urb(urb);
return count;
}
@@ -315,8 +319,10 @@
{
int retval;
- airprime_device.num_ports =
- (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
+ airprime_device.num_ports = endpoints;
+ if (endpoints < 0 || endpoints >= MAX_BULK_EPS)
+ airprime_device.num_ports = NUM_BULK_EPS;
+
retval = usb_serial_register(&airprime_device);
if (retval)
return retval;
@@ -341,6 +347,7 @@
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled");
module_param(buffer_size, int, 0);
-MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
+MODULE_PARM_DESC(buffer_size,
+ "Size of the transfer buffers in bytes (default 4096)");
module_param(endpoints, int, 0);
MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 599ab2e..77895c8 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -24,7 +24,7 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
#include <linux/serial.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
static int debug;
@@ -246,29 +246,29 @@
baud = tty_get_baud_rate(port->tty);
switch (baud) {
- case 75:
- case 150:
- case 300:
- case 600:
- case 1200:
- case 1800:
- case 2400:
- case 4800:
- case 9600:
- case 19200:
- case 38400:
- case 57600:
- case 115200:
- case 230400:
- case 460800:
- /* Report the resulting rate back to the caller */
- tty_encode_baud_rate(port->tty, baud, baud);
- break;
- /* set 9600 as default (if given baudrate is invalid for example) */
- default:
- tty_encode_baud_rate(port->tty, 9600, 9600);
- case 0:
- baud = 9600;
+ case 75:
+ case 150:
+ case 300:
+ case 600:
+ case 1200:
+ case 1800:
+ case 2400:
+ case 4800:
+ case 9600:
+ case 19200:
+ case 38400:
+ case 57600:
+ case 115200:
+ case 230400:
+ case 460800:
+ /* Report the resulting rate back to the caller */
+ tty_encode_baud_rate(port->tty, baud, baud);
+ break;
+ /* set 9600 as default (if given baudrate is invalid for example) */
+ default:
+ tty_encode_baud_rate(port->tty, 9600, 9600);
+ case 0:
+ baud = 9600;
}
/*
@@ -380,19 +380,19 @@
switch (cmd) {
case TIOCGSERIAL:
/* XXX: Some of these values are probably wrong. */
- memset(&serstruct, 0, sizeof (serstruct));
+ memset(&serstruct, 0, sizeof(serstruct));
serstruct.type = PORT_16654;
serstruct.line = port->serial->minor;
serstruct.port = port->number;
serstruct.custom_divisor = 0;
serstruct.baud_base = 460800;
- if (copy_to_user(user_arg, &serstruct, sizeof (serstruct)))
+ if (copy_to_user(user_arg, &serstruct, sizeof(serstruct)))
return -EFAULT;
return 0;
case TIOCSSERIAL:
- if (copy_from_user(&serstruct, user_arg, sizeof (serstruct)))
+ if (copy_from_user(&serstruct, user_arg, sizeof(serstruct)))
return -EFAULT;
return 0;
default:
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index d947d95..ba28fdc 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -130,7 +130,7 @@
return -ENOMEM;
r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
- if ( r < 0)
+ if (r < 0)
goto out;
/* Not having the datasheet for the CH341, we ignore the bytes returned
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index d17d164..04a56f3 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -1421,8 +1421,7 @@
tty_wait_until_sent(tty, DIGI_CLOSE_TIMEOUT);
/* flush driver and line discipline buffers */
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
tty_ldisc_flush(tty);
if (port->serial->dev) {
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c7329f4..5b349ec 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -133,6 +133,14 @@
static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_AMC232_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_3_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_4_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_5_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_6_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_7_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) },
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 6da539e..504edf8 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -40,6 +40,17 @@
/* AlphaMicro Components AMC-232USB01 device */
#define FTDI_AMC232_PID 0xFF00 /* Product Id */
+/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
+/* the VID is the standard ftdi vid (FTDI_VID) */
+#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */
+#define FTDI_SCS_DEVICE_1_PID 0xD011 /* SCS Tracker / DSP TNC */
+#define FTDI_SCS_DEVICE_2_PID 0xD012
+#define FTDI_SCS_DEVICE_3_PID 0xD013
+#define FTDI_SCS_DEVICE_4_PID 0xD014
+#define FTDI_SCS_DEVICE_5_PID 0xD015
+#define FTDI_SCS_DEVICE_6_PID 0xD016
+#define FTDI_SCS_DEVICE_7_PID 0xD017
+
/* ACT Solutions HomePro ZWave interface (http://www.act-solutions.com/HomePro.htm) */
#define FTDI_ACTZWAVE_PID 0xF2D0
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 6bcb82d..78f2f6d 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1713,7 +1713,7 @@
{
struct moschip_port *mos7840_port;
unsigned int mcr;
- unsigned int status;
+ int status;
dbg("%s - port %d", __func__, port->number);
@@ -1740,11 +1740,10 @@
mos7840_port->shadowMCR = mcr;
- status = 0;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
if (status < 0) {
dbg("setting MODEM_CONTROL_REGISTER Failed\n");
- return -1;
+ return status;
}
return 0;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index a9934a3..0cb0d77 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -296,16 +296,14 @@
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
+ if (port->serial->dev->state == USB_STATE_NOTATTACHED)
goto exit;
dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
- if (!port->open_count) {
- retval = -EINVAL;
- dbg("%s - port not opened", __func__);
- goto exit;
- }
+ /* open_count is managed under the mutex lock for the tty so cannot
+ drop to zero until after the last close completes */
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
retval = port->serial->type->write(port, buf, count);
@@ -317,61 +315,28 @@
static int serial_write_room (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
-
- if (!port)
- goto exit;
-
dbg("%s - port %d", __func__, port->number);
-
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- goto exit;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
- retval = port->serial->type->write_room(port);
-
-exit:
- return retval;
+ return port->serial->type->write_room(port);
}
static int serial_chars_in_buffer (struct tty_struct *tty)
{
struct usb_serial_port *port = tty->driver_data;
- int retval = -ENODEV;
-
- if (!port)
- goto exit;
-
dbg("%s = port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- goto exit;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
- retval = port->serial->type->chars_in_buffer(port);
-
-exit:
- return retval;
+ return port->serial->type->chars_in_buffer(port);
}
static void serial_throttle (struct tty_struct * tty)
{
struct usb_serial_port *port = tty->driver_data;
-
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg ("%s - port not open", __func__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
if (port->serial->type->throttle)
port->serial->type->throttle(port);
@@ -380,17 +345,9 @@
static void serial_unthrottle (struct tty_struct * tty)
{
struct usb_serial_port *port = tty->driver_data;
-
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function */
if (port->serial->type->unthrottle)
port->serial->type->unthrottle(port);
@@ -401,42 +358,27 @@
struct usb_serial_port *port = tty->driver_data;
int retval = -ENODEV;
- lock_kernel();
- if (!port)
- goto exit;
-
dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
- /* Caution - port->open_count is BKL protected */
- if (!port->open_count) {
- dbg ("%s - port not open", __func__);
- goto exit;
- }
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
- if (port->serial->type->ioctl)
+ if (port->serial->type->ioctl) {
+ lock_kernel();
retval = port->serial->type->ioctl(port, file, cmd, arg);
+ unlock_kernel();
+ }
else
retval = -ENOIOCTLCMD;
-exit:
- unlock_kernel();
return retval;
}
static void serial_set_termios (struct tty_struct *tty, struct ktermios * old)
{
struct usb_serial_port *port = tty->driver_data;
-
- if (!port)
- return;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
if (port->serial->type->set_termios)
port->serial->type->set_termios(port, old);
@@ -448,24 +390,15 @@
{
struct usb_serial_port *port = tty->driver_data;
- lock_kernel();
- if (!port) {
- unlock_kernel();
- return;
- }
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- unlock_kernel();
- return;
- }
-
+ WARN_ON(!port->open_count);
/* pass on to the driver specific version of this function if it is available */
- if (port->serial->type->break_ctl)
+ if (port->serial->type->break_ctl) {
+ lock_kernel();
port->serial->type->break_ctl(port, break_state);
- unlock_kernel();
+ unlock_kernel();
+ }
}
static int serial_read_proc (char *page, char **start, off_t off, int count, int *eof, void *data)
@@ -519,19 +452,11 @@
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return -ENODEV;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return -ENODEV;
- }
-
+ WARN_ON(!port->open_count);
if (port->serial->type->tiocmget)
return port->serial->type->tiocmget(port, file);
-
return -EINVAL;
}
@@ -540,19 +465,11 @@
{
struct usb_serial_port *port = tty->driver_data;
- if (!port)
- return -ENODEV;
-
dbg("%s - port %d", __func__, port->number);
- if (!port->open_count) {
- dbg("%s - port not open", __func__);
- return -ENODEV;
- }
-
+ WARN_ON(!port->open_count);
if (port->serial->type->tiocmset)
return port->serial->type->tiocmset(port, file, set, clear);
-
return -EINVAL;
}
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index e96bf86..f07e8a4 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -673,15 +673,13 @@
}
*/
- if (port->tty->driver->flush_buffer)
- port->tty->driver->flush_buffer(port->tty);
+ tty_driver_flush_buffer(port->tty);
tty_ldisc_flush(port->tty);
firm_report_tx_done(port);
firm_close(port);
-printk(KERN_ERR"Before processing rx_urbs_submitted.\n");
/* shutdown our bulk reads and writes */
mutex_lock(&info->deathwarrant);
spin_lock_irq(&info->lock);
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index 0f6d234..3d92496 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -123,7 +123,8 @@
config USB_STORAGE_ONETOUCH
bool "Support OneTouch Button on Maxtor Hard Drives"
- depends on USB_STORAGE && INPUT_EVDEV
+ depends on USB_STORAGE
+ depends on INPUT=y || INPUT=USB_STORAGE
help
Say Y here to include additional code to support the Maxtor OneTouch
USB hard drive's onetouch button.
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index d88824b..898e67d 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -46,7 +46,7 @@
}
memcpy(save_cmnd, srb->cmnd, sizeof(save_cmnd));
- memset(srb->cmnd, 0, sizeof(srb->cmnd));
+ memset(srb->cmnd, 0, MAX_COMMAND_SIZE);
/* check if we support the command */
if (save_cmnd[1] >> 5) /* MULTIPLE_COUNT */
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index 971d13d..3addcd8 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -292,6 +292,7 @@
/* maximum number of LUNs supported */
unsigned char MaxLUNs;
+ unsigned char cmnd[BLK_MAX_CDB];
struct scsi_cmnd srb;
struct scatterlist sg;
};
@@ -450,6 +451,7 @@
memset(&ata, 0, sizeof(ata));
memset(&srb_dev, 0, sizeof(srb_dev));
+ srb->cmnd = info->cmnd;
srb->device = &srb_dev;
++srb->serial_number;
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index a28d491..d617e8a 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -135,7 +135,7 @@
stat[type].fls |= USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
- task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
+ task = kthread_run(usu_probe_thread, (void*)type, "libusual_%ld", type);
if (IS_ERR(task)) {
rc = PTR_ERR(task);
printk(KERN_WARNING "libusual: "
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index dfd42fe..98b89ea 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -38,7 +38,7 @@
#include "onetouch.h"
#include "debug.h"
-void onetouch_release_input(void *onetouch_);
+static void onetouch_release_input(void *onetouch_);
struct usb_onetouch {
char name[128];
@@ -223,7 +223,7 @@
return error;
}
-void onetouch_release_input(void *onetouch_)
+static void onetouch_release_input(void *onetouch_)
{
struct usb_onetouch *onetouch = (struct usb_onetouch *) onetouch_;
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 732bf52..a0ed889 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -44,7 +44,8 @@
* running with this patch.
* Send your submission to either Phil Dibowitz <phil@ipom.com> or
* Alan Stern <stern@rowland.harvard.edu>, and don't forget to CC: the
- * USB development list <linux-usb-devel@lists.sourceforge.net>.
+ * USB development list <linux-usb@vger.kernel.org> and the USB storage list
+ * <usb-storage@lists.one-eyed-alien.net>
*/
/* patch submitted by Vivian Bregier <Vivian.Bregier@imag.fr>
@@ -557,6 +558,13 @@
US_FL_SINGLE_LUN),
#endif
+/* Reported by Dmitry Khlystov <adminimus@gmail.com> */
+UNUSUAL_DEV( 0x04e8, 0x507c, 0x0220, 0x0220,
+ "Samsung",
+ "YP-U3",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64),
+
/* Reported by Bob Sass <rls@vectordb.com> -- only rev 1.33 tested */
UNUSUAL_DEV( 0x050d, 0x0115, 0x0133, 0x0133,
"Belkin",
@@ -1200,6 +1208,17 @@
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_BULK32),
+/* Andrew Lunn <andrew@lunn.ch>
+ * PanDigital Digital Picture Frame. Does not like ALLOW_MEDIUM_REMOVAL
+ * on LUN 4.
+ * Note: Vend:Prod clash with "Ltd Maxell WS30 Slim Digital Camera"
+*/
+UNUSUAL_DEV( 0x0851, 0x1543, 0x0200, 0x0200,
+ "PanDigital",
+ "Photo Frame",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_NOT_LOCKABLE),
+
/* Submitted by Jan De Luyck <lkml@kcore.org> */
UNUSUAL_DEV( 0x08bd, 0x1100, 0x0000, 0x0000,
"CITIZEN",
@@ -1342,6 +1361,13 @@
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_INQUIRY),
+/* Reported by Rohan Hart <rohan.hart17@gmail.com> */
+UNUSUAL_DEV( 0x2770, 0x915d, 0x0010, 0x0010,
+ "INTOVA",
+ "Pixtreme",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/*
* Entry for Jenoptik JD 5200z3
*
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index a856eff..e268aac 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -539,7 +539,8 @@
" has %s in unusual_devs.h (kernel"
" %s)\n"
" Please send a copy of this message to "
- "<linux-usb-devel@lists.sourceforge.net>\n",
+ "<linux-usb@vger.kernel.org> and "
+ "<usb-storage@lists.one-eyed-alien.net>\n",
le16_to_cpu(ddesc->idVendor),
le16_to_cpu(ddesc->idProduct),
le16_to_cpu(ddesc->bcdDevice),
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index a576dc2..bb1dada 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1774,6 +1774,11 @@
If unsure, say N.
+config FB_PXA_SMARTPANEL
+ bool "PXA Smartpanel LCD support"
+ default n
+ depends on FB_PXA
+
config FB_PXA_PARAMETERS
bool "PXA LCD command line parameters"
default n
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c
index 17b5267..9f8a389 100644
--- a/drivers/video/clps711xfb.c
+++ b/drivers/video/clps711xfb.c
@@ -381,7 +381,7 @@
/* Register the /proc entries. */
clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444,
- &proc_root);
+ NULL);
if (clps7111fb_backlight_proc_entry == NULL) {
printk("Couldn't create the /proc entry for the backlight.\n");
return -EINVAL;
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 8eda7b6..ad31983 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -1881,7 +1881,7 @@
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
- vc->vc_video_erase_char,
+ vc->vc_scrl_erase_char,
vc->vc_size_row * count);
return 1;
break;
@@ -1953,7 +1953,7 @@
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
(b - count)),
- vc->vc_video_erase_char,
+ vc->vc_scrl_erase_char,
vc->vc_size_row * count);
return 1;
}
@@ -1972,7 +1972,7 @@
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
t),
- vc->vc_video_erase_char,
+ vc->vc_scrl_erase_char,
vc->vc_size_row * count);
return 1;
break;
@@ -2042,7 +2042,7 @@
scr_memsetw((unsigned short *) (vc->vc_origin +
vc->vc_size_row *
t),
- vc->vc_video_erase_char,
+ vc->vc_scrl_erase_char,
vc->vc_size_row * count);
return 1;
}
diff --git a/drivers/video/console/mdacon.c b/drivers/video/console/mdacon.c
index bd8d995..38a296b 100644
--- a/drivers/video/console/mdacon.c
+++ b/drivers/video/console/mdacon.c
@@ -531,7 +531,7 @@
static int mdacon_scroll(struct vc_data *c, int t, int b, int dir, int lines)
{
- u16 eattr = mda_convert_attr(c->vc_video_erase_char);
+ u16 eattr = mda_convert_attr(c->vc_scrl_erase_char);
if (!lines)
return 0;
diff --git a/drivers/video/console/sticon.c b/drivers/video/console/sticon.c
index 67a682d..a11cc2f 100644
--- a/drivers/video/console/sticon.c
+++ b/drivers/video/console/sticon.c
@@ -170,12 +170,12 @@
switch (dir) {
case SM_UP:
sti_bmove(sti, t + count, 0, t, 0, b - t - count, conp->vc_cols);
- sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+ sti_clear(sti, b - count, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
break;
case SM_DOWN:
sti_bmove(sti, t, 0, t + count, 0, b - t - count, conp->vc_cols);
- sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_video_erase_char);
+ sti_clear(sti, t, 0, count, conp->vc_cols, conp->vc_scrl_erase_char);
break;
}
diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c
index 6df29a6..bd1f57b 100644
--- a/drivers/video/console/vgacon.c
+++ b/drivers/video/console/vgacon.c
@@ -1350,7 +1350,7 @@
} else
c->vc_origin += delta;
scr_memsetw((u16 *) (c->vc_origin + c->vc_screenbuf_size -
- delta), c->vc_video_erase_char,
+ delta), c->vc_scrl_erase_char,
delta);
} else {
if (oldo - delta < vga_vram_base) {
@@ -1363,7 +1363,7 @@
} else
c->vc_origin -= delta;
c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
- scr_memsetw((u16 *) (c->vc_origin), c->vc_video_erase_char,
+ scr_memsetw((u16 *) (c->vc_origin), c->vc_scrl_erase_char,
delta);
}
c->vc_scr_end = c->vc_origin + c->vc_screenbuf_size;
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index aaa3e53..5b5f072 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -522,8 +522,6 @@
#endif
}
-#define get_u16(x) (le16_to_cpu(get_unaligned((__u16*)(x))))
-#define get_u32(x) (le32_to_cpu(get_unaligned((__u32*)(x))))
static int parse_pins1(WPMINFO const struct matrox_bios* bd) {
unsigned int maxdac;
@@ -532,11 +530,12 @@
case 1: maxdac = 220000; break;
default: maxdac = 240000; break;
}
- if (get_u16(bd->pins + 24)) {
- maxdac = get_u16(bd->pins + 24) * 10;
+ if (get_unaligned_le16(bd->pins + 24)) {
+ maxdac = get_unaligned_le16(bd->pins + 24) * 10;
}
MINFO->limits.pixel.vcomax = maxdac;
- MINFO->values.pll.system = get_u16(bd->pins + 28) ? get_u16(bd->pins + 28) * 10 : 50000;
+ MINFO->values.pll.system = get_unaligned_le16(bd->pins + 28) ?
+ get_unaligned_le16(bd->pins + 28) * 10 : 50000;
/* ignore 4MB, 8MB, module clocks */
MINFO->features.pll.ref_freq = 14318;
MINFO->values.reg.mctlwtst = 0x00030101;
@@ -575,7 +574,8 @@
static int parse_pins3(WPMINFO const struct matrox_bios* bd) {
MINFO->limits.pixel.vcomax =
MINFO->limits.system.vcomax = (bd->pins[36] == 0xFF) ? 230000 : ((bd->pins[36] + 100) * 1000);
- MINFO->values.reg.mctlwtst = get_u32(bd->pins + 48) == 0xFFFFFFFF ? 0x01250A21 : get_u32(bd->pins + 48);
+ MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 48) == 0xFFFFFFFF ?
+ 0x01250A21 : get_unaligned_le32(bd->pins + 48);
/* memory config */
MINFO->values.reg.memrdbk = ((bd->pins[57] << 21) & 0x1E000000) |
((bd->pins[57] << 22) & 0x00C00000) |
@@ -601,7 +601,7 @@
static int parse_pins4(WPMINFO const struct matrox_bios* bd) {
MINFO->limits.pixel.vcomax = (bd->pins[ 39] == 0xFF) ? 230000 : bd->pins[ 39] * 4000;
MINFO->limits.system.vcomax = (bd->pins[ 38] == 0xFF) ? MINFO->limits.pixel.vcomax : bd->pins[ 38] * 4000;
- MINFO->values.reg.mctlwtst = get_u32(bd->pins + 71);
+ MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 71);
MINFO->values.reg.memrdbk = ((bd->pins[87] << 21) & 0x1E000000) |
((bd->pins[87] << 22) & 0x00C00000) |
((bd->pins[86] << 1) & 0x000001E0) |
@@ -609,7 +609,7 @@
MINFO->values.reg.opt = ((bd->pins[53] << 15) & 0x00400000) |
((bd->pins[53] << 22) & 0x10000000) |
((bd->pins[53] << 7) & 0x00001C00);
- MINFO->values.reg.opt3 = get_u32(bd->pins + 67);
+ MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 67);
MINFO->values.pll.system = (bd->pins[ 65] == 0xFF) ? 200000 : bd->pins[ 65] * 4000;
MINFO->features.pll.ref_freq = (bd->pins[ 92] & 0x01) ? 14318 : 27000;
return 0;
@@ -640,12 +640,12 @@
MINFO->limits.video.vcomin = (bd->pins[122] == 0xFF) ? MINFO->limits.system.vcomin : bd->pins[122] * mult;
MINFO->values.pll.system =
MINFO->values.pll.video = (bd->pins[ 92] == 0xFF) ? 284000 : bd->pins[ 92] * 4000;
- MINFO->values.reg.opt = get_u32(bd->pins+ 48);
- MINFO->values.reg.opt2 = get_u32(bd->pins+ 52);
- MINFO->values.reg.opt3 = get_u32(bd->pins+ 94);
- MINFO->values.reg.mctlwtst = get_u32(bd->pins+ 98);
- MINFO->values.reg.memmisc = get_u32(bd->pins+102);
- MINFO->values.reg.memrdbk = get_u32(bd->pins+106);
+ MINFO->values.reg.opt = get_unaligned_le32(bd->pins + 48);
+ MINFO->values.reg.opt2 = get_unaligned_le32(bd->pins + 52);
+ MINFO->values.reg.opt3 = get_unaligned_le32(bd->pins + 94);
+ MINFO->values.reg.mctlwtst = get_unaligned_le32(bd->pins + 98);
+ MINFO->values.reg.memmisc = get_unaligned_le32(bd->pins + 102);
+ MINFO->values.reg.memrdbk = get_unaligned_le32(bd->pins + 106);
MINFO->features.pll.ref_freq = (bd->pins[110] & 0x01) ? 14318 : 27000;
MINFO->values.memory.ddr = (bd->pins[114] & 0x60) == 0x20;
MINFO->values.memory.dll = (bd->pins[115] & 0x02) != 0;
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c
index 2497912..cc4c038 100644
--- a/drivers/video/metronomefb.c
+++ b/drivers/video/metronomefb.c
@@ -206,8 +206,7 @@
}
/* check waveform mode table address checksum */
- wmta = le32_to_cpu(get_unaligned((__le32 *) wfm_hdr->wmta));
- wmta &= 0x00FFFFFF;
+ wmta = get_unaligned_le32(wfm_hdr->wmta) & 0x00FFFFFF;
cksum_idx = wmta + m*4 + 3;
if (cksum_idx > size)
return -EINVAL;
@@ -219,8 +218,7 @@
}
/* check waveform temperature table address checksum */
- tta = le32_to_cpu(get_unaligned((int *) (mem + wmta + m*4)));
- tta &= 0x00FFFFFF;
+ tta = get_unaligned_le32(mem + wmta + m * 4) & 0x00FFFFFF;
cksum_idx = tta + trn*4 + 3;
if (cksum_idx > size)
return -EINVAL;
@@ -233,8 +231,7 @@
/* here we do the real work of putting the waveform into the
metromem buffer. this does runlength decoding of the waveform */
- wfm_idx = le32_to_cpu(get_unaligned((__le32 *) (mem + tta + trn*4)));
- wfm_idx &= 0x00FFFFFF;
+ wfm_idx = get_unaligned_le32(mem + tta + trn * 4) & 0x00FFFFFF;
owfm_idx = wfm_idx;
if (wfm_idx > size)
return -EINVAL;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 7576519..3ab6e3d 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -39,6 +39,9 @@
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/completion.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <asm/hardware.h>
#include <asm/io.h>
@@ -57,19 +60,31 @@
#include "pxafb.h"
/* Bits which should not be set in machine configuration structures */
-#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM|LCCR0_BM|LCCR0_QDM|LCCR0_DIS|LCCR0_EFM|LCCR0_IUM|LCCR0_SFM|LCCR0_LDM|LCCR0_ENB)
-#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
+#define LCCR0_INVALID_CONFIG_MASK (LCCR0_OUM | LCCR0_BM | LCCR0_QDM |\
+ LCCR0_DIS | LCCR0_EFM | LCCR0_IUM |\
+ LCCR0_SFM | LCCR0_LDM | LCCR0_ENB)
+
+#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP | LCCR3_VSP |\
+ LCCR3_PCD | LCCR3_BPP)
static void (*pxafb_backlight_power)(int);
static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
-static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
+static int pxafb_activate_var(struct fb_var_screeninfo *var,
+ struct pxafb_info *);
static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
-#ifdef CONFIG_FB_PXA_PARAMETERS
-#define PXAFB_OPTIONS_SIZE 256
-static char g_options[PXAFB_OPTIONS_SIZE] __devinitdata = "";
-#endif
+static inline unsigned long
+lcd_readl(struct pxafb_info *fbi, unsigned int off)
+{
+ return __raw_readl(fbi->mmio_base + off);
+}
+
+static inline void
+lcd_writel(struct pxafb_info *fbi, unsigned int off, unsigned long val)
+{
+ __raw_writel(val, fbi->mmio_base + off);
+}
static inline void pxafb_schedule_work(struct pxafb_info *fbi, u_int state)
{
@@ -79,10 +94,12 @@
/*
* We need to handle two requests being made at the same time.
* There are two important cases:
- * 1. When we are changing VT (C_REENABLE) while unblanking (C_ENABLE)
- * We must perform the unblanking, which will do our REENABLE for us.
- * 2. When we are blanking, but immediately unblank before we have
- * blanked. We do the "REENABLE" thing here as well, just to be sure.
+ * 1. When we are changing VT (C_REENABLE) while unblanking
+ * (C_ENABLE) We must perform the unblanking, which will
+ * do our REENABLE for us.
+ * 2. When we are blanking, but immediately unblank before
+ * we have blanked. We do the "REENABLE" thing here as
+ * well, just to be sure.
*/
if (fbi->task_state == C_ENABLE && state == C_REENABLE)
state = (u_int) -1;
@@ -129,13 +146,13 @@
val = ((red << 8) & 0x00f80000);
val |= ((green >> 0) & 0x0000fc00);
val |= ((blue >> 8) & 0x000000f8);
- ((u32*)(fbi->palette_cpu))[regno] = val;
+ ((u32 *)(fbi->palette_cpu))[regno] = val;
break;
case LCCR4_PAL_FOR_2:
val = ((red << 8) & 0x00fc0000);
val |= ((green >> 0) & 0x0000fc00);
val |= ((blue >> 8) & 0x000000fc);
- ((u32*)(fbi->palette_cpu))[regno] = val;
+ ((u32 *)(fbi->palette_cpu))[regno] = val;
break;
}
@@ -203,15 +220,15 @@
*/
static int pxafb_bpp_to_lccr3(struct fb_var_screeninfo *var)
{
- int ret = 0;
- switch (var->bits_per_pixel) {
- case 1: ret = LCCR3_1BPP; break;
- case 2: ret = LCCR3_2BPP; break;
- case 4: ret = LCCR3_4BPP; break;
- case 8: ret = LCCR3_8BPP; break;
- case 16: ret = LCCR3_16BPP; break;
- }
- return ret;
+ int ret = 0;
+ switch (var->bits_per_pixel) {
+ case 1: ret = LCCR3_1BPP; break;
+ case 2: ret = LCCR3_2BPP; break;
+ case 4: ret = LCCR3_4BPP; break;
+ case 8: ret = LCCR3_8BPP; break;
+ case 16: ret = LCCR3_16BPP; break;
+ }
+ return ret;
}
#ifdef CONFIG_CPU_FREQ
@@ -223,31 +240,32 @@
*/
static unsigned int pxafb_display_dma_period(struct fb_var_screeninfo *var)
{
- /*
- * Period = pixclock * bits_per_byte * bytes_per_transfer
- * / memory_bits_per_pixel;
- */
- return var->pixclock * 8 * 16 / var->bits_per_pixel;
+ /*
+ * Period = pixclock * bits_per_byte * bytes_per_transfer
+ * / memory_bits_per_pixel;
+ */
+ return var->pixclock * 8 * 16 / var->bits_per_pixel;
}
-
-extern unsigned int get_clk_frequency_khz(int info);
#endif
/*
* Select the smallest mode that allows the desired resolution to be
* displayed. If desired parameters can be rounded up.
*/
-static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struct fb_var_screeninfo *var)
+static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach,
+ struct fb_var_screeninfo *var)
{
struct pxafb_mode_info *mode = NULL;
struct pxafb_mode_info *modelist = mach->modes;
unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
unsigned int i;
- for (i = 0 ; i < mach->num_modes ; i++) {
- if (modelist[i].xres >= var->xres && modelist[i].yres >= var->yres &&
- modelist[i].xres < best_x && modelist[i].yres < best_y &&
- modelist[i].bpp >= var->bits_per_pixel ) {
+ for (i = 0; i < mach->num_modes; i++) {
+ if (modelist[i].xres >= var->xres &&
+ modelist[i].yres >= var->yres &&
+ modelist[i].xres < best_x &&
+ modelist[i].yres < best_y &&
+ modelist[i].bpp >= var->bits_per_pixel) {
best_x = modelist[i].xres;
best_y = modelist[i].yres;
mode = &modelist[i];
@@ -257,7 +275,8 @@
return mode;
}
-static void pxafb_setmode(struct fb_var_screeninfo *var, struct pxafb_mode_info *mode)
+static void pxafb_setmode(struct fb_var_screeninfo *var,
+ struct pxafb_mode_info *mode)
{
var->xres = mode->xres;
var->yres = mode->yres;
@@ -315,19 +334,20 @@
var->yres_virtual =
max(var->yres_virtual, var->yres);
- /*
+ /*
* Setup the RGB parameters for this display.
*
* The pixel packing format is described on page 7-11 of the
* PXA2XX Developer's Manual.
- */
+ */
if (var->bits_per_pixel == 16) {
var->red.offset = 11; var->red.length = 5;
var->green.offset = 5; var->green.length = 6;
var->blue.offset = 0; var->blue.length = 5;
var->transp.offset = var->transp.length = 0;
} else {
- var->red.offset = var->green.offset = var->blue.offset = var->transp.offset = 0;
+ var->red.offset = var->green.offset = 0;
+ var->blue.offset = var->transp.offset = 0;
var->red.length = 8;
var->green.length = 8;
var->blue.length = 8;
@@ -345,8 +365,7 @@
static inline void pxafb_set_truecolor(u_int is_true_color)
{
- pr_debug("pxafb: true_color = %d\n", is_true_color);
- // do your machine-specific setup if needed
+ /* do your machine-specific setup if needed */
}
/*
@@ -357,9 +376,6 @@
{
struct pxafb_info *fbi = (struct pxafb_info *)info;
struct fb_var_screeninfo *var = &info->var;
- unsigned long palette_mem_size;
-
- pr_debug("pxafb: set_par\n");
if (var->bits_per_pixel == 16)
fbi->fb.fix.visual = FB_VISUAL_TRUECOLOR;
@@ -379,17 +395,10 @@
if (var->bits_per_pixel == 16)
fbi->palette_size = 0;
else
- fbi->palette_size = var->bits_per_pixel == 1 ? 4 : 1 << var->bits_per_pixel;
+ fbi->palette_size = var->bits_per_pixel == 1 ?
+ 4 : 1 << var->bits_per_pixel;
- if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
- palette_mem_size = fbi->palette_size * sizeof(u16);
- else
- palette_mem_size = fbi->palette_size * sizeof(u32);
-
- pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
-
- fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
- fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+ fbi->palette_cpu = (u16 *)&fbi->dma_buff->palette[0];
/*
* Set (any) board control register to handle new color depth
@@ -407,36 +416,6 @@
}
/*
- * Formal definition of the VESA spec:
- * On
- * This refers to the state of the display when it is in full operation
- * Stand-By
- * This defines an optional operating state of minimal power reduction with
- * the shortest recovery time
- * Suspend
- * This refers to a level of power management in which substantial power
- * reduction is achieved by the display. The display can have a longer
- * recovery time from this state than from the Stand-by state
- * Off
- * This indicates that the display is consuming the lowest level of power
- * and is non-operational. Recovery from this state may optionally require
- * the user to manually power on the monitor
- *
- * Now, the fbdev driver adds an additional state, (blank), where they
- * turn off the video (maybe by colormap tricks), but don't mess with the
- * video itself: think of it semantically between on and Stand-By.
- *
- * So here's what we should do in our fbdev blank routine:
- *
- * VESA_NO_BLANKING (mode 0) Video on, front/back light on
- * VESA_VSYNC_SUSPEND (mode 1) Video on, front/back light off
- * VESA_HSYNC_SUSPEND (mode 2) Video on, front/back light off
- * VESA_POWERDOWN (mode 3) Video off, front/back light off
- *
- * This will match the matrox implementation.
- */
-
-/*
* pxafb_blank():
* Blank the display by setting all palette values to zero. Note, the
* 16 bpp mode does not really use the palette, so this will not
@@ -447,8 +426,6 @@
struct pxafb_info *fbi = (struct pxafb_info *)info;
int i;
- pr_debug("pxafb: blank=%d\n", blank);
-
switch (blank) {
case FB_BLANK_POWERDOWN:
case FB_BLANK_VSYNC_SUSPEND:
@@ -460,11 +437,11 @@
pxafb_setpalettereg(i, 0, 0, 0, 0, info);
pxafb_schedule_work(fbi, C_DISABLE);
- //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+ /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
break;
case FB_BLANK_UNBLANK:
- //TODO if (pxafb_blank_helper) pxafb_blank_helper(blank);
+ /* TODO if (pxafb_blank_helper) pxafb_blank_helper(blank); */
if (fbi->fb.fix.visual == FB_VISUAL_PSEUDOCOLOR ||
fbi->fb.fix.visual == FB_VISUAL_STATIC_PSEUDOCOLOR)
fb_set_cmap(&fbi->fb.cmap, info);
@@ -480,7 +457,7 @@
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
if (off < info->fix.smem_len) {
- vma->vm_pgoff += 1;
+ vma->vm_pgoff += fbi->video_offset / PAGE_SIZE;
return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu,
fbi->map_dma, fbi->map_size);
}
@@ -529,7 +506,8 @@
*
* Factoring the 10^4 and 10^-12 out gives 10^-8 == 1 / 100000000 as used below.
*/
-static inline unsigned int get_pcd(struct pxafb_info *fbi, unsigned int pixclock)
+static inline unsigned int get_pcd(struct pxafb_info *fbi,
+ unsigned int pixclock)
{
unsigned long long pcd;
@@ -555,7 +533,7 @@
unsigned long htime;
if ((pcd == 0) || (fbi->fb.var.hsync_len == 0)) {
- fbi->hsync_time=0;
+ fbi->hsync_time = 0;
return;
}
@@ -576,71 +554,231 @@
}
EXPORT_SYMBOL(pxafb_get_hsync_time);
-/*
- * pxafb_activate_var():
- * Configures LCD Controller based on entries in var parameter. Settings are
- * only written to the controller if changes were made.
- */
-static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *fbi)
+static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal,
+ unsigned int offset, size_t size)
{
- struct pxafb_lcd_reg new_regs;
- u_long flags;
- u_int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
+ struct pxafb_dma_descriptor *dma_desc, *pal_desc;
+ unsigned int dma_desc_off, pal_desc_off;
- pr_debug("pxafb: Configuring PXA LCD\n");
+ if (dma < 0 || dma >= DMA_MAX)
+ return -EINVAL;
- pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
- var->xres, var->hsync_len,
- var->left_margin, var->right_margin);
- pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
- var->yres, var->vsync_len,
- var->upper_margin, var->lower_margin);
- pr_debug("var: pixclock=%d pcd=%d\n", var->pixclock, pcd);
+ dma_desc = &fbi->dma_buff->dma_desc[dma];
+ dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[dma]);
-#if DEBUG_VAR
- if (var->xres < 16 || var->xres > 1024)
- printk(KERN_ERR "%s: invalid xres %d\n",
- fbi->fb.fix.id, var->xres);
- switch(var->bits_per_pixel) {
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- break;
- default:
- printk(KERN_ERR "%s: invalid bit depth %d\n",
- fbi->fb.fix.id, var->bits_per_pixel);
- break;
+ dma_desc->fsadr = fbi->screen_dma + offset;
+ dma_desc->fidr = 0;
+ dma_desc->ldcmd = size;
+
+ if (pal < 0 || pal >= PAL_MAX) {
+ dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
+ fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
+ } else {
+ pal_desc = &fbi->dma_buff->pal_desc[dma];
+ pal_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[pal]);
+
+ pal_desc->fsadr = fbi->dma_buff_phys + pal * PALETTE_SIZE;
+ pal_desc->fidr = 0;
+
+ if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
+ pal_desc->ldcmd = fbi->palette_size * sizeof(u16);
+ else
+ pal_desc->ldcmd = fbi->palette_size * sizeof(u32);
+
+ pal_desc->ldcmd |= LDCMD_PAL;
+
+ /* flip back and forth between palette and frame buffer */
+ pal_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
+ dma_desc->fdadr = fbi->dma_buff_phys + pal_desc_off;
+ fbi->fdadr[dma] = fbi->dma_buff_phys + dma_desc_off;
}
- if (var->hsync_len < 1 || var->hsync_len > 64)
- printk(KERN_ERR "%s: invalid hsync_len %d\n",
- fbi->fb.fix.id, var->hsync_len);
- if (var->left_margin < 1 || var->left_margin > 255)
- printk(KERN_ERR "%s: invalid left_margin %d\n",
- fbi->fb.fix.id, var->left_margin);
- if (var->right_margin < 1 || var->right_margin > 255)
- printk(KERN_ERR "%s: invalid right_margin %d\n",
- fbi->fb.fix.id, var->right_margin);
- if (var->yres < 1 || var->yres > 1024)
- printk(KERN_ERR "%s: invalid yres %d\n",
- fbi->fb.fix.id, var->yres);
- if (var->vsync_len < 1 || var->vsync_len > 64)
- printk(KERN_ERR "%s: invalid vsync_len %d\n",
- fbi->fb.fix.id, var->vsync_len);
- if (var->upper_margin < 0 || var->upper_margin > 255)
- printk(KERN_ERR "%s: invalid upper_margin %d\n",
- fbi->fb.fix.id, var->upper_margin);
- if (var->lower_margin < 0 || var->lower_margin > 255)
- printk(KERN_ERR "%s: invalid lower_margin %d\n",
- fbi->fb.fix.id, var->lower_margin);
-#endif
- new_regs.lccr0 = fbi->lccr0 |
- (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
- LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
+ return 0;
+}
- new_regs.lccr1 =
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+static int setup_smart_dma(struct pxafb_info *fbi)
+{
+ struct pxafb_dma_descriptor *dma_desc;
+ unsigned long dma_desc_off, cmd_buff_off;
+
+ dma_desc = &fbi->dma_buff->dma_desc[DMA_CMD];
+ dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[DMA_CMD]);
+ cmd_buff_off = offsetof(struct pxafb_dma_buff, cmd_buff);
+
+ dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off;
+ dma_desc->fsadr = fbi->dma_buff_phys + cmd_buff_off;
+ dma_desc->fidr = 0;
+ dma_desc->ldcmd = fbi->n_smart_cmds * sizeof(uint16_t);
+
+ fbi->fdadr[DMA_CMD] = dma_desc->fdadr;
+ return 0;
+}
+
+int pxafb_smart_flush(struct fb_info *info)
+{
+ struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
+ uint32_t prsr;
+ int ret = 0;
+
+ /* disable controller until all registers are set up */
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
+
+ /* 1. make it an even number of commands to align on 32-bit boundary
+ * 2. add the interrupt command to the end of the chain so we can
+ * keep track of the end of the transfer
+ */
+
+ while (fbi->n_smart_cmds & 1)
+ fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_NOOP;
+
+ fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_INTERRUPT;
+ fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_WAIT_FOR_VSYNC;
+ setup_smart_dma(fbi);
+
+ /* continue to execute next command */
+ prsr = lcd_readl(fbi, PRSR) | PRSR_ST_OK | PRSR_CON_NT;
+ lcd_writel(fbi, PRSR, prsr);
+
+ /* stop the processor in case it executed "wait for sync" cmd */
+ lcd_writel(fbi, CMDCR, 0x0001);
+
+ /* don't send interrupts for fifo underruns on channel 6 */
+ lcd_writel(fbi, LCCR5, LCCR5_IUM(6));
+
+ lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
+ lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
+ lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
+ lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
+ lcd_writel(fbi, FDADR6, fbi->fdadr[6]);
+
+ /* begin sending */
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
+
+ if (wait_for_completion_timeout(&fbi->command_done, HZ/2) == 0) {
+ pr_warning("%s: timeout waiting for command done\n",
+ __func__);
+ ret = -ETIMEDOUT;
+ }
+
+ /* quick disable */
+ prsr = lcd_readl(fbi, PRSR) & ~(PRSR_ST_OK | PRSR_CON_NT);
+ lcd_writel(fbi, PRSR, prsr);
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
+ lcd_writel(fbi, FDADR6, 0);
+ fbi->n_smart_cmds = 0;
+ return ret;
+}
+
+int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds)
+{
+ int i;
+ struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb);
+
+ /* leave 2 commands for INTERRUPT and WAIT_FOR_SYNC */
+ for (i = 0; i < n_cmds; i++) {
+ if (fbi->n_smart_cmds == CMD_BUFF_SIZE - 8)
+ pxafb_smart_flush(info);
+
+ fbi->smart_cmds[fbi->n_smart_cmds++] = *cmds++;
+ }
+
+ return 0;
+}
+
+static unsigned int __smart_timing(unsigned time_ns, unsigned long lcd_clk)
+{
+ unsigned int t = (time_ns * (lcd_clk / 1000000) / 1000);
+ return (t == 0) ? 1 : t;
+}
+
+static void setup_smart_timing(struct pxafb_info *fbi,
+ struct fb_var_screeninfo *var)
+{
+ struct pxafb_mach_info *inf = fbi->dev->platform_data;
+ struct pxafb_mode_info *mode = &inf->modes[0];
+ unsigned long lclk = clk_get_rate(fbi->clk);
+ unsigned t1, t2, t3, t4;
+
+ t1 = max(mode->a0csrd_set_hld, mode->a0cswr_set_hld);
+ t2 = max(mode->rd_pulse_width, mode->wr_pulse_width);
+ t3 = mode->op_hold_time;
+ t4 = mode->cmd_inh_time;
+
+ fbi->reg_lccr1 =
+ LCCR1_DisWdth(var->xres) |
+ LCCR1_BegLnDel(__smart_timing(t1, lclk)) |
+ LCCR1_EndLnDel(__smart_timing(t2, lclk)) |
+ LCCR1_HorSnchWdth(__smart_timing(t3, lclk));
+
+ fbi->reg_lccr2 = LCCR2_DisHght(var->yres);
+ fbi->reg_lccr3 = LCCR3_PixClkDiv(__smart_timing(t4, lclk));
+
+ /* FIXME: make this configurable */
+ fbi->reg_cmdcr = 1;
+}
+
+static int pxafb_smart_thread(void *arg)
+{
+ struct pxafb_info *fbi = arg;
+ struct pxafb_mach_info *inf = fbi->dev->platform_data;
+
+ if (!fbi || !inf->smart_update) {
+ pr_err("%s: not properly initialized, thread terminated\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ pr_debug("%s(): task starting\n", __func__);
+
+ set_freezable();
+ while (!kthread_should_stop()) {
+
+ if (try_to_freeze())
+ continue;
+
+ if (fbi->state == C_ENABLE) {
+ inf->smart_update(&fbi->fb);
+ complete(&fbi->refresh_done);
+ }
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(30 * HZ / 1000);
+ }
+
+ pr_debug("%s(): task ending\n", __func__);
+ return 0;
+}
+
+static int pxafb_smart_init(struct pxafb_info *fbi)
+{
+ fbi->smart_thread = kthread_run(pxafb_smart_thread, fbi,
+ "lcd_refresh");
+ if (IS_ERR(fbi->smart_thread)) {
+ printk(KERN_ERR "%s: unable to create kernel thread\n",
+ __func__);
+ return PTR_ERR(fbi->smart_thread);
+ }
+ return 0;
+}
+#else
+int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds)
+{
+ return 0;
+}
+
+int pxafb_smart_flush(struct fb_info *info)
+{
+ return 0;
+}
+#endif /* CONFIG_FB_SMART_PANEL */
+
+static void setup_parallel_timing(struct pxafb_info *fbi,
+ struct fb_var_screeninfo *var)
+{
+ unsigned int lines_per_panel, pcd = get_pcd(fbi, var->pixclock);
+
+ fbi->reg_lccr1 =
LCCR1_DisWdth(var->xres) +
LCCR1_HorSnchWdth(var->hsync_len) +
LCCR1_BegLnDel(var->left_margin) +
@@ -654,110 +792,118 @@
if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual)
lines_per_panel /= 2;
- new_regs.lccr2 =
+ fbi->reg_lccr2 =
LCCR2_DisHght(lines_per_panel) +
LCCR2_VrtSnchWdth(var->vsync_len) +
LCCR2_BegFrmDel(var->upper_margin) +
LCCR2_EndFrmDel(var->lower_margin);
- new_regs.lccr3 = fbi->lccr3 |
- pxafb_bpp_to_lccr3(var) |
- (var->sync & FB_SYNC_HOR_HIGH_ACT ? LCCR3_HorSnchH : LCCR3_HorSnchL) |
- (var->sync & FB_SYNC_VERT_HIGH_ACT ? LCCR3_VrtSnchH : LCCR3_VrtSnchL);
+ fbi->reg_lccr3 = fbi->lccr3 |
+ (var->sync & FB_SYNC_HOR_HIGH_ACT ?
+ LCCR3_HorSnchH : LCCR3_HorSnchL) |
+ (var->sync & FB_SYNC_VERT_HIGH_ACT ?
+ LCCR3_VrtSnchH : LCCR3_VrtSnchL);
- if (pcd)
- new_regs.lccr3 |= LCCR3_PixClkDiv(pcd);
+ if (pcd) {
+ fbi->reg_lccr3 |= LCCR3_PixClkDiv(pcd);
+ set_hsync_time(fbi, pcd);
+ }
+}
- pr_debug("nlccr0 = 0x%08x\n", new_regs.lccr0);
- pr_debug("nlccr1 = 0x%08x\n", new_regs.lccr1);
- pr_debug("nlccr2 = 0x%08x\n", new_regs.lccr2);
- pr_debug("nlccr3 = 0x%08x\n", new_regs.lccr3);
+/*
+ * pxafb_activate_var():
+ * Configures LCD Controller based on entries in var parameter.
+ * Settings are only written to the controller if changes were made.
+ */
+static int pxafb_activate_var(struct fb_var_screeninfo *var,
+ struct pxafb_info *fbi)
+{
+ u_long flags;
+ size_t nbytes;
+#if DEBUG_VAR
+ if (!(fbi->lccr0 & LCCR0_LCDT)) {
+ if (var->xres < 16 || var->xres > 1024)
+ printk(KERN_ERR "%s: invalid xres %d\n",
+ fbi->fb.fix.id, var->xres);
+ switch (var->bits_per_pixel) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ break;
+ default:
+ printk(KERN_ERR "%s: invalid bit depth %d\n",
+ fbi->fb.fix.id, var->bits_per_pixel);
+ break;
+ }
+
+ if (var->hsync_len < 1 || var->hsync_len > 64)
+ printk(KERN_ERR "%s: invalid hsync_len %d\n",
+ fbi->fb.fix.id, var->hsync_len);
+ if (var->left_margin < 1 || var->left_margin > 255)
+ printk(KERN_ERR "%s: invalid left_margin %d\n",
+ fbi->fb.fix.id, var->left_margin);
+ if (var->right_margin < 1 || var->right_margin > 255)
+ printk(KERN_ERR "%s: invalid right_margin %d\n",
+ fbi->fb.fix.id, var->right_margin);
+ if (var->yres < 1 || var->yres > 1024)
+ printk(KERN_ERR "%s: invalid yres %d\n",
+ fbi->fb.fix.id, var->yres);
+ if (var->vsync_len < 1 || var->vsync_len > 64)
+ printk(KERN_ERR "%s: invalid vsync_len %d\n",
+ fbi->fb.fix.id, var->vsync_len);
+ if (var->upper_margin < 0 || var->upper_margin > 255)
+ printk(KERN_ERR "%s: invalid upper_margin %d\n",
+ fbi->fb.fix.id, var->upper_margin);
+ if (var->lower_margin < 0 || var->lower_margin > 255)
+ printk(KERN_ERR "%s: invalid lower_margin %d\n",
+ fbi->fb.fix.id, var->lower_margin);
+ }
+#endif
/* Update shadow copy atomically */
local_irq_save(flags);
- /* setup dma descriptors */
- fbi->dmadesc_fblow_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 3*16);
- fbi->dmadesc_fbhigh_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 2*16);
- fbi->dmadesc_palette_cpu = (struct pxafb_dma_descriptor *)((unsigned int)fbi->palette_cpu - 1*16);
-
- fbi->dmadesc_fblow_dma = fbi->palette_dma - 3*16;
- fbi->dmadesc_fbhigh_dma = fbi->palette_dma - 2*16;
- fbi->dmadesc_palette_dma = fbi->palette_dma - 1*16;
-
-#define BYTES_PER_PANEL (lines_per_panel * fbi->fb.fix.line_length)
-
- /* populate descriptors */
- fbi->dmadesc_fblow_cpu->fdadr = fbi->dmadesc_fblow_dma;
- fbi->dmadesc_fblow_cpu->fsadr = fbi->screen_dma + BYTES_PER_PANEL;
- fbi->dmadesc_fblow_cpu->fidr = 0;
- fbi->dmadesc_fblow_cpu->ldcmd = BYTES_PER_PANEL;
-
- fbi->fdadr1 = fbi->dmadesc_fblow_dma; /* only used in dual-panel mode */
-
- fbi->dmadesc_fbhigh_cpu->fsadr = fbi->screen_dma;
- fbi->dmadesc_fbhigh_cpu->fidr = 0;
- fbi->dmadesc_fbhigh_cpu->ldcmd = BYTES_PER_PANEL;
-
- fbi->dmadesc_palette_cpu->fsadr = fbi->palette_dma;
- fbi->dmadesc_palette_cpu->fidr = 0;
- if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
- fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
- sizeof(u16);
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ if (fbi->lccr0 & LCCR0_LCDT)
+ setup_smart_timing(fbi, var);
else
- fbi->dmadesc_palette_cpu->ldcmd = fbi->palette_size *
- sizeof(u32);
- fbi->dmadesc_palette_cpu->ldcmd |= LDCMD_PAL;
+#endif
+ setup_parallel_timing(fbi, var);
- if (var->bits_per_pixel == 16) {
- /* palette shouldn't be loaded in true-color mode */
- fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
- fbi->fdadr0 = fbi->dmadesc_fbhigh_dma; /* no pal just fbhigh */
- /* init it to something, even though we won't be using it */
- fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_palette_dma;
- } else {
- fbi->dmadesc_palette_cpu->fdadr = fbi->dmadesc_fbhigh_dma;
- fbi->dmadesc_fbhigh_cpu->fdadr = fbi->dmadesc_palette_dma;
- fbi->fdadr0 = fbi->dmadesc_palette_dma; /* flips back and forth between pal and fbhigh */
+ fbi->reg_lccr0 = fbi->lccr0 |
+ (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM |
+ LCCR0_QDM | LCCR0_BM | LCCR0_OUM);
+
+ fbi->reg_lccr3 |= pxafb_bpp_to_lccr3(var);
+
+ nbytes = var->yres * fbi->fb.fix.line_length;
+
+ if ((fbi->lccr0 & LCCR0_SDS) == LCCR0_Dual) {
+ nbytes = nbytes / 2;
+ setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes, nbytes);
}
-#if 0
- pr_debug("fbi->dmadesc_fblow_cpu = 0x%p\n", fbi->dmadesc_fblow_cpu);
- pr_debug("fbi->dmadesc_fbhigh_cpu = 0x%p\n", fbi->dmadesc_fbhigh_cpu);
- pr_debug("fbi->dmadesc_palette_cpu = 0x%p\n", fbi->dmadesc_palette_cpu);
- pr_debug("fbi->dmadesc_fblow_dma = 0x%x\n", fbi->dmadesc_fblow_dma);
- pr_debug("fbi->dmadesc_fbhigh_dma = 0x%x\n", fbi->dmadesc_fbhigh_dma);
- pr_debug("fbi->dmadesc_palette_dma = 0x%x\n", fbi->dmadesc_palette_dma);
+ if ((var->bits_per_pixel >= 16) || (fbi->lccr0 & LCCR0_LCDT))
+ setup_frame_dma(fbi, DMA_BASE, PAL_NONE, 0, nbytes);
+ else
+ setup_frame_dma(fbi, DMA_BASE, PAL_BASE, 0, nbytes);
- pr_debug("fbi->dmadesc_fblow_cpu->fdadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fdadr);
- pr_debug("fbi->dmadesc_fbhigh_cpu->fdadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fdadr);
- pr_debug("fbi->dmadesc_palette_cpu->fdadr = 0x%x\n", fbi->dmadesc_palette_cpu->fdadr);
-
- pr_debug("fbi->dmadesc_fblow_cpu->fsadr = 0x%x\n", fbi->dmadesc_fblow_cpu->fsadr);
- pr_debug("fbi->dmadesc_fbhigh_cpu->fsadr = 0x%x\n", fbi->dmadesc_fbhigh_cpu->fsadr);
- pr_debug("fbi->dmadesc_palette_cpu->fsadr = 0x%x\n", fbi->dmadesc_palette_cpu->fsadr);
-
- pr_debug("fbi->dmadesc_fblow_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fblow_cpu->ldcmd);
- pr_debug("fbi->dmadesc_fbhigh_cpu->ldcmd = 0x%x\n", fbi->dmadesc_fbhigh_cpu->ldcmd);
- pr_debug("fbi->dmadesc_palette_cpu->ldcmd = 0x%x\n", fbi->dmadesc_palette_cpu->ldcmd);
-#endif
-
- fbi->reg_lccr0 = new_regs.lccr0;
- fbi->reg_lccr1 = new_regs.lccr1;
- fbi->reg_lccr2 = new_regs.lccr2;
- fbi->reg_lccr3 = new_regs.lccr3;
- fbi->reg_lccr4 = LCCR4 & (~LCCR4_PAL_FOR_MASK);
+ fbi->reg_lccr4 = lcd_readl(fbi, LCCR4) & ~LCCR4_PAL_FOR_MASK;
fbi->reg_lccr4 |= (fbi->lccr4 & LCCR4_PAL_FOR_MASK);
- set_hsync_time(fbi, pcd);
local_irq_restore(flags);
/*
* Only update the registers if the controller is enabled
* and something has changed.
*/
- if ((LCCR0 != fbi->reg_lccr0) || (LCCR1 != fbi->reg_lccr1) ||
- (LCCR2 != fbi->reg_lccr2) || (LCCR3 != fbi->reg_lccr3) ||
- (FDADR0 != fbi->fdadr0) || (FDADR1 != fbi->fdadr1))
+ if ((lcd_readl(fbi, LCCR0) != fbi->reg_lccr0) ||
+ (lcd_readl(fbi, LCCR1) != fbi->reg_lccr1) ||
+ (lcd_readl(fbi, LCCR2) != fbi->reg_lccr2) ||
+ (lcd_readl(fbi, LCCR3) != fbi->reg_lccr3) ||
+ (lcd_readl(fbi, FDADR0) != fbi->fdadr[0]) ||
+ (lcd_readl(fbi, FDADR1) != fbi->fdadr[1]))
pxafb_schedule_work(fbi, C_REENABLE);
return 0;
@@ -773,8 +919,8 @@
{
pr_debug("pxafb: backlight o%s\n", on ? "n" : "ff");
- if (pxafb_backlight_power)
- pxafb_backlight_power(on);
+ if (pxafb_backlight_power)
+ pxafb_backlight_power(on);
}
static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
@@ -788,11 +934,11 @@
static void pxafb_setup_gpio(struct pxafb_info *fbi)
{
int gpio, ldd_bits;
- unsigned int lccr0 = fbi->lccr0;
+ unsigned int lccr0 = fbi->lccr0;
/*
* setup is based on type of panel supported
- */
+ */
/* 4 bit interface */
if ((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
@@ -801,21 +947,25 @@
ldd_bits = 4;
/* 8 bit interface */
- else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
- ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
- ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
- (lccr0 & LCCR0_PAS) == LCCR0_Pas && (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
+ else if (((lccr0 & LCCR0_CMS) == LCCR0_Mono &&
+ ((lccr0 & LCCR0_SDS) == LCCR0_Dual ||
+ (lccr0 & LCCR0_DPD) == LCCR0_8PixMono)) ||
+ ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
+ (lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+ (lccr0 & LCCR0_SDS) == LCCR0_Sngl))
ldd_bits = 8;
/* 16 bit interface */
else if ((lccr0 & LCCR0_CMS) == LCCR0_Color &&
- ((lccr0 & LCCR0_SDS) == LCCR0_Dual || (lccr0 & LCCR0_PAS) == LCCR0_Act))
+ ((lccr0 & LCCR0_SDS) == LCCR0_Dual ||
+ (lccr0 & LCCR0_PAS) == LCCR0_Act))
ldd_bits = 16;
else {
- printk(KERN_ERR "pxafb_setup_gpio: unable to determine bits per pixel\n");
+ printk(KERN_ERR "pxafb_setup_gpio: unable to determine "
+ "bits per pixel\n");
return;
- }
+ }
for (gpio = 58; ldd_bits; gpio++, ldd_bits--)
pxa_gpio_mode(gpio | GPIO_ALT_FN_2_OUT);
@@ -828,8 +978,8 @@
static void pxafb_enable_controller(struct pxafb_info *fbi)
{
pr_debug("pxafb: Enabling LCD controller\n");
- pr_debug("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr0);
- pr_debug("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr1);
+ pr_debug("fdadr0 0x%08x\n", (unsigned int) fbi->fdadr[0]);
+ pr_debug("fdadr1 0x%08x\n", (unsigned int) fbi->fdadr[1]);
pr_debug("reg_lccr0 0x%08x\n", (unsigned int) fbi->reg_lccr0);
pr_debug("reg_lccr1 0x%08x\n", (unsigned int) fbi->reg_lccr1);
pr_debug("reg_lccr2 0x%08x\n", (unsigned int) fbi->reg_lccr2);
@@ -838,40 +988,40 @@
/* enable LCD controller clock */
clk_enable(fbi->clk);
+ if (fbi->lccr0 & LCCR0_LCDT)
+ return;
+
/* Sequence from 11.7.10 */
- LCCR3 = fbi->reg_lccr3;
- LCCR2 = fbi->reg_lccr2;
- LCCR1 = fbi->reg_lccr1;
- LCCR0 = fbi->reg_lccr0 & ~LCCR0_ENB;
+ lcd_writel(fbi, LCCR3, fbi->reg_lccr3);
+ lcd_writel(fbi, LCCR2, fbi->reg_lccr2);
+ lcd_writel(fbi, LCCR1, fbi->reg_lccr1);
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB);
- FDADR0 = fbi->fdadr0;
- FDADR1 = fbi->fdadr1;
- LCCR0 |= LCCR0_ENB;
-
- pr_debug("FDADR0 0x%08x\n", (unsigned int) FDADR0);
- pr_debug("FDADR1 0x%08x\n", (unsigned int) FDADR1);
- pr_debug("LCCR0 0x%08x\n", (unsigned int) LCCR0);
- pr_debug("LCCR1 0x%08x\n", (unsigned int) LCCR1);
- pr_debug("LCCR2 0x%08x\n", (unsigned int) LCCR2);
- pr_debug("LCCR3 0x%08x\n", (unsigned int) LCCR3);
- pr_debug("LCCR4 0x%08x\n", (unsigned int) LCCR4);
+ lcd_writel(fbi, FDADR0, fbi->fdadr[0]);
+ lcd_writel(fbi, FDADR1, fbi->fdadr[1]);
+ lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB);
}
static void pxafb_disable_controller(struct pxafb_info *fbi)
{
- DECLARE_WAITQUEUE(wait, current);
+ uint32_t lccr0;
- pr_debug("pxafb: disabling LCD controller\n");
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ if (fbi->lccr0 & LCCR0_LCDT) {
+ wait_for_completion_timeout(&fbi->refresh_done,
+ 200 * HZ / 1000);
+ return;
+ }
+#endif
- set_current_state(TASK_UNINTERRUPTIBLE);
- add_wait_queue(&fbi->ctrlr_wait, &wait);
+ /* Clear LCD Status Register */
+ lcd_writel(fbi, LCSR, 0xffffffff);
- LCSR = 0xffffffff; /* Clear LCD Status Register */
- LCCR0 &= ~LCCR0_LDM; /* Enable LCD Disable Done Interrupt */
- LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */
+ lccr0 = lcd_readl(fbi, LCCR0) & ~LCCR0_LDM;
+ lcd_writel(fbi, LCCR0, lccr0);
+ lcd_writel(fbi, LCCR0, lccr0 | LCCR0_DIS);
- schedule_timeout(200 * HZ / 1000);
- remove_wait_queue(&fbi->ctrlr_wait, &wait);
+ wait_for_completion_timeout(&fbi->disable_done, 200 * HZ / 1000);
/* disable LCD controller clock */
clk_disable(fbi->clk);
@@ -883,14 +1033,20 @@
static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
{
struct pxafb_info *fbi = dev_id;
- unsigned int lcsr = LCSR;
+ unsigned int lccr0, lcsr = lcd_readl(fbi, LCSR);
if (lcsr & LCSR_LDD) {
- LCCR0 |= LCCR0_LDM;
- wake_up(&fbi->ctrlr_wait);
+ lccr0 = lcd_readl(fbi, LCCR0);
+ lcd_writel(fbi, LCCR0, lccr0 | LCCR0_LDM);
+ complete(&fbi->disable_done);
}
- LCSR = lcsr;
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ if (lcsr & LCSR_CMD_INT)
+ complete(&fbi->command_done);
+#endif
+
+ lcd_writel(fbi, LCSR, lcsr);
return IRQ_HANDLED;
}
@@ -921,7 +1077,7 @@
*/
if (old_state != C_DISABLE && old_state != C_DISABLE_PM) {
fbi->state = state;
- //TODO __pxafb_lcd_power(fbi, 0);
+ /* TODO __pxafb_lcd_power(fbi, 0); */
pxafb_disable_controller(fbi);
}
break;
@@ -948,7 +1104,7 @@
if (old_state == C_DISABLE_CLKCHANGE) {
fbi->state = C_ENABLE;
pxafb_enable_controller(fbi);
- //TODO __pxafb_lcd_power(fbi, 1);
+ /* TODO __pxafb_lcd_power(fbi, 1); */
}
break;
@@ -1019,7 +1175,7 @@
pxafb_freq_transition(struct notifier_block *nb, unsigned long val, void *data)
{
struct pxafb_info *fbi = TO_INF(nb, freq_transition);
- //TODO struct cpufreq_freqs *f = data;
+ /* TODO struct cpufreq_freqs *f = data; */
u_int pcd;
switch (val) {
@@ -1030,7 +1186,8 @@
case CPUFREQ_POSTCHANGE:
pcd = get_pcd(fbi, fbi->fb.var.pixclock);
set_hsync_time(fbi, pcd);
- fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) | LCCR3_PixClkDiv(pcd);
+ fbi->reg_lccr3 = (fbi->reg_lccr3 & ~0xff) |
+ LCCR3_PixClkDiv(pcd);
set_ctrlr_state(fbi, C_ENABLE_CLKCHANGE);
break;
}
@@ -1050,18 +1207,8 @@
pr_debug("min dma period: %d ps, "
"new clock %d kHz\n", pxafb_display_dma_period(var),
policy->max);
- // TODO: fill in min/max values
+ /* TODO: fill in min/max values */
break;
-#if 0
- case CPUFREQ_NOTIFY:
- printk(KERN_ERR "%s: got CPUFREQ_NOTIFY\n", __FUNCTION__);
- do {} while(0);
- /* todo: panic if min/max values aren't fulfilled
- * [can't really happen unless there's a bug in the
- * CPU policy verification process *
- */
- break;
-#endif
}
return 0;
}
@@ -1102,21 +1249,21 @@
*/
static int __init pxafb_map_video_memory(struct pxafb_info *fbi)
{
- u_long palette_mem_size;
-
/*
* We reserve one page for the palette, plus the size
* of the framebuffer.
*/
- fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE);
+ fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_buff));
+ fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset);
fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
&fbi->map_dma, GFP_KERNEL);
if (fbi->map_cpu) {
/* prevent initial garbage on screen */
memset(fbi->map_cpu, 0, fbi->map_size);
- fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE;
- fbi->screen_dma = fbi->map_dma + PAGE_SIZE;
+ fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset;
+ fbi->screen_dma = fbi->map_dma + fbi->video_offset;
+
/*
* FIXME: this is actually the wrong thing to place in
* smem_start. But fbdev suffers from the problem that
@@ -1126,27 +1273,86 @@
fbi->fb.fix.smem_start = fbi->screen_dma;
fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16;
- if ((fbi->lccr4 & LCCR4_PAL_FOR_MASK) == LCCR4_PAL_FOR_0)
- palette_mem_size = fbi->palette_size * sizeof(u16);
- else
- palette_mem_size = fbi->palette_size * sizeof(u32);
+ fbi->dma_buff = (void *) fbi->map_cpu;
+ fbi->dma_buff_phys = fbi->map_dma;
+ fbi->palette_cpu = (u16 *) fbi->dma_buff->palette;
- pr_debug("pxafb: palette_mem_size = 0x%08lx\n", palette_mem_size);
-
- fbi->palette_cpu = (u16 *)(fbi->map_cpu + PAGE_SIZE - palette_mem_size);
- fbi->palette_dma = fbi->map_dma + PAGE_SIZE - palette_mem_size;
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff;
+ fbi->n_smart_cmds = 0;
+#endif
}
return fbi->map_cpu ? 0 : -ENOMEM;
}
+static void pxafb_decode_mode_info(struct pxafb_info *fbi,
+ struct pxafb_mode_info *modes,
+ unsigned int num_modes)
+{
+ unsigned int i, smemlen;
+
+ pxafb_setmode(&fbi->fb.var, &modes[0]);
+
+ for (i = 0; i < num_modes; i++) {
+ smemlen = modes[i].xres * modes[i].yres * modes[i].bpp / 8;
+ if (smemlen > fbi->fb.fix.smem_len)
+ fbi->fb.fix.smem_len = smemlen;
+ }
+}
+
+static int pxafb_decode_mach_info(struct pxafb_info *fbi,
+ struct pxafb_mach_info *inf)
+{
+ unsigned int lcd_conn = inf->lcd_conn;
+
+ fbi->cmap_inverse = inf->cmap_inverse;
+ fbi->cmap_static = inf->cmap_static;
+
+ switch (lcd_conn & 0xf) {
+ case LCD_TYPE_MONO_STN:
+ fbi->lccr0 = LCCR0_CMS;
+ break;
+ case LCD_TYPE_MONO_DSTN:
+ fbi->lccr0 = LCCR0_CMS | LCCR0_SDS;
+ break;
+ case LCD_TYPE_COLOR_STN:
+ fbi->lccr0 = 0;
+ break;
+ case LCD_TYPE_COLOR_DSTN:
+ fbi->lccr0 = LCCR0_SDS;
+ break;
+ case LCD_TYPE_COLOR_TFT:
+ fbi->lccr0 = LCCR0_PAS;
+ break;
+ case LCD_TYPE_SMART_PANEL:
+ fbi->lccr0 = LCCR0_LCDT | LCCR0_PAS;
+ break;
+ default:
+ /* fall back to backward compatibility way */
+ fbi->lccr0 = inf->lccr0;
+ fbi->lccr3 = inf->lccr3;
+ fbi->lccr4 = inf->lccr4;
+ return -EINVAL;
+ }
+
+ if (lcd_conn == LCD_MONO_STN_8BPP)
+ fbi->lccr0 |= LCCR0_DPD;
+
+ fbi->lccr3 = LCCR3_Acb((inf->lcd_conn >> 10) & 0xff);
+ fbi->lccr3 |= (lcd_conn & LCD_BIAS_ACTIVE_LOW) ? LCCR3_OEP : 0;
+ fbi->lccr3 |= (lcd_conn & LCD_PCLK_EDGE_FALL) ? LCCR3_PCP : 0;
+
+ pxafb_decode_mode_info(fbi, inf->modes, inf->num_modes);
+ return 0;
+}
+
static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
{
struct pxafb_info *fbi;
void *addr;
struct pxafb_mach_info *inf = dev->platform_data;
struct pxafb_mode_info *mode = inf->modes;
- int i, smemlen;
/* Alloc the pxafb_info and pseudo_palette in one step */
fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
@@ -1186,187 +1392,233 @@
addr = addr + sizeof(struct pxafb_info);
fbi->fb.pseudo_palette = addr;
- pxafb_setmode(&fbi->fb.var, mode);
+ fbi->state = C_STARTUP;
+ fbi->task_state = (u_char)-1;
- fbi->cmap_inverse = inf->cmap_inverse;
- fbi->cmap_static = inf->cmap_static;
-
- fbi->lccr0 = inf->lccr0;
- fbi->lccr3 = inf->lccr3;
- fbi->lccr4 = inf->lccr4;
- fbi->state = C_STARTUP;
- fbi->task_state = (u_char)-1;
-
- for (i = 0; i < inf->num_modes; i++) {
- smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
- if (smemlen > fbi->fb.fix.smem_len)
- fbi->fb.fix.smem_len = smemlen;
- }
+ pxafb_decode_mach_info(fbi, inf);
init_waitqueue_head(&fbi->ctrlr_wait);
INIT_WORK(&fbi->task, pxafb_task);
init_MUTEX(&fbi->ctrlr_sem);
+ init_completion(&fbi->disable_done);
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ init_completion(&fbi->command_done);
+ init_completion(&fbi->refresh_done);
+#endif
return fbi;
}
#ifdef CONFIG_FB_PXA_PARAMETERS
-static int __init pxafb_parse_options(struct device *dev, char *options)
+static int __init parse_opt_mode(struct device *dev, const char *this_opt)
{
struct pxafb_mach_info *inf = dev->platform_data;
- char *this_opt;
- if (!options || !*options)
- return 0;
+ const char *name = this_opt+5;
+ unsigned int namelen = strlen(name);
+ int res_specified = 0, bpp_specified = 0;
+ unsigned int xres = 0, yres = 0, bpp = 0;
+ int yres_specified = 0;
+ int i;
+ for (i = namelen-1; i >= 0; i--) {
+ switch (name[i]) {
+ case '-':
+ namelen = i;
+ if (!bpp_specified && !yres_specified) {
+ bpp = simple_strtoul(&name[i+1], NULL, 0);
+ bpp_specified = 1;
+ } else
+ goto done;
+ break;
+ case 'x':
+ if (!yres_specified) {
+ yres = simple_strtoul(&name[i+1], NULL, 0);
+ yres_specified = 1;
+ } else
+ goto done;
+ break;
+ case '0' ... '9':
+ break;
+ default:
+ goto done;
+ }
+ }
+ if (i < 0 && yres_specified) {
+ xres = simple_strtoul(name, NULL, 0);
+ res_specified = 1;
+ }
+done:
+ if (res_specified) {
+ dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
+ inf->modes[0].xres = xres; inf->modes[0].yres = yres;
+ }
+ if (bpp_specified)
+ switch (bpp) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ case 16:
+ inf->modes[0].bpp = bpp;
+ dev_info(dev, "overriding bit depth: %d\n", bpp);
+ break;
+ default:
+ dev_err(dev, "Depth %d is not valid\n", bpp);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int __init parse_opt(struct device *dev, char *this_opt)
+{
+ struct pxafb_mach_info *inf = dev->platform_data;
+ struct pxafb_mode_info *mode = &inf->modes[0];
+ char s[64];
+
+ s[0] = '\0';
+
+ if (!strncmp(this_opt, "mode:", 5)) {
+ return parse_opt_mode(dev, this_opt);
+ } else if (!strncmp(this_opt, "pixclock:", 9)) {
+ mode->pixclock = simple_strtoul(this_opt+9, NULL, 0);
+ sprintf(s, "pixclock: %ld\n", mode->pixclock);
+ } else if (!strncmp(this_opt, "left:", 5)) {
+ mode->left_margin = simple_strtoul(this_opt+5, NULL, 0);
+ sprintf(s, "left: %u\n", mode->left_margin);
+ } else if (!strncmp(this_opt, "right:", 6)) {
+ mode->right_margin = simple_strtoul(this_opt+6, NULL, 0);
+ sprintf(s, "right: %u\n", mode->right_margin);
+ } else if (!strncmp(this_opt, "upper:", 6)) {
+ mode->upper_margin = simple_strtoul(this_opt+6, NULL, 0);
+ sprintf(s, "upper: %u\n", mode->upper_margin);
+ } else if (!strncmp(this_opt, "lower:", 6)) {
+ mode->lower_margin = simple_strtoul(this_opt+6, NULL, 0);
+ sprintf(s, "lower: %u\n", mode->lower_margin);
+ } else if (!strncmp(this_opt, "hsynclen:", 9)) {
+ mode->hsync_len = simple_strtoul(this_opt+9, NULL, 0);
+ sprintf(s, "hsynclen: %u\n", mode->hsync_len);
+ } else if (!strncmp(this_opt, "vsynclen:", 9)) {
+ mode->vsync_len = simple_strtoul(this_opt+9, NULL, 0);
+ sprintf(s, "vsynclen: %u\n", mode->vsync_len);
+ } else if (!strncmp(this_opt, "hsync:", 6)) {
+ if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+ sprintf(s, "hsync: Active Low\n");
+ mode->sync &= ~FB_SYNC_HOR_HIGH_ACT;
+ } else {
+ sprintf(s, "hsync: Active High\n");
+ mode->sync |= FB_SYNC_HOR_HIGH_ACT;
+ }
+ } else if (!strncmp(this_opt, "vsync:", 6)) {
+ if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
+ sprintf(s, "vsync: Active Low\n");
+ mode->sync &= ~FB_SYNC_VERT_HIGH_ACT;
+ } else {
+ sprintf(s, "vsync: Active High\n");
+ mode->sync |= FB_SYNC_VERT_HIGH_ACT;
+ }
+ } else if (!strncmp(this_opt, "dpc:", 4)) {
+ if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
+ sprintf(s, "double pixel clock: false\n");
+ inf->lccr3 &= ~LCCR3_DPC;
+ } else {
+ sprintf(s, "double pixel clock: true\n");
+ inf->lccr3 |= LCCR3_DPC;
+ }
+ } else if (!strncmp(this_opt, "outputen:", 9)) {
+ if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
+ sprintf(s, "output enable: active low\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
+ } else {
+ sprintf(s, "output enable: active high\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
+ }
+ } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
+ if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
+ sprintf(s, "pixel clock polarity: falling edge\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
+ } else {
+ sprintf(s, "pixel clock polarity: rising edge\n");
+ inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
+ }
+ } else if (!strncmp(this_opt, "color", 5)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
+ } else if (!strncmp(this_opt, "mono", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
+ } else if (!strncmp(this_opt, "active", 6)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
+ } else if (!strncmp(this_opt, "passive", 7)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
+ } else if (!strncmp(this_opt, "single", 6)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
+ } else if (!strncmp(this_opt, "dual", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
+ } else if (!strncmp(this_opt, "4pix", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
+ } else if (!strncmp(this_opt, "8pix", 4)) {
+ inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
+ } else {
+ dev_err(dev, "unknown option: %s\n", this_opt);
+ return -EINVAL;
+ }
+
+ if (s[0] != '\0')
+ dev_info(dev, "override %s", s);
+
+ return 0;
+}
+
+static int __init pxafb_parse_options(struct device *dev, char *options)
+{
+ char *this_opt;
+ int ret;
+
+ if (!options || !*options)
+ return 0;
dev_dbg(dev, "options are \"%s\"\n", options ? options : "null");
/* could be made table driven or similar?... */
- while ((this_opt = strsep(&options, ",")) != NULL) {
- if (!strncmp(this_opt, "mode:", 5)) {
- const char *name = this_opt+5;
- unsigned int namelen = strlen(name);
- int res_specified = 0, bpp_specified = 0;
- unsigned int xres = 0, yres = 0, bpp = 0;
- int yres_specified = 0;
- int i;
- for (i = namelen-1; i >= 0; i--) {
- switch (name[i]) {
- case '-':
- namelen = i;
- if (!bpp_specified && !yres_specified) {
- bpp = simple_strtoul(&name[i+1], NULL, 0);
- bpp_specified = 1;
- } else
- goto done;
- break;
- case 'x':
- if (!yres_specified) {
- yres = simple_strtoul(&name[i+1], NULL, 0);
- yres_specified = 1;
- } else
- goto done;
- break;
- case '0' ... '9':
- break;
- default:
- goto done;
- }
- }
- if (i < 0 && yres_specified) {
- xres = simple_strtoul(name, NULL, 0);
- res_specified = 1;
- }
- done:
- if (res_specified) {
- dev_info(dev, "overriding resolution: %dx%d\n", xres, yres);
- inf->modes[0].xres = xres; inf->modes[0].yres = yres;
- }
- if (bpp_specified)
- switch (bpp) {
- case 1:
- case 2:
- case 4:
- case 8:
- case 16:
- inf->modes[0].bpp = bpp;
- dev_info(dev, "overriding bit depth: %d\n", bpp);
- break;
- default:
- dev_err(dev, "Depth %d is not valid\n", bpp);
- }
- } else if (!strncmp(this_opt, "pixclock:", 9)) {
- inf->modes[0].pixclock = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override pixclock: %ld\n", inf->modes[0].pixclock);
- } else if (!strncmp(this_opt, "left:", 5)) {
- inf->modes[0].left_margin = simple_strtoul(this_opt+5, NULL, 0);
- dev_info(dev, "override left: %u\n", inf->modes[0].left_margin);
- } else if (!strncmp(this_opt, "right:", 6)) {
- inf->modes[0].right_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override right: %u\n", inf->modes[0].right_margin);
- } else if (!strncmp(this_opt, "upper:", 6)) {
- inf->modes[0].upper_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override upper: %u\n", inf->modes[0].upper_margin);
- } else if (!strncmp(this_opt, "lower:", 6)) {
- inf->modes[0].lower_margin = simple_strtoul(this_opt+6, NULL, 0);
- dev_info(dev, "override lower: %u\n", inf->modes[0].lower_margin);
- } else if (!strncmp(this_opt, "hsynclen:", 9)) {
- inf->modes[0].hsync_len = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override hsynclen: %u\n", inf->modes[0].hsync_len);
- } else if (!strncmp(this_opt, "vsynclen:", 9)) {
- inf->modes[0].vsync_len = simple_strtoul(this_opt+9, NULL, 0);
- dev_info(dev, "override vsynclen: %u\n", inf->modes[0].vsync_len);
- } else if (!strncmp(this_opt, "hsync:", 6)) {
- if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
- dev_info(dev, "override hsync: Active Low\n");
- inf->modes[0].sync &= ~FB_SYNC_HOR_HIGH_ACT;
- } else {
- dev_info(dev, "override hsync: Active High\n");
- inf->modes[0].sync |= FB_SYNC_HOR_HIGH_ACT;
- }
- } else if (!strncmp(this_opt, "vsync:", 6)) {
- if (simple_strtoul(this_opt+6, NULL, 0) == 0) {
- dev_info(dev, "override vsync: Active Low\n");
- inf->modes[0].sync &= ~FB_SYNC_VERT_HIGH_ACT;
- } else {
- dev_info(dev, "override vsync: Active High\n");
- inf->modes[0].sync |= FB_SYNC_VERT_HIGH_ACT;
- }
- } else if (!strncmp(this_opt, "dpc:", 4)) {
- if (simple_strtoul(this_opt+4, NULL, 0) == 0) {
- dev_info(dev, "override double pixel clock: false\n");
- inf->lccr3 &= ~LCCR3_DPC;
- } else {
- dev_info(dev, "override double pixel clock: true\n");
- inf->lccr3 |= LCCR3_DPC;
- }
- } else if (!strncmp(this_opt, "outputen:", 9)) {
- if (simple_strtoul(this_opt+9, NULL, 0) == 0) {
- dev_info(dev, "override output enable: active low\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnL;
- } else {
- dev_info(dev, "override output enable: active high\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_OEP) | LCCR3_OutEnH;
- }
- } else if (!strncmp(this_opt, "pixclockpol:", 12)) {
- if (simple_strtoul(this_opt+12, NULL, 0) == 0) {
- dev_info(dev, "override pixel clock polarity: falling edge\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixFlEdg;
- } else {
- dev_info(dev, "override pixel clock polarity: rising edge\n");
- inf->lccr3 = (inf->lccr3 & ~LCCR3_PCP) | LCCR3_PixRsEdg;
- }
- } else if (!strncmp(this_opt, "color", 5)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Color;
- } else if (!strncmp(this_opt, "mono", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_CMS) | LCCR0_Mono;
- } else if (!strncmp(this_opt, "active", 6)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Act;
- } else if (!strncmp(this_opt, "passive", 7)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_PAS) | LCCR0_Pas;
- } else if (!strncmp(this_opt, "single", 6)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Sngl;
- } else if (!strncmp(this_opt, "dual", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_SDS) | LCCR0_Dual;
- } else if (!strncmp(this_opt, "4pix", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_4PixMono;
- } else if (!strncmp(this_opt, "8pix", 4)) {
- inf->lccr0 = (inf->lccr0 & ~LCCR0_DPD) | LCCR0_8PixMono;
- } else {
- dev_err(dev, "unknown option: %s\n", this_opt);
- return -EINVAL;
- }
- }
- return 0;
-
+ while ((this_opt = strsep(&options, ",")) != NULL) {
+ ret = parse_opt(dev, this_opt);
+ if (ret)
+ return ret;
+ }
+ return 0;
}
+
+static char g_options[256] __devinitdata = "";
+
+#ifndef CONFIG_MODULES
+static int __devinit pxafb_setup_options(void)
+{
+ char *options = NULL;
+
+ if (fb_get_options("pxafb", &options))
+ return -ENODEV;
+
+ if (options)
+ strlcpy(g_options, options, sizeof(g_options));
+
+ return 0;
+}
+#else
+#define pxafb_setup_options() (0)
+
+module_param_string(options, g_options, sizeof(g_options), 0);
+MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
+#endif
+
+#else
+#define pxafb_parse_options(...) (0)
+#define pxafb_setup_options() (0)
#endif
static int __init pxafb_probe(struct platform_device *dev)
{
struct pxafb_info *fbi;
struct pxafb_mach_info *inf;
- int ret;
+ struct resource *r;
+ int irq, ret;
dev_dbg(&dev->dev, "pxafb_probe\n");
@@ -1376,38 +1628,45 @@
if (!inf)
goto failed;
-#ifdef CONFIG_FB_PXA_PARAMETERS
ret = pxafb_parse_options(&dev->dev, g_options);
if (ret < 0)
goto failed;
-#endif
#ifdef DEBUG_VAR
- /* Check for various illegal bit-combinations. Currently only
+ /* Check for various illegal bit-combinations. Currently only
* a warning is given. */
- if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
- dev_warn(&dev->dev, "machine LCCR0 setting contains illegal bits: %08x\n",
- inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
- if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
- dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n",
- inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
- if (inf->lccr0 & LCCR0_DPD &&
+ if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
+ dev_warn(&dev->dev, "machine LCCR0 setting contains "
+ "illegal bits: %08x\n",
+ inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
+ if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
+ dev_warn(&dev->dev, "machine LCCR3 setting contains "
+ "illegal bits: %08x\n",
+ inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
+ if (inf->lccr0 & LCCR0_DPD &&
((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
(inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
(inf->lccr0 & LCCR0_CMS) != LCCR0_Mono))
- dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is only valid in passive mono"
- " single panel mode\n");
- if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
+ dev_warn(&dev->dev, "Double Pixel Data (DPD) mode is "
+ "only valid in passive mono"
+ " single panel mode\n");
+ if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Act &&
(inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
- dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
- if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
- (inf->modes->upper_margin || inf->modes->lower_margin))
- dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n");
+ dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
+ if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
+ (inf->modes->upper_margin || inf->modes->lower_margin))
+ dev_warn(&dev->dev, "Upper and lower margins must be 0 in "
+ "passive mode\n");
#endif
- dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->modes->xres, inf->modes->yres, inf->modes->bpp);
- if (inf->modes->xres == 0 || inf->modes->yres == 0 || inf->modes->bpp == 0) {
+ dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",
+ inf->modes->xres,
+ inf->modes->yres,
+ inf->modes->bpp);
+ if (inf->modes->xres == 0 ||
+ inf->modes->yres == 0 ||
+ inf->modes->bpp == 0) {
dev_err(&dev->dev, "Invalid resolution or bit depth\n");
ret = -EINVAL;
goto failed;
@@ -1416,26 +1675,62 @@
pxafb_lcd_power = inf->pxafb_lcd_power;
fbi = pxafb_init_fbinfo(&dev->dev);
if (!fbi) {
+ /* only reason for pxafb_init_fbinfo to fail is kmalloc */
dev_err(&dev->dev, "Failed to initialize framebuffer device\n");
- ret = -ENOMEM; // only reason for pxafb_init_fbinfo to fail is kmalloc
+ ret = -ENOMEM;
goto failed;
}
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (r == NULL) {
+ dev_err(&dev->dev, "no I/O memory resource defined\n");
+ ret = -ENODEV;
+ goto failed;
+ }
+
+ r = request_mem_region(r->start, r->end - r->start + 1, dev->name);
+ if (r == NULL) {
+ dev_err(&dev->dev, "failed to request I/O memory\n");
+ ret = -EBUSY;
+ goto failed;
+ }
+
+ fbi->mmio_base = ioremap(r->start, r->end - r->start + 1);
+ if (fbi->mmio_base == NULL) {
+ dev_err(&dev->dev, "failed to map I/O memory\n");
+ ret = -EBUSY;
+ goto failed_free_res;
+ }
+
/* Initialize video memory */
ret = pxafb_map_video_memory(fbi);
if (ret) {
dev_err(&dev->dev, "Failed to allocate video RAM: %d\n", ret);
ret = -ENOMEM;
- goto failed;
+ goto failed_free_io;
}
- ret = request_irq(IRQ_LCD, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ dev_err(&dev->dev, "no IRQ defined\n");
+ ret = -ENODEV;
+ goto failed_free_mem;
+ }
+
+ ret = request_irq(irq, pxafb_handle_irq, IRQF_DISABLED, "LCD", fbi);
if (ret) {
dev_err(&dev->dev, "request_irq failed: %d\n", ret);
ret = -EBUSY;
- goto failed;
+ goto failed_free_mem;
}
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ ret = pxafb_smart_init(fbi);
+ if (ret) {
+ dev_err(&dev->dev, "failed to initialize smartpanel\n");
+ goto failed_free_irq;
+ }
+#endif
/*
* This makes sure that our colour bitfield
* descriptors are correctly initialised.
@@ -1447,19 +1742,18 @@
ret = register_framebuffer(&fbi->fb);
if (ret < 0) {
- dev_err(&dev->dev, "Failed to register framebuffer device: %d\n", ret);
- goto failed;
+ dev_err(&dev->dev,
+ "Failed to register framebuffer device: %d\n", ret);
+ goto failed_free_irq;
}
-#ifdef CONFIG_PM
- // TODO
-#endif
-
#ifdef CONFIG_CPU_FREQ
fbi->freq_transition.notifier_call = pxafb_freq_transition;
fbi->freq_policy.notifier_call = pxafb_freq_policy;
- cpufreq_register_notifier(&fbi->freq_transition, CPUFREQ_TRANSITION_NOTIFIER);
- cpufreq_register_notifier(&fbi->freq_policy, CPUFREQ_POLICY_NOTIFIER);
+ cpufreq_register_notifier(&fbi->freq_transition,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ cpufreq_register_notifier(&fbi->freq_policy,
+ CPUFREQ_POLICY_NOTIFIER);
#endif
/*
@@ -1469,6 +1763,15 @@
return 0;
+failed_free_irq:
+ free_irq(irq, fbi);
+failed_free_res:
+ release_mem_region(r->start, r->end - r->start + 1);
+failed_free_io:
+ iounmap(fbi->mmio_base);
+failed_free_mem:
+ dma_free_writecombine(&dev->dev, fbi->map_size,
+ fbi->map_cpu, fbi->map_dma);
failed:
platform_set_drvdata(dev, NULL);
kfree(fbi);
@@ -1477,40 +1780,18 @@
static struct platform_driver pxafb_driver = {
.probe = pxafb_probe,
-#ifdef CONFIG_PM
.suspend = pxafb_suspend,
.resume = pxafb_resume,
-#endif
.driver = {
.name = "pxa2xx-fb",
},
};
-#ifndef MODULE
-static int __devinit pxafb_setup(char *options)
-{
-# ifdef CONFIG_FB_PXA_PARAMETERS
- if (options)
- strlcpy(g_options, options, sizeof(g_options));
-# endif
- return 0;
-}
-#else
-# ifdef CONFIG_FB_PXA_PARAMETERS
-module_param_string(options, g_options, sizeof(g_options), 0);
-MODULE_PARM_DESC(options, "LCD parameters (see Documentation/fb/pxafb.txt)");
-# endif
-#endif
-
static int __devinit pxafb_init(void)
{
-#ifndef MODULE
- char *option = NULL;
+ if (pxafb_setup_options())
+ return -EINVAL;
- if (fb_get_options("pxafb", &option))
- return -ENODEV;
- pxafb_setup(option);
-#endif
return platform_driver_register(&pxafb_driver);
}
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index d920b8a..8238dc8 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -21,14 +21,6 @@
* for more details.
*/
-/* Shadows for LCD controller registers */
-struct pxafb_lcd_reg {
- unsigned int lccr0;
- unsigned int lccr1;
- unsigned int lccr2;
- unsigned int lccr3;
-};
-
/* PXA LCD DMA descriptor */
struct pxafb_dma_descriptor {
unsigned int fdadr;
@@ -37,11 +29,49 @@
unsigned int ldcmd;
};
+enum {
+ PAL_NONE = -1,
+ PAL_BASE = 0,
+ PAL_OV1 = 1,
+ PAL_OV2 = 2,
+ PAL_MAX,
+};
+
+enum {
+ DMA_BASE = 0,
+ DMA_UPPER = 0,
+ DMA_LOWER = 1,
+ DMA_OV1 = 1,
+ DMA_OV2_Y = 2,
+ DMA_OV2_Cb = 3,
+ DMA_OV2_Cr = 4,
+ DMA_CURSOR = 5,
+ DMA_CMD = 6,
+ DMA_MAX,
+};
+
+/* maximum palette size - 256 entries, each 4 bytes long */
+#define PALETTE_SIZE (256 * 4)
+#define CMD_BUFF_SIZE (1024 * 50)
+
+struct pxafb_dma_buff {
+ unsigned char palette[PAL_MAX * PALETTE_SIZE];
+ uint16_t cmd_buff[CMD_BUFF_SIZE];
+ struct pxafb_dma_descriptor pal_desc[PAL_MAX];
+ struct pxafb_dma_descriptor dma_desc[DMA_MAX];
+};
+
struct pxafb_info {
struct fb_info fb;
struct device *dev;
struct clk *clk;
+ void __iomem *mmio_base;
+
+ struct pxafb_dma_buff *dma_buff;
+ dma_addr_t dma_buff_phys;
+ dma_addr_t fdadr[DMA_MAX];
+
/*
* These are the addresses we mapped
* the framebuffer memory region to.
@@ -55,19 +85,8 @@
u_char * screen_cpu; /* virtual address of frame buffer */
dma_addr_t screen_dma; /* physical address of frame buffer */
u16 * palette_cpu; /* virtual address of palette memory */
- dma_addr_t palette_dma; /* physical address of palette memory */
u_int palette_size;
-
- /* DMA descriptors */
- struct pxafb_dma_descriptor * dmadesc_fblow_cpu;
- dma_addr_t dmadesc_fblow_dma;
- struct pxafb_dma_descriptor * dmadesc_fbhigh_cpu;
- dma_addr_t dmadesc_fbhigh_dma;
- struct pxafb_dma_descriptor * dmadesc_palette_cpu;
- dma_addr_t dmadesc_palette_dma;
-
- dma_addr_t fdadr0;
- dma_addr_t fdadr1;
+ ssize_t video_offset;
u_int lccr0;
u_int lccr3;
@@ -81,6 +100,7 @@
u_int reg_lccr2;
u_int reg_lccr3;
u_int reg_lccr4;
+ u_int reg_cmdcr;
unsigned long hsync_time;
@@ -90,6 +110,16 @@
wait_queue_head_t ctrlr_wait;
struct work_struct task;
+ struct completion disable_done;
+
+#ifdef CONFIG_FB_PXA_SMARTPANEL
+ uint16_t *smart_cmds;
+ size_t n_smart_cmds;
+ struct completion command_done;
+ struct completion refresh_done;
+ struct task_struct *smart_thread;
+#endif
+
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
struct notifier_block freq_policy;
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index b535483..1386678 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -80,19 +80,51 @@
dev->config->set_status(dev, dev->config->get_status(dev) | status);
}
+void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
+ unsigned int fbit)
+{
+ unsigned int i;
+ struct virtio_driver *drv = container_of(vdev->dev.driver,
+ struct virtio_driver, driver);
+
+ for (i = 0; i < drv->feature_table_size; i++)
+ if (drv->feature_table[i] == fbit)
+ return;
+ BUG();
+}
+EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
+
static int virtio_dev_probe(struct device *_d)
{
- int err;
+ int err, i;
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
struct virtio_driver *drv = container_of(dev->dev.driver,
struct virtio_driver, driver);
+ u32 device_features;
+ /* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER);
+
+ /* Figure out what features the device supports. */
+ device_features = dev->config->get_features(dev);
+
+ /* Features supported by both device and driver into dev->features. */
+ memset(dev->features, 0, sizeof(dev->features));
+ for (i = 0; i < drv->feature_table_size; i++) {
+ unsigned int f = drv->feature_table[i];
+ BUG_ON(f >= 32);
+ if (device_features & (1 << f))
+ set_bit(f, dev->features);
+ }
+
err = drv->probe(dev);
if (err)
add_status(dev, VIRTIO_CONFIG_S_FAILED);
- else
+ else {
add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
+ /* They should never have set feature bits beyond 32 */
+ dev->config->set_features(dev, dev->features[0]);
+ }
return err;
}
@@ -114,6 +146,8 @@
int register_virtio_driver(struct virtio_driver *driver)
{
+ /* Catch this early. */
+ BUG_ON(driver->feature_table_size && !driver->feature_table);
driver->driver.bus = &virtio_bus;
driver->driver.probe = virtio_dev_probe;
driver->driver.remove = virtio_dev_remove;
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 0b3efc3..bfef604 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -155,9 +155,9 @@
static inline s64 towards_target(struct virtio_balloon *vb)
{
u32 v;
- __virtio_config_val(vb->vdev,
- offsetof(struct virtio_balloon_config, num_pages),
- &v);
+ vb->vdev->config->get(vb->vdev,
+ offsetof(struct virtio_balloon_config, num_pages),
+ &v, sizeof(v));
return v - vb->num_pages;
}
@@ -227,7 +227,7 @@
}
vb->tell_host_first
- = vdev->config->feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+ = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
return 0;
@@ -259,7 +259,11 @@
kfree(vb);
}
+static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST };
+
static struct virtio_driver virtio_balloon = {
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
index c0df924..27e9fc9 100644
--- a/drivers/virtio/virtio_pci.c
+++ b/drivers/virtio/virtio_pci.c
@@ -87,23 +87,22 @@
return container_of(vdev, struct virtio_pci_device, vdev);
}
-/* virtio config->feature() implementation */
-static bool vp_feature(struct virtio_device *vdev, unsigned bit)
+/* virtio config->get_features() implementation */
+static u32 vp_get_features(struct virtio_device *vdev)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- u32 mask;
- /* Since this function is supposed to have the side effect of
- * enabling a queried feature, we simulate that by doing a read
- * from the host feature bitmask and then writing to the guest
- * feature bitmask */
- mask = ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
- if (mask & (1 << bit)) {
- mask |= (1 << bit);
- iowrite32(mask, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
- }
+ /* When someone needs more than 32 feature bits, we'll need to
+ * steal a bit to indicate that the rest are somewhere else. */
+ return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
- return !!(mask & (1 << bit));
+/* virtio config->set_features() implementation */
+static void vp_set_features(struct virtio_device *vdev, u32 features)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ iowrite32(features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
}
/* virtio config->get() implementation */
@@ -145,14 +144,14 @@
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
/* We should never be setting status to 0. */
BUG_ON(status == 0);
- return iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+ iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
}
static void vp_reset(struct virtio_device *vdev)
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
/* 0 status means a reset. */
- return iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+ iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
}
/* the notify function used when creating a virt queue */
@@ -293,7 +292,6 @@
}
static struct virtio_config_ops virtio_pci_config_ops = {
- .feature = vp_feature,
.get = vp_get,
.set = vp_set,
.get_status = vp_get_status,
@@ -301,6 +299,8 @@
.reset = vp_reset,
.find_vq = vp_find_vq,
.del_vq = vp_del_vq,
+ .get_features = vp_get_features,
+ .set_features = vp_set_features,
};
/* the PCI probing function */
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index c2fa5c6..937a49d 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -184,6 +184,11 @@
START_USE(vq);
+ if (unlikely(vq->broken)) {
+ END_USE(vq);
+ return NULL;
+ }
+
if (!more_used(vq)) {
pr_debug("No more buffers in queue\n");
END_USE(vq);
diff --git a/drivers/w1/w1_log.h b/drivers/w1/w1_log.h
index fe6bdf4..e6ab7cf 100644
--- a/drivers/w1/w1_log.h
+++ b/drivers/w1/w1_log.h
@@ -30,7 +30,7 @@
# define assert(expr) \
if(unlikely(!(expr))) { \
printk(KERN_ERR "Assertion failed! %s,%s,%s,line=%d\n", \
- #expr,__FILE__,__FUNCTION__,__LINE__); \
+ #expr, __FILE__, __func__, __LINE__); \
}
#endif
diff --git a/drivers/zorro/proc.c b/drivers/zorro/proc.c
index 2ce4ceb..099b6fb 100644
--- a/drivers/zorro/proc.c
+++ b/drivers/zorro/proc.c
@@ -13,6 +13,7 @@
#include <linux/types.h>
#include <linux/zorro.h>
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
@@ -76,36 +77,58 @@
}
static const struct file_operations proc_bus_zorro_operations = {
+ .owner = THIS_MODULE,
.llseek = proc_bus_zorro_lseek,
.read = proc_bus_zorro_read,
};
-static int
-get_zorro_dev_info(char *buf, char **start, off_t pos, int count)
+static void * zorro_seq_start(struct seq_file *m, loff_t *pos)
{
- u_int slot;
- off_t at = 0;
- int len, cnt;
-
- for (slot = cnt = 0; slot < zorro_num_autocon && count > cnt; slot++) {
- struct zorro_dev *z = &zorro_autocon[slot];
- len = sprintf(buf, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot,
- z->id, (unsigned long)zorro_resource_start(z),
- (unsigned long)zorro_resource_len(z),
- z->rom.er_Type);
- at += len;
- if (at >= pos) {
- if (!*start) {
- *start = buf + (pos - (at - len));
- cnt = at - pos;
- } else
- cnt += len;
- buf += len;
- }
- }
- return (count > cnt) ? cnt : count;
+ return (*pos < zorro_num_autocon) ? pos : NULL;
}
+static void * zorro_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return (*pos < zorro_num_autocon) ? pos : NULL;
+}
+
+static void zorro_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int zorro_seq_show(struct seq_file *m, void *v)
+{
+ u_int slot = *(loff_t *)v;
+ struct zorro_dev *z = &zorro_autocon[slot];
+
+ seq_printf(m, "%02x\t%08x\t%08lx\t%08lx\t%02x\n", slot, z->id,
+ (unsigned long)zorro_resource_start(z),
+ (unsigned long)zorro_resource_len(z),
+ z->rom.er_Type);
+ return 0;
+}
+
+static const struct seq_operations zorro_devices_seq_ops = {
+ .start = zorro_seq_start,
+ .next = zorro_seq_next,
+ .stop = zorro_seq_stop,
+ .show = zorro_seq_show,
+};
+
+static int zorro_devices_proc_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &zorro_devices_seq_ops);
+}
+
+static const struct file_operations zorro_devices_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = zorro_devices_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
static struct proc_dir_entry *proc_bus_zorro_dir;
static int __init zorro_proc_attach_device(u_int slot)
@@ -114,11 +137,11 @@
char name[4];
sprintf(name, "%02x", slot);
- entry = create_proc_entry(name, 0, proc_bus_zorro_dir);
+ entry = proc_create_data(name, 0, proc_bus_zorro_dir,
+ &proc_bus_zorro_operations,
+ &zorro_autocon[slot]);
if (!entry)
return -ENOMEM;
- entry->proc_fops = &proc_bus_zorro_operations;
- entry->data = &zorro_autocon[slot];
entry->size = sizeof(struct zorro_dev);
return 0;
}
@@ -128,9 +151,9 @@
u_int slot;
if (MACH_IS_AMIGA && AMIGAHW_PRESENT(ZORRO)) {
- proc_bus_zorro_dir = proc_mkdir("zorro", proc_bus);
- create_proc_info_entry("devices", 0, proc_bus_zorro_dir,
- get_zorro_dev_info);
+ proc_bus_zorro_dir = proc_mkdir("bus/zorro", NULL);
+ proc_create("devices", 0, proc_bus_zorro_dir,
+ &zorro_devices_proc_fops);
for (slot = 0; slot < zorro_num_autocon; slot++)
zorro_proc_attach_device(slot);
}
diff --git a/fs/Kconfig b/fs/Kconfig
index 2e43d46..cf12c40 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1005,7 +1005,8 @@
config HUGETLBFS
bool "HugeTLB file system support"
- depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || BROKEN
+ depends on X86 || IA64 || PPC64 || SPARC64 || (SUPERH && MMU) || \
+ (S390 && 64BIT) || BROKEN
help
hugetlbfs is a filesystem backing for HugeTLB pages, based on
ramfs. For architectures that support it, say Y here and read
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 853845a..55e8ee1 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -41,7 +41,7 @@
It is also possible to run FDPIC ELF binaries on MMU linux also.
config BINFMT_FLAT
- tristate "Kernel support for flat binaries"
+ bool "Kernel support for flat binaries"
depends on !MMU
help
Support uClinux FLAT format binaries.
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h
index 936f2af..8311575 100644
--- a/fs/adfs/adfs.h
+++ b/fs/adfs/adfs.h
@@ -75,7 +75,7 @@
/* Misc */
void __adfs_error(struct super_block *sb, const char *function,
const char *fmt, ...);
-#define adfs_error(sb, fmt...) __adfs_error(sb, __FUNCTION__, fmt)
+#define adfs_error(sb, fmt...) __adfs_error(sb, __func__, fmt)
/* super.c */
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index b9b2b27..ea7df21 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -122,9 +122,9 @@
ptr.ptr8 = bufoff(bh, i);
end.ptr8 = ptr.ptr8 + last - i;
- do
+ do {
dircheck = *ptr.ptr8++ ^ ror13(dircheck);
- while (ptr.ptr8 < end.ptr8);
+ } while (ptr.ptr8 < end.ptr8);
}
/*
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 6e0c939..1a4f092 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -325,8 +325,7 @@
pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block);
- if (block > (sector_t)0x7fffffffUL)
- BUG();
+ BUG_ON(block > (sector_t)0x7fffffffUL);
if (block >= AFFS_I(inode)->i_blkcnt) {
if (block > AFFS_I(inode)->i_blkcnt || !create)
@@ -493,8 +492,7 @@
u32 tmp;
pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
- if (from > to || to > PAGE_CACHE_SIZE)
- BUG();
+ BUG_ON(from > to || to > PAGE_CACHE_SIZE);
kmap(page);
data = page_address(page);
bsize = AFFS_SB(sb)->s_data_blksize;
@@ -507,8 +505,7 @@
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, to - from);
- if (from + tmp > to || tmp > bsize)
- BUG();
+ BUG_ON(from + tmp > to || tmp > bsize);
memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
affs_brelse(bh);
bidx++;
@@ -540,10 +537,9 @@
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, newsize - size);
- if (boff + tmp > bsize || tmp > bsize)
- BUG();
+ BUG_ON(boff + tmp > bsize || tmp > bsize);
memset(AFFS_DATA(bh) + boff, 0, tmp);
- AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
+ be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp);
affs_fix_checksum(sb, bh);
mark_buffer_dirty_inode(bh, inode);
size += tmp;
@@ -560,8 +556,7 @@
if (IS_ERR(bh))
goto out;
tmp = min(bsize, newsize - size);
- if (tmp > bsize)
- BUG();
+ BUG_ON(tmp > bsize);
AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
@@ -683,10 +678,9 @@
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, to - from);
- if (boff + tmp > bsize || tmp > bsize)
- BUG();
+ BUG_ON(boff + tmp > bsize || tmp > bsize);
memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
- AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
+ be32_add_cpu(&AFFS_DATA_HEAD(bh)->size, tmp);
affs_fix_checksum(sb, bh);
mark_buffer_dirty_inode(bh, inode);
written += tmp;
@@ -732,8 +726,7 @@
if (IS_ERR(bh))
goto out;
tmp = min(bsize, to - from);
- if (tmp > bsize)
- BUG();
+ BUG_ON(tmp > bsize);
memcpy(AFFS_DATA(bh), data + from, tmp);
if (buffer_new(bh)) {
AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index d2dc047..01d25d532 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -199,7 +199,6 @@
case Opt_prefix:
/* Free any previous prefix */
kfree(*prefix);
- *prefix = NULL;
*prefix = match_strdup(&args[0]);
if (!*prefix)
return 0;
@@ -233,6 +232,8 @@
break;
case Opt_volume: {
char *vol = match_strdup(&args[0]);
+ if (!vol)
+ return 0;
strlcpy(volume, vol, 32);
kfree(vol);
break;
diff --git a/fs/afs/afs_cm.h b/fs/afs/afs_cm.h
index 7b4d4fa..255f5dd 100644
--- a/fs/afs/afs_cm.h
+++ b/fs/afs/afs_cm.h
@@ -24,7 +24,8 @@
CBGetXStatsVersion = 209, /* get version of extended statistics */
CBGetXStats = 210, /* get contents of extended statistics data */
CBInitCallBackState3 = 213, /* initialise callback state, version 3 */
- CBGetCapabilities = 65538, /* get client capabilities */
+ CBProbeUuid = 214, /* check the client hasn't rebooted */
+ CBTellMeAboutYourself = 65538, /* get client capabilities */
};
#define AFS_CAP_ERROR_TRANSLATION 0x1
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 584bb0f..5e1df14 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -20,7 +20,7 @@
DECLARE_RWSEM(afs_proc_cells_sem);
LIST_HEAD(afs_proc_cells);
-static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
+static LIST_HEAD(afs_cells);
static DEFINE_RWLOCK(afs_cells_lock);
static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq);
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index 47b71c8..eb76548 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -26,8 +26,9 @@
struct sk_buff *, bool);
static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool);
static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
-static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *,
- bool);
+static int afs_deliver_cb_probe_uuid(struct afs_call *, struct sk_buff *, bool);
+static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *,
+ struct sk_buff *, bool);
static void afs_cm_destructor(struct afs_call *);
/*
@@ -71,11 +72,21 @@
};
/*
- * CB.GetCapabilities operation type
+ * CB.ProbeUuid operation type
*/
-static const struct afs_call_type afs_SRXCBGetCapabilites = {
- .name = "CB.GetCapabilities",
- .deliver = afs_deliver_cb_get_capabilities,
+static const struct afs_call_type afs_SRXCBProbeUuid = {
+ .name = "CB.ProbeUuid",
+ .deliver = afs_deliver_cb_probe_uuid,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_cm_destructor,
+};
+
+/*
+ * CB.TellMeAboutYourself operation type
+ */
+static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
+ .name = "CB.TellMeAboutYourself",
+ .deliver = afs_deliver_cb_tell_me_about_yourself,
.abort_to_error = afs_abort_to_error,
.destructor = afs_cm_destructor,
};
@@ -103,8 +114,8 @@
case CBProbe:
call->type = &afs_SRXCBProbe;
return true;
- case CBGetCapabilities:
- call->type = &afs_SRXCBGetCapabilites;
+ case CBTellMeAboutYourself:
+ call->type = &afs_SRXCBTellMeAboutYourself;
return true;
default:
return false;
@@ -393,9 +404,105 @@
}
/*
+ * allow the fileserver to quickly find out if the fileserver has been rebooted
+ */
+static void SRXAFSCB_ProbeUuid(struct work_struct *work)
+{
+ struct afs_call *call = container_of(work, struct afs_call, work);
+ struct afs_uuid *r = call->request;
+
+ struct {
+ __be32 match;
+ } reply;
+
+ _enter("");
+
+
+ if (memcmp(r, &afs_uuid, sizeof(afs_uuid)) == 0)
+ reply.match = htonl(0);
+ else
+ reply.match = htonl(1);
+
+ afs_send_simple_reply(call, &reply, sizeof(reply));
+ _leave("");
+}
+
+/*
+ * deliver request data to a CB.ProbeUuid call
+ */
+static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
+ bool last)
+{
+ struct afs_uuid *r;
+ unsigned loop;
+ __be32 *b;
+ int ret;
+
+ _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+ if (skb->len > 0)
+ return -EBADMSG;
+ if (!last)
+ return 0;
+
+ switch (call->unmarshall) {
+ case 0:
+ call->offset = 0;
+ call->buffer = kmalloc(11 * sizeof(__be32), GFP_KERNEL);
+ if (!call->buffer)
+ return -ENOMEM;
+ call->unmarshall++;
+
+ case 1:
+ _debug("extract UUID");
+ ret = afs_extract_data(call, skb, last, call->buffer,
+ 11 * sizeof(__be32));
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ _debug("unmarshall UUID");
+ call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
+ if (!call->request)
+ return -ENOMEM;
+
+ b = call->buffer;
+ r = call->request;
+ r->time_low = ntohl(b[0]);
+ r->time_mid = ntohl(b[1]);
+ r->time_hi_and_version = ntohl(b[2]);
+ r->clock_seq_hi_and_reserved = ntohl(b[3]);
+ r->clock_seq_low = ntohl(b[4]);
+
+ for (loop = 0; loop < 6; loop++)
+ r->node[loop] = ntohl(b[loop + 5]);
+
+ call->offset = 0;
+ call->unmarshall++;
+
+ case 2:
+ _debug("trailer");
+ if (skb->len != 0)
+ return -EBADMSG;
+ break;
+ }
+
+ if (!last)
+ return 0;
+
+ call->state = AFS_CALL_REPLYING;
+
+ INIT_WORK(&call->work, SRXAFSCB_ProbeUuid);
+ schedule_work(&call->work);
+ return 0;
+}
+
+/*
* allow the fileserver to ask about the cache manager's capabilities
*/
-static void SRXAFSCB_GetCapabilities(struct work_struct *work)
+static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
{
struct afs_interface *ifs;
struct afs_call *call = container_of(work, struct afs_call, work);
@@ -456,10 +563,10 @@
}
/*
- * deliver request data to a CB.GetCapabilities call
+ * deliver request data to a CB.TellMeAboutYourself call
*/
-static int afs_deliver_cb_get_capabilities(struct afs_call *call,
- struct sk_buff *skb, bool last)
+static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,
+ struct sk_buff *skb, bool last)
{
_enter(",{%u},%d", skb->len, last);
@@ -471,7 +578,7 @@
/* no unmarshalling required */
call->state = AFS_CALL_REPLYING;
- INIT_WORK(&call->work, SRXAFSCB_GetCapabilities);
+ INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself);
schedule_work(&call->work);
return 0;
}
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index b58af8f..dfda03d 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -140,7 +140,7 @@
if (page->index == 0 && qty != ntohs(dbuf->blocks[0].pagehdr.npages)) {
printk("kAFS: %s(%lu): wrong number of dir blocks %d!=%hu\n",
- __FUNCTION__, dir->i_ino, qty,
+ __func__, dir->i_ino, qty,
ntohs(dbuf->blocks[0].pagehdr.npages));
goto error;
}
@@ -159,7 +159,7 @@
for (tmp = 0; tmp < qty; tmp++) {
if (dbuf->blocks[tmp].pagehdr.magic != AFS_DIR_MAGIC) {
printk("kAFS: %s(%lu): bad magic %d/%d is %04hx\n",
- __FUNCTION__, dir->i_ino, tmp, qty,
+ __func__, dir->i_ino, tmp, qty,
ntohs(dbuf->blocks[tmp].pagehdr.magic));
goto error;
}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index eec41c7..7102824 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -757,8 +757,8 @@
{
}
-#define kenter(FMT,...) dbgprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
-#define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define kenter(FMT,...) dbgprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
+#define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
#define kdebug(FMT,...) dbgprintk(" "FMT ,##__VA_ARGS__)
@@ -791,8 +791,8 @@
} while (0)
#else
-#define _enter(FMT,...) _dbprintk("==> %s("FMT")",__FUNCTION__ ,##__VA_ARGS__)
-#define _leave(FMT,...) _dbprintk("<== %s()"FMT"",__FUNCTION__ ,##__VA_ARGS__)
+#define _enter(FMT,...) _dbprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__)
+#define _leave(FMT,...) _dbprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__)
#define _debug(FMT,...) _dbprintk(" "FMT ,##__VA_ARGS__)
#endif
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 846c761..9f7d1ae 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -41,6 +41,7 @@
.write = afs_proc_cells_write,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
static int afs_proc_rootcell_open(struct inode *inode, struct file *file);
@@ -56,7 +57,8 @@
.read = afs_proc_rootcell_read,
.write = afs_proc_rootcell_write,
.llseek = no_llseek,
- .release = afs_proc_rootcell_release
+ .release = afs_proc_rootcell_release,
+ .owner = THIS_MODULE,
};
static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
@@ -80,6 +82,7 @@
.read = seq_read,
.llseek = seq_lseek,
.release = afs_proc_cell_volumes_release,
+ .owner = THIS_MODULE,
};
static int afs_proc_cell_vlservers_open(struct inode *inode,
@@ -104,6 +107,7 @@
.read = seq_read,
.llseek = seq_lseek,
.release = afs_proc_cell_vlservers_release,
+ .owner = THIS_MODULE,
};
static int afs_proc_cell_servers_open(struct inode *inode, struct file *file);
@@ -127,6 +131,7 @@
.read = seq_read,
.llseek = seq_lseek,
.release = afs_proc_cell_servers_release,
+ .owner = THIS_MODULE,
};
/*
@@ -143,17 +148,13 @@
goto error_dir;
proc_afs->owner = THIS_MODULE;
- p = create_proc_entry("cells", 0, proc_afs);
+ p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops);
if (!p)
goto error_cells;
- p->proc_fops = &afs_proc_cells_fops;
- p->owner = THIS_MODULE;
- p = create_proc_entry("rootcell", 0, proc_afs);
+ p = proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops);
if (!p)
goto error_rootcell;
- p->proc_fops = &afs_proc_rootcell_fops;
- p->owner = THIS_MODULE;
_leave(" = 0");
return 0;
@@ -395,26 +396,20 @@
if (!cell->proc_dir)
goto error_dir;
- p = create_proc_entry("servers", 0, cell->proc_dir);
+ p = proc_create_data("servers", 0, cell->proc_dir,
+ &afs_proc_cell_servers_fops, cell);
if (!p)
goto error_servers;
- p->proc_fops = &afs_proc_cell_servers_fops;
- p->owner = THIS_MODULE;
- p->data = cell;
- p = create_proc_entry("vlservers", 0, cell->proc_dir);
+ p = proc_create_data("vlservers", 0, cell->proc_dir,
+ &afs_proc_cell_vlservers_fops, cell);
if (!p)
goto error_vlservers;
- p->proc_fops = &afs_proc_cell_vlservers_fops;
- p->owner = THIS_MODULE;
- p->data = cell;
- p = create_proc_entry("volumes", 0, cell->proc_dir);
+ p = proc_create_data("volumes", 0, cell->proc_dir,
+ &afs_proc_cell_volumes_fops, cell);
if (!p)
goto error_volumes;
- p->proc_fops = &afs_proc_cell_volumes_fops;
- p->owner = THIS_MODULE;
- p->data = cell;
_leave(" = 0");
return 0;
diff --git a/fs/aio.c b/fs/aio.c
index ae94e1dea..b5253e7 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -191,6 +191,43 @@
kunmap_atomic((void *)((unsigned long)__event & PAGE_MASK), km); \
} while(0)
+
+/* __put_ioctx
+ * Called when the last user of an aio context has gone away,
+ * and the struct needs to be freed.
+ */
+static void __put_ioctx(struct kioctx *ctx)
+{
+ unsigned nr_events = ctx->max_reqs;
+
+ BUG_ON(ctx->reqs_active);
+
+ cancel_delayed_work(&ctx->wq);
+ cancel_work_sync(&ctx->wq.work);
+ aio_free_ring(ctx);
+ mmdrop(ctx->mm);
+ ctx->mm = NULL;
+ pr_debug("__put_ioctx: freeing %p\n", ctx);
+ kmem_cache_free(kioctx_cachep, ctx);
+
+ if (nr_events) {
+ spin_lock(&aio_nr_lock);
+ BUG_ON(aio_nr - nr_events > aio_nr);
+ aio_nr -= nr_events;
+ spin_unlock(&aio_nr_lock);
+ }
+}
+
+#define get_ioctx(kioctx) do { \
+ BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
+ atomic_inc(&(kioctx)->users); \
+} while (0)
+#define put_ioctx(kioctx) do { \
+ BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
+ if (unlikely(atomic_dec_and_test(&(kioctx)->users))) \
+ __put_ioctx(kioctx); \
+} while (0)
+
/* ioctx_alloc
* Allocates and initializes an ioctx. Returns an ERR_PTR if it failed.
*/
@@ -240,7 +277,7 @@
if (ctx->max_reqs == 0)
goto out_cleanup;
- /* now link into global list. kludge. FIXME */
+ /* now link into global list. */
write_lock(&mm->ioctx_list_lock);
ctx->next = mm->ioctx_list;
mm->ioctx_list = ctx;
@@ -361,32 +398,6 @@
}
}
-/* __put_ioctx
- * Called when the last user of an aio context has gone away,
- * and the struct needs to be freed.
- */
-void __put_ioctx(struct kioctx *ctx)
-{
- unsigned nr_events = ctx->max_reqs;
-
- BUG_ON(ctx->reqs_active);
-
- cancel_delayed_work(&ctx->wq);
- cancel_work_sync(&ctx->wq.work);
- aio_free_ring(ctx);
- mmdrop(ctx->mm);
- ctx->mm = NULL;
- pr_debug("__put_ioctx: freeing %p\n", ctx);
- kmem_cache_free(kioctx_cachep, ctx);
-
- if (nr_events) {
- spin_lock(&aio_nr_lock);
- BUG_ON(aio_nr - nr_events > aio_nr);
- aio_nr -= nr_events;
- spin_unlock(&aio_nr_lock);
- }
-}
-
/* aio_get_req
* Allocate a slot for an aio request. Increments the users count
* of the kioctx so that the kioctx stays around until all requests are
@@ -542,10 +553,7 @@
return ret;
}
-/* Lookup an ioctx id. ioctx_list is lockless for reads.
- * FIXME: this is O(n) and is only suitable for development.
- */
-struct kioctx *lookup_ioctx(unsigned long ctx_id)
+static struct kioctx *lookup_ioctx(unsigned long ctx_id)
{
struct kioctx *ioctx;
struct mm_struct *mm;
@@ -1070,9 +1078,7 @@
static inline void init_timeout(struct aio_timeout *to)
{
- init_timer(&to->timer);
- to->timer.data = (unsigned long)to;
- to->timer.function = timeout_func;
+ setup_timer_on_stack(&to->timer, timeout_func, (unsigned long) to);
to->timed_out = 0;
to->p = current;
}
@@ -1205,6 +1211,7 @@
if (timeout)
clear_timeout(&to);
out:
+ destroy_timer_on_stack(&to.timer);
return i ? i : ret;
}
@@ -1552,7 +1559,7 @@
return 1;
}
-int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
+static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
struct iocb *iocb)
{
struct kiocb *req;
@@ -1593,7 +1600,7 @@
* event using the eventfd_signal() function.
*/
req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd);
- if (unlikely(IS_ERR(req->ki_eventfd))) {
+ if (IS_ERR(req->ki_eventfd)) {
ret = PTR_ERR(req->ki_eventfd);
goto out_put_req;
}
diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c
index f42be06..977ef20 100644
--- a/fs/anon_inodes.c
+++ b/fs/anon_inodes.c
@@ -57,9 +57,6 @@
* anonymous inode, and a dentry that describe the "class"
* of the file
*
- * @pfd: [out] pointer to the file descriptor
- * @dpinode: [out] pointer to the inode
- * @pfile: [out] pointer to the file struct
* @name: [in] name of the "class" of the new file
* @fops [in] file operations for the new file
* @priv [in] private data for the new file (will be file's private_data)
@@ -68,10 +65,9 @@
* that do not need to have a full-fledged inode in order to operate correctly.
* All the files created with anon_inode_getfd() will share a single inode,
* hence saving memory and avoiding code duplication for the file/inode/dentry
- * setup.
+ * setup. Returns new descriptor or -error.
*/
-int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
- const char *name, const struct file_operations *fops,
+int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv)
{
struct qstr this;
@@ -125,10 +121,7 @@
fd_install(fd, file);
- *pfd = fd;
- *pinode = anon_inode_inode;
- *pfile = file;
- return 0;
+ return fd;
err_dput:
dput(dentry);
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 2d4ae40..c3d352d 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -35,7 +35,7 @@
/* #define DEBUG */
#ifdef DEBUG
-#define DPRINTK(fmt,args...) do { printk(KERN_DEBUG "pid %d: %s: " fmt "\n" , current->pid , __FUNCTION__ , ##args); } while(0)
+#define DPRINTK(fmt,args...) do { printk(KERN_DEBUG "pid %d: %s: " fmt "\n" , current->pid , __func__ , ##args); } while(0)
#else
#define DPRINTK(fmt,args...) do {} while(0)
#endif
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index d96e5c1..894fee5 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -73,8 +73,8 @@
status = 0;
done:
DPRINTK("returning = %d", status);
- mntput(mnt);
dput(dentry);
+ mntput(mnt);
return status;
}
@@ -333,7 +333,7 @@
/* Can we expire this guy */
if (autofs4_can_expire(dentry, timeout, do_now)) {
expired = dentry;
- break;
+ goto found;
}
goto next;
}
@@ -352,7 +352,7 @@
inf->flags |= AUTOFS_INF_EXPIRING;
spin_unlock(&sbi->fs_lock);
expired = dentry;
- break;
+ goto found;
}
spin_unlock(&sbi->fs_lock);
/*
@@ -363,7 +363,7 @@
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
if (expired) {
dput(dentry);
- break;
+ goto found;
}
}
next:
@@ -371,18 +371,16 @@
spin_lock(&dcache_lock);
next = next->next;
}
-
- if (expired) {
- DPRINTK("returning %p %.*s",
- expired, (int)expired->d_name.len, expired->d_name.name);
- spin_lock(&dcache_lock);
- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
- spin_unlock(&dcache_lock);
- return expired;
- }
spin_unlock(&dcache_lock);
-
return NULL;
+
+found:
+ DPRINTK("returning %p %.*s",
+ expired, (int)expired->d_name.len, expired->d_name.name);
+ spin_lock(&dcache_lock);
+ list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
+ spin_unlock(&dcache_lock);
+ return expired;
}
/* Perform an expiry operation */
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index a54a946..edf5b6b 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -146,17 +146,17 @@
if (d_mountpoint(dentry)) {
struct file *fp = NULL;
- struct vfsmount *fp_mnt = mntget(mnt);
- struct dentry *fp_dentry = dget(dentry);
+ struct path fp_path = { .dentry = dentry, .mnt = mnt };
- if (!autofs4_follow_mount(&fp_mnt, &fp_dentry)) {
- dput(fp_dentry);
- mntput(fp_mnt);
+ path_get(&fp_path);
+
+ if (!autofs4_follow_mount(&fp_path.mnt, &fp_path.dentry)) {
+ path_put(&fp_path);
dcache_dir_close(inode, file);
goto out;
}
- fp = dentry_open(fp_dentry, fp_mnt, file->f_flags);
+ fp = dentry_open(fp_path.dentry, fp_path.mnt, file->f_flags);
status = PTR_ERR(fp);
if (IS_ERR(fp)) {
dcache_dir_close(inode, file);
@@ -242,7 +242,8 @@
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
- int status = 0;
+ struct dentry *new;
+ int status;
/* Block on any pending expiry here; invalidate the dentry
when expiration is done to trigger mount request with a new
@@ -318,7 +319,28 @@
spin_lock(&dentry->d_lock);
dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
spin_unlock(&dentry->d_lock);
- return status;
+
+ /*
+ * The dentry that is passed in from lookup may not be the one
+ * we end up using, as mkdir can create a new one. If this
+ * happens, and another process tries the lookup at the same time,
+ * it will set the PENDING flag on this new dentry, but add itself
+ * to our waitq. Then, if after the lookup succeeds, the first
+ * process that requested the mount performs another lookup of the
+ * same directory, it will show up as still pending! So, we need
+ * to redo the lookup here and clear pending on that dentry.
+ */
+ if (d_unhashed(dentry)) {
+ new = d_lookup(dentry->d_parent, &dentry->d_name);
+ if (new) {
+ spin_lock(&new->d_lock);
+ new->d_flags &= ~DCACHE_AUTOFS_PENDING;
+ spin_unlock(&new->d_lock);
+ dput(new);
+ }
+ }
+
+ return 0;
}
/* For autofs direct mounts the follow link triggers the mount */
@@ -533,9 +555,9 @@
goto next;
if (d_unhashed(dentry)) {
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
struct inode *inode = dentry->d_inode;
+ ino = autofs4_dentry_ino(dentry);
list_del_init(&ino->rehash);
dget(dentry);
/*
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 1fe28e4..75e5955 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -171,7 +171,7 @@
for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent)
len += tmp->d_name.len + 1;
- if (--len > NAME_MAX) {
+ if (!len || --len > NAME_MAX) {
spin_unlock(&dcache_lock);
return 0;
}
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 82123ff..e8717de 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -489,9 +489,9 @@
{
befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
- char *p = nd_get_link(nd);
- if (!IS_ERR(p))
- kfree(p);
+ char *link = nd_get_link(nd);
+ if (!IS_ERR(link))
+ kfree(link);
}
}
diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h
index 71faf4d..70f5d3a 100644
--- a/fs/bfs/bfs.h
+++ b/fs/bfs/bfs.h
@@ -42,7 +42,7 @@
#define printf(format, args...) \
- printk(KERN_ERR "BFS-fs: %s(): " format, __FUNCTION__, ## args)
+ printk(KERN_ERR "BFS-fs: %s(): " format, __func__, ## args)
/* inode.c */
extern struct inode *bfs_iget(struct super_block *sb, unsigned long ino);
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index a1bb224..ba4cddb 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -372,21 +372,17 @@
flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data);
} else {
- static unsigned long error_time, error_time2;
if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
- (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
+ (N_MAGIC(ex) != NMAGIC) && printk_ratelimit())
{
printk(KERN_NOTICE "executable not page aligned\n");
- error_time2 = jiffies;
}
- if ((fd_offset & ~PAGE_MASK) != 0 &&
- (jiffies-error_time) > 5*HZ)
+ if ((fd_offset & ~PAGE_MASK) != 0 && printk_ratelimit())
{
printk(KERN_WARNING
"fd_offset is not page aligned. Please convert program: %s\n",
bprm->file->f_path.dentry->d_name.name);
- error_time = jiffies;
}
if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
@@ -495,15 +491,13 @@
start_addr = ex.a_entry & 0xfffff000;
if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
- static unsigned long error_time;
loff_t pos = N_TXTOFF(ex);
- if ((jiffies-error_time) > 5*HZ)
+ if (printk_ratelimit())
{
printk(KERN_WARNING
"N_TXTOFF is not page aligned. Please convert library: %s\n",
file->f_path.dentry->d_name.name);
- error_time = jiffies;
}
down_write(¤t->mm->mmap_sem);
do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 9924581..b25707f 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1255,26 +1255,23 @@
static void fill_elf_header(struct elfhdr *elf, int segs,
u16 machine, u32 flags, u8 osabi)
{
+ memset(elf, 0, sizeof(*elf));
+
memcpy(elf->e_ident, ELFMAG, SELFMAG);
elf->e_ident[EI_CLASS] = ELF_CLASS;
elf->e_ident[EI_DATA] = ELF_DATA;
elf->e_ident[EI_VERSION] = EV_CURRENT;
elf->e_ident[EI_OSABI] = ELF_OSABI;
- memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
elf->e_type = ET_CORE;
elf->e_machine = machine;
elf->e_version = EV_CURRENT;
- elf->e_entry = 0;
elf->e_phoff = sizeof(struct elfhdr);
- elf->e_shoff = 0;
elf->e_flags = flags;
elf->e_ehsize = sizeof(struct elfhdr);
elf->e_phentsize = sizeof(struct elf_phdr);
elf->e_phnum = segs;
- elf->e_shentsize = 0;
- elf->e_shnum = 0;
- elf->e_shstrndx = 0;
+
return;
}
@@ -1725,26 +1722,25 @@
info->thread_status_size = 0;
if (signr) {
- struct elf_thread_status *tmp;
+ struct elf_thread_status *ets;
rcu_read_lock();
do_each_thread(g, p)
if (current->mm == p->mm && current != p) {
- tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
- if (!tmp) {
+ ets = kzalloc(sizeof(*ets), GFP_ATOMIC);
+ if (!ets) {
rcu_read_unlock();
return 0;
}
- tmp->thread = p;
- list_add(&tmp->list, &info->thread_list);
+ ets->thread = p;
+ list_add(&ets->list, &info->thread_list);
}
while_each_thread(g, p);
rcu_read_unlock();
list_for_each(t, &info->thread_list) {
- struct elf_thread_status *tmp;
int sz;
- tmp = list_entry(t, struct elf_thread_status, list);
- sz = elf_dump_thread_status(signr, tmp);
+ ets = list_entry(t, struct elf_thread_status, list);
+ sz = elf_dump_thread_status(signr, ets);
info->thread_status_size += sz;
}
}
@@ -2000,10 +1996,10 @@
for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
struct page *page;
- struct vm_area_struct *vma;
+ struct vm_area_struct *tmp_vma;
if (get_user_pages(current, current->mm, addr, 1, 0, 1,
- &page, &vma) <= 0) {
+ &page, &tmp_vma) <= 0) {
DUMP_SEEK(PAGE_SIZE);
} else {
if (page == ZERO_PAGE(0)) {
@@ -2013,7 +2009,7 @@
}
} else {
void *kaddr;
- flush_cache_page(vma, addr,
+ flush_cache_page(tmp_vma, addr,
page_to_pfn(page));
kaddr = kmap(page);
if ((size += PAGE_SIZE) > limit ||
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 32649f2..ddd35d8 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -136,8 +136,8 @@
retval = kernel_read(file, params->hdr.e_phoff,
(char *) params->phdrs, size);
- if (retval < 0)
- return retval;
+ if (unlikely(retval != size))
+ return retval < 0 ? retval : -ENOEXEC;
/* determine stack size for this binary */
phdr = params->phdrs;
@@ -218,8 +218,11 @@
phdr->p_offset,
interpreter_name,
phdr->p_filesz);
- if (retval < 0)
+ if (unlikely(retval != phdr->p_filesz)) {
+ if (retval >= 0)
+ retval = -ENOEXEC;
goto error;
+ }
retval = -ENOENT;
if (interpreter_name[phdr->p_filesz - 1] != '\0')
@@ -245,8 +248,11 @@
retval = kernel_read(interpreter, 0, bprm->buf,
BINPRM_BUF_SIZE);
- if (retval < 0)
+ if (unlikely(retval != BINPRM_BUF_SIZE)) {
+ if (retval >= 0)
+ retval = -ENOEXEC;
goto error;
+ }
interp_params.hdr = *((struct elfhdr *) bprm->buf);
break;
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index f95ae97..f9c88d0 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -43,7 +43,7 @@
return -ENOEXEC;
}
- bprm->sh_bang++; /* Well, the bang-shell is implicit... */
+ bprm->sh_bang = 1; /* Well, the bang-shell is implicit... */
allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index 0498b18..3b40d45 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -531,7 +531,8 @@
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_PRIVATE, 0);
+ textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
+ MAP_PRIVATE|MAP_EXECUTABLE, 0);
up_write(¤t->mm->mmap_sem);
if (!textpos || textpos >= (unsigned long) -4096) {
if (!textpos)
@@ -932,14 +933,8 @@
return register_binfmt(&flat_format);
}
-static void __exit exit_flat_binfmt(void)
-{
- unregister_binfmt(&flat_format);
-}
-
/****************************************************************************/
core_initcall(init_flat_binfmt);
-module_exit(exit_flat_binfmt);
/****************************************************************************/
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index dbf0ac0..7191306 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -115,6 +115,12 @@
if (!enabled)
goto _ret;
+ retval = -ENOEXEC;
+ if (bprm->misc_bang)
+ goto _ret;
+
+ bprm->misc_bang = 1;
+
/* to keep locking time low, we copy the interpreter string */
read_lock(&entries_lock);
fmt = check_file(bprm);
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index ab33939..9e3963f 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -29,7 +29,7 @@
* Sorta complicated, but hopefully it will work. -TYT
*/
- bprm->sh_bang++;
+ bprm->sh_bang = 1;
allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
diff --git a/fs/bio.c b/fs/bio.c
index 6e0b6f6..799f86d 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -937,6 +937,95 @@
return ERR_PTR(-EINVAL);
}
+static void bio_copy_kern_endio(struct bio *bio, int err)
+{
+ struct bio_vec *bvec;
+ const int read = bio_data_dir(bio) == READ;
+ char *p = bio->bi_private;
+ int i;
+
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ char *addr = page_address(bvec->bv_page);
+
+ if (read && !err)
+ memcpy(p, addr, bvec->bv_len);
+
+ __free_page(bvec->bv_page);
+ p += bvec->bv_len;
+ }
+
+ bio_put(bio);
+}
+
+/**
+ * bio_copy_kern - copy kernel address into bio
+ * @q: the struct request_queue for the bio
+ * @data: pointer to buffer to copy
+ * @len: length in bytes
+ * @gfp_mask: allocation flags for bio and page allocation
+ *
+ * copy the kernel address into a bio suitable for io to a block
+ * device. Returns an error pointer in case of error.
+ */
+struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len,
+ gfp_t gfp_mask, int reading)
+{
+ 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;
+ struct bio *bio;
+ struct bio_vec *bvec;
+ int i, ret;
+
+ bio = bio_alloc(gfp_mask, nr_pages);
+ if (!bio)
+ return ERR_PTR(-ENOMEM);
+
+ while (len) {
+ struct page *page;
+ unsigned int bytes = PAGE_SIZE;
+
+ if (bytes > len)
+ bytes = len;
+
+ page = alloc_page(q->bounce_gfp | gfp_mask);
+ if (!page) {
+ ret = -ENOMEM;
+ goto cleanup;
+ }
+
+ if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) {
+ ret = -EINVAL;
+ goto cleanup;
+ }
+
+ len -= bytes;
+ }
+
+ if (!reading) {
+ void *p = data;
+
+ bio_for_each_segment(bvec, bio, i) {
+ char *addr = page_address(bvec->bv_page);
+
+ memcpy(addr, p, bvec->bv_len);
+ p += bvec->bv_len;
+ }
+ }
+
+ bio->bi_private = data;
+ bio->bi_end_io = bio_copy_kern_endio;
+ return bio;
+cleanup:
+ bio_for_each_segment(bvec, bio, i)
+ __free_page(bvec->bv_page);
+
+ bio_put(bio);
+
+ return ERR_PTR(ret);
+}
+
/*
* bio_set_pages_dirty() and bio_check_pages_dirty() are support functions
* for performing direct-IO in BIOs.
@@ -1273,6 +1362,7 @@
EXPORT_SYMBOL(bio_map_user);
EXPORT_SYMBOL(bio_unmap_user);
EXPORT_SYMBOL(bio_map_kern);
+EXPORT_SYMBOL(bio_copy_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 3db4a26..a073f3f 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -1101,7 +1101,7 @@
printk(KERN_ERR "%s: requested out-of-range block %llu for "
"device %s\n",
- __FUNCTION__, (unsigned long long)block,
+ __func__, (unsigned long long)block,
bdevname(bdev, b));
return -EIO;
}
@@ -2211,8 +2211,8 @@
return err;
}
-int cont_expand_zero(struct file *file, struct address_space *mapping,
- loff_t pos, loff_t *bytes)
+static int cont_expand_zero(struct file *file, struct address_space *mapping,
+ loff_t pos, loff_t *bytes)
{
struct inode *inode = mapping->host;
unsigned blocksize = 1 << inode->i_blkbits;
@@ -2328,23 +2328,6 @@
return 0;
}
-int generic_commit_write(struct file *file, struct page *page,
- unsigned from, unsigned to)
-{
- struct inode *inode = page->mapping->host;
- loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
- __block_commit_write(inode,page,from,to);
- /*
- * No need to use i_size_read() here, the i_size
- * cannot change under us because we hold i_mutex.
- */
- if (pos > inode->i_size) {
- i_size_write(inode, pos);
- mark_inode_dirty(inode);
- }
- return 0;
-}
-
/*
* block_page_mkwrite() is not allowed to change the file size as it gets
* called from a page fault handler when a page is first dirtied. Hence we must
@@ -3315,7 +3298,6 @@
EXPORT_SYMBOL(file_fsync);
EXPORT_SYMBOL(fsync_bdev);
EXPORT_SYMBOL(generic_block_bmap);
-EXPORT_SYMBOL(generic_commit_write);
EXPORT_SYMBOL(generic_cont_expand_simple);
EXPORT_SYMBOL(init_buffer);
EXPORT_SYMBOL(invalidate_bdev);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 038674a..68e510b 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -55,7 +55,6 @@
unsigned int baseminor;
int minorct;
char name[64];
- struct file_operations *fops;
struct cdev *cdev; /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 0228ed0..cc950f6 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -468,7 +468,7 @@
{
struct proc_dir_entry *pde;
- proc_fs_cifs = proc_mkdir("cifs", proc_root_fs);
+ proc_fs_cifs = proc_mkdir("fs/cifs", NULL);
if (proc_fs_cifs == NULL)
return;
@@ -559,7 +559,7 @@
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
remove_proc_entry("Experimental", proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
- remove_proc_entry("cifs", proc_root_fs);
+ remove_proc_entry("fs/cifs", NULL);
}
static int
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index 95a5425..e1c8548 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -134,7 +134,7 @@
unsigned int valid;
/* clean out */
- vattr->va_mode = (umode_t) -1;
+ vattr->va_mode = -1;
vattr->va_uid = (vuid_t) -1;
vattr->va_gid = (vgid_t) -1;
vattr->va_size = (off_t) -1;
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index f89ff08..3d2580e 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -345,7 +345,7 @@
}
/* destruction routines: unlink, rmdir */
-int coda_unlink(struct inode *dir, struct dentry *de)
+static int coda_unlink(struct inode *dir, struct dentry *de)
{
int error;
const char *name = de->d_name.name;
@@ -365,7 +365,7 @@
return 0;
}
-int coda_rmdir(struct inode *dir, struct dentry *de)
+static int coda_rmdir(struct inode *dir, struct dentry *de)
{
const char *name = de->d_name.name;
int len = de->d_name.len;
@@ -424,7 +424,7 @@
/* file operations for directories */
-int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
+static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
{
struct coda_file_info *cfi;
struct file *host_file;
diff --git a/fs/compat.c b/fs/compat.c
index 2ce4456..332a869 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -24,6 +24,7 @@
#include <linux/fcntl.h>
#include <linux/namei.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/vfs.h>
#include <linux/ioctl.h>
#include <linux/init.h>
@@ -1634,7 +1635,7 @@
return ret;
}
-#ifdef TIF_RESTORE_SIGMASK
+#ifdef HAVE_SET_RESTORE_SIGMASK
asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp,
compat_ulong_t __user *outp, compat_ulong_t __user *exp,
struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask,
@@ -1720,7 +1721,7 @@
if (sigmask) {
memcpy(¤t->saved_sigmask, &sigsaved,
sizeof(sigsaved));
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
}
} else if (sigmask)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
@@ -1791,7 +1792,7 @@
if (sigmask) {
memcpy(¤t->saved_sigmask, &sigsaved,
sizeof(sigsaved));
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
}
ret = -ERESTARTNOHAND;
} else if (sigmask)
@@ -1825,7 +1826,7 @@
return ret;
}
-#endif /* TIF_RESTORE_SIGMASK */
+#endif /* HAVE_SET_RESTORE_SIGMASK */
#if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
/* Stuff for NFS server syscalls... */
@@ -2080,7 +2081,7 @@
#ifdef CONFIG_EPOLL
-#ifdef TIF_RESTORE_SIGMASK
+#ifdef HAVE_SET_RESTORE_SIGMASK
asmlinkage long compat_sys_epoll_pwait(int epfd,
struct compat_epoll_event __user *events,
int maxevents, int timeout,
@@ -2117,14 +2118,14 @@
if (err == -EINTR) {
memcpy(¤t->saved_sigmask, &sigsaved,
sizeof(sigsaved));
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
} else
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
}
return err;
}
-#endif /* TIF_RESTORE_SIGMASK */
+#endif /* HAVE_SET_RESTORE_SIGMASK */
#endif /* CONFIG_EPOLL */
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index c6e72ae..97dba0d 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -1046,14 +1046,14 @@
struct inode *inode = file->f_path.dentry->d_inode;
struct vc_data *vc;
- if (file->f_op->ioctl != tty_ioctl)
+ if (file->f_op->unlocked_ioctl != tty_ioctl)
return -EINVAL;
tty = (struct tty_struct *)file->private_data;
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
- if (tty->driver->ioctl != vt_ioctl)
+ if (tty->ops->ioctl != vt_ioctl)
return -EINVAL;
vc = (struct vc_data *)tty->driver_data;
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index 397cb50..2b6cb23 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -115,7 +115,7 @@
goto out;
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
- __FUNCTION__, count, *ppos, buffer->page);
+ __func__, count, *ppos, buffer->page);
retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
buffer->count);
out:
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index 4c1ebff..b9a1d81 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -47,7 +47,7 @@
static struct backing_dev_info configfs_backing_dev_info = {
.ra_pages = 0, /* No readahead */
- .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
static const struct inode_operations configfs_inode_operations ={
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index de3b31d..8421cea 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -92,7 +92,7 @@
root = d_alloc_root(inode);
if (!root) {
- pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
+ pr_debug("%s: could not get root dentry!\n",__func__);
iput(inode);
return -ENOMEM;
}
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
index 78929ea..2a731ef 100644
--- a/fs/configfs/symlink.c
+++ b/fs/configfs/symlink.c
@@ -210,13 +210,13 @@
if (size > PATH_MAX)
return -ENAMETOOLONG;
- pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size);
+ pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size);
for (s = path; depth--; s += 3)
strcpy(s,"../");
fill_item_path(target, path, size);
- pr_debug("%s: path = '%s'\n", __FUNCTION__, path);
+ pr_debug("%s: path = '%s'\n", __func__, path);
return 0;
}
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index fddffe4..159a5ef 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -9,7 +9,7 @@
* 2 as published by the Free Software Foundation.
*
* debugfs is for people to use instead of /proc or /sys.
- * See Documentation/DocBook/kernel-api for more details.
+ * See Documentation/DocBook/filesystems for more details.
*
*/
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index f120e12..285b64a 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -17,6 +17,8 @@
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/tty.h>
+#include <linux/mutex.h>
+#include <linux/idr.h>
#include <linux/devpts_fs.h>
#include <linux/parser.h>
#include <linux/fsnotify.h>
@@ -26,6 +28,10 @@
#define DEVPTS_DEFAULT_MODE 0600
+extern int pty_limit; /* Config limit on Unix98 ptys */
+static DEFINE_IDR(allocated_ptys);
+static DEFINE_MUTEX(allocated_ptys_lock);
+
static struct vfsmount *devpts_mnt;
static struct dentry *devpts_root;
@@ -171,9 +177,44 @@
return lookup_one_len(s, root, sprintf(s, "%d", num));
}
+int devpts_new_index(void)
+{
+ int index;
+ int idr_ret;
+
+retry:
+ if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
+ return -ENOMEM;
+ }
+
+ mutex_lock(&allocated_ptys_lock);
+ idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
+ if (idr_ret < 0) {
+ mutex_unlock(&allocated_ptys_lock);
+ if (idr_ret == -EAGAIN)
+ goto retry;
+ return -EIO;
+ }
+
+ if (index >= pty_limit) {
+ idr_remove(&allocated_ptys, index);
+ mutex_unlock(&allocated_ptys_lock);
+ return -EIO;
+ }
+ mutex_unlock(&allocated_ptys_lock);
+ return index;
+}
+
+void devpts_kill_index(int idx)
+{
+ mutex_lock(&allocated_ptys_lock);
+ idr_remove(&allocated_ptys, idx);
+ mutex_unlock(&allocated_ptys_lock);
+}
+
int devpts_pty_new(struct tty_struct *tty)
{
- int number = tty->index;
+ int number = tty->index; /* tty layer puts index from devpts_new_index() in here */
struct tty_driver *driver = tty->driver;
dev_t device = MKDEV(driver->major, driver->minor_start+number);
struct dentry *dentry;
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
index b64e55e..499e167 100644
--- a/fs/dlm/lockspace.c
+++ b/fs/dlm/lockspace.c
@@ -200,7 +200,7 @@
dlm_kset = kset_create_and_add("dlm", NULL, kernel_kobj);
if (!dlm_kset) {
- printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: can not create kset\n", __func__);
return -ENOMEM;
}
return 0;
diff --git a/fs/dnotify.c b/fs/dnotify.c
index 28d01ed..676073b 100644
--- a/fs/dnotify.c
+++ b/fs/dnotify.c
@@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
+#include <linux/fdtable.h>
int dir_notify_enable __read_mostly = 1;
@@ -66,6 +67,7 @@
struct dnotify_struct **prev;
struct inode *inode;
fl_owner_t id = current->files;
+ struct file *f;
int error = 0;
if ((arg & ~DN_MULTISHOT) == 0) {
@@ -92,6 +94,15 @@
prev = &odn->dn_next;
}
+ rcu_read_lock();
+ f = fcheck(fd);
+ rcu_read_unlock();
+ /* we'd lost the race with close(), sod off silently */
+ /* note that inode->i_lock prevents reordering problems
+ * between accesses to descriptor table and ->i_dnotify */
+ if (f != filp)
+ goto out_free;
+
error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
if (error)
goto out_free;
diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index 59375ef..3e5637f 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -14,18 +14,26 @@
static void drop_pagecache_sb(struct super_block *sb)
{
- struct inode *inode;
+ struct inode *inode, *toput_inode = NULL;
spin_lock(&inode_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
if (inode->i_state & (I_FREEING|I_WILL_FREE))
continue;
+ if (inode->i_mapping->nrpages == 0)
+ continue;
+ __iget(inode);
+ spin_unlock(&inode_lock);
__invalidate_mapping_pages(inode->i_mapping, 0, -1, true);
+ iput(toput_inode);
+ toput_inode = inode;
+ spin_lock(&inode_lock);
}
spin_unlock(&inode_lock);
+ iput(toput_inode);
}
-void drop_pagecache(void)
+static void drop_pagecache(void)
{
struct super_block *sb;
@@ -45,7 +53,7 @@
spin_unlock(&sb_lock);
}
-void drop_slab(void)
+static void drop_slab(void)
{
int nr_objects;
diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
index 7688570..1e34a7f 100644
--- a/fs/ecryptfs/Makefile
+++ b/fs/ecryptfs/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
-ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o debug.o
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o miscdev.o debug.o
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index a066e10..cd62d75 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -119,21 +119,21 @@
if (rc) {
printk(KERN_ERR
"%s: Error initializing crypto hash; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out;
}
rc = crypto_hash_update(&desc, &sg, len);
if (rc) {
printk(KERN_ERR
"%s: Error updating crypto hash; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out;
}
rc = crypto_hash_final(&desc, dst);
if (rc) {
printk(KERN_ERR
"%s: Error finalizing crypto hash; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out;
}
out:
@@ -437,7 +437,7 @@
if (rc < 0) {
printk(KERN_ERR "%s: Error attempting to encrypt page with "
"page->index = [%ld], extent_offset = [%ld]; "
- "rc = [%d]\n", __FUNCTION__, page->index, extent_offset,
+ "rc = [%d]\n", __func__, page->index, extent_offset,
rc);
goto out;
}
@@ -487,7 +487,7 @@
0, PAGE_CACHE_SIZE);
if (rc)
printk(KERN_ERR "%s: Error attempting to copy "
- "page at index [%ld]\n", __FUNCTION__,
+ "page at index [%ld]\n", __func__,
page->index);
goto out;
}
@@ -508,7 +508,7 @@
extent_offset);
if (rc) {
printk(KERN_ERR "%s: Error encrypting extent; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
goto out;
}
ecryptfs_lower_offset_for_extent(
@@ -569,7 +569,7 @@
if (rc < 0) {
printk(KERN_ERR "%s: Error attempting to decrypt to page with "
"page->index = [%ld], extent_offset = [%ld]; "
- "rc = [%d]\n", __FUNCTION__, page->index, extent_offset,
+ "rc = [%d]\n", __func__, page->index, extent_offset,
rc);
goto out;
}
@@ -622,7 +622,7 @@
ecryptfs_inode);
if (rc)
printk(KERN_ERR "%s: Error attempting to copy "
- "page at index [%ld]\n", __FUNCTION__,
+ "page at index [%ld]\n", __func__,
page->index);
goto out;
}
@@ -656,7 +656,7 @@
extent_offset);
if (rc) {
printk(KERN_ERR "%s: Error encrypting extent; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
goto out;
}
}
@@ -1215,7 +1215,7 @@
ecryptfs_inode);
if (rc) {
printk(KERN_ERR "%s: Error reading header region; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out;
}
if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) {
@@ -1246,7 +1246,6 @@
(*written) = 6;
}
-struct kmem_cache *ecryptfs_header_cache_0;
struct kmem_cache *ecryptfs_header_cache_1;
struct kmem_cache *ecryptfs_header_cache_2;
@@ -1320,7 +1319,7 @@
0, crypt_stat->num_header_bytes_at_front);
if (rc)
printk(KERN_ERR "%s: Error attempting to write header "
- "information to lower file; rc = [%d]\n", __FUNCTION__,
+ "information to lower file; rc = [%d]\n", __func__,
rc);
return rc;
}
@@ -1365,14 +1364,14 @@
}
} else {
printk(KERN_WARNING "%s: Encrypted flag not set\n",
- __FUNCTION__);
+ __func__);
rc = -EINVAL;
goto out;
}
/* Released in this function */
virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL);
if (!virt) {
- printk(KERN_ERR "%s: Out of memory\n", __FUNCTION__);
+ printk(KERN_ERR "%s: Out of memory\n", __func__);
rc = -ENOMEM;
goto out;
}
@@ -1380,7 +1379,7 @@
ecryptfs_dentry);
if (unlikely(rc)) {
printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out_free;
}
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
@@ -1391,7 +1390,7 @@
ecryptfs_dentry, virt);
if (rc) {
printk(KERN_ERR "%s: Error writing metadata out to lower file; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
goto out_free;
}
out_free:
@@ -1585,7 +1584,7 @@
if (!page_virt) {
rc = -ENOMEM;
printk(KERN_ERR "%s: Unable to allocate page_virt\n",
- __FUNCTION__);
+ __func__);
goto out;
}
rc = ecryptfs_read_lower(page_virt, 0, crypt_stat->extent_size,
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 5007f78..951ee33 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 1997-2003 Erez Zadok
* Copyright (C) 2001-2003 Stony Brook University
- * Copyright (C) 2004-2007 International Business Machines Corp.
+ * Copyright (C) 2004-2008 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
* Trevor S. Highland <trevor.highland@gmail.com>
* Tyler Hicks <tyhicks@ou.edu>
@@ -34,6 +34,7 @@
#include <linux/namei.h>
#include <linux/scatterlist.h>
#include <linux/hash.h>
+#include <linux/nsproxy.h>
/* Version verification for shared data structures w/ userspace */
#define ECRYPTFS_VERSION_MAJOR 0x00
@@ -49,11 +50,13 @@
#define ECRYPTFS_VERSIONING_POLICY 0x00000008
#define ECRYPTFS_VERSIONING_XATTR 0x00000010
#define ECRYPTFS_VERSIONING_MULTKEY 0x00000020
+#define ECRYPTFS_VERSIONING_DEVMISC 0x00000040
#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
| ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \
| ECRYPTFS_VERSIONING_PUBKEY \
| ECRYPTFS_VERSIONING_XATTR \
- | ECRYPTFS_VERSIONING_MULTKEY)
+ | ECRYPTFS_VERSIONING_MULTKEY \
+ | ECRYPTFS_VERSIONING_DEVMISC)
#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
#define ECRYPTFS_SALT_SIZE 8
@@ -73,17 +76,14 @@
#define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32
#define ECRYPTFS_DEFAULT_SEND_TIMEOUT HZ
#define ECRYPTFS_MAX_MSG_CTX_TTL (HZ*3)
-#define ECRYPTFS_NLMSG_HELO 100
-#define ECRYPTFS_NLMSG_QUIT 101
-#define ECRYPTFS_NLMSG_REQUEST 102
-#define ECRYPTFS_NLMSG_RESPONSE 103
#define ECRYPTFS_MAX_PKI_NAME_BYTES 16
#define ECRYPTFS_DEFAULT_NUM_USERS 4
#define ECRYPTFS_MAX_NUM_USERS 32768
#define ECRYPTFS_TRANSPORT_NETLINK 0
#define ECRYPTFS_TRANSPORT_CONNECTOR 1
#define ECRYPTFS_TRANSPORT_RELAYFS 2
-#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_NETLINK
+#define ECRYPTFS_TRANSPORT_MISCDEV 3
+#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_MISCDEV
#define ECRYPTFS_XATTR_NAME "user.ecryptfs"
#define RFC2440_CIPHER_DES3_EDE 0x02
@@ -366,32 +366,63 @@
};
struct ecryptfs_message {
+ /* Can never be greater than ecryptfs_message_buf_len */
+ /* Used to find the parent msg_ctx */
+ /* Inherits from msg_ctx->index */
u32 index;
u32 data_len;
u8 data[];
};
struct ecryptfs_msg_ctx {
-#define ECRYPTFS_MSG_CTX_STATE_FREE 0x0001
-#define ECRYPTFS_MSG_CTX_STATE_PENDING 0x0002
-#define ECRYPTFS_MSG_CTX_STATE_DONE 0x0003
- u32 state;
- unsigned int index;
- unsigned int counter;
+#define ECRYPTFS_MSG_CTX_STATE_FREE 0x01
+#define ECRYPTFS_MSG_CTX_STATE_PENDING 0x02
+#define ECRYPTFS_MSG_CTX_STATE_DONE 0x03
+#define ECRYPTFS_MSG_CTX_STATE_NO_REPLY 0x04
+ u8 state;
+#define ECRYPTFS_MSG_HELO 100
+#define ECRYPTFS_MSG_QUIT 101
+#define ECRYPTFS_MSG_REQUEST 102
+#define ECRYPTFS_MSG_RESPONSE 103
+ u8 type;
+ u32 index;
+ /* Counter converts to a sequence number. Each message sent
+ * out for which we expect a response has an associated
+ * sequence number. The response must have the same sequence
+ * number as the counter for the msg_stc for the message to be
+ * valid. */
+ u32 counter;
+ size_t msg_size;
struct ecryptfs_message *msg;
struct task_struct *task;
struct list_head node;
+ struct list_head daemon_out_list;
struct mutex mux;
};
extern unsigned int ecryptfs_transport;
-struct ecryptfs_daemon_id {
- pid_t pid;
- uid_t uid;
- struct hlist_node id_chain;
+struct ecryptfs_daemon;
+
+struct ecryptfs_daemon {
+#define ECRYPTFS_DAEMON_IN_READ 0x00000001
+#define ECRYPTFS_DAEMON_IN_POLL 0x00000002
+#define ECRYPTFS_DAEMON_ZOMBIE 0x00000004
+#define ECRYPTFS_DAEMON_MISCDEV_OPEN 0x00000008
+ u32 flags;
+ u32 num_queued_msg_ctx;
+ struct pid *pid;
+ uid_t euid;
+ struct user_namespace *user_ns;
+ struct task_struct *task;
+ struct mutex mux;
+ struct list_head msg_ctx_out_queue;
+ wait_queue_head_t wait;
+ struct hlist_node euid_chain;
};
+extern struct mutex ecryptfs_daemon_hash_mux;
+
static inline struct ecryptfs_file_info *
ecryptfs_file_to_private(struct file *file)
{
@@ -500,7 +531,7 @@
}
#define ecryptfs_printk(type, fmt, arg...) \
- __ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg);
+ __ecryptfs_printk(type "%s: " fmt, __func__, ## arg);
void __ecryptfs_printk(const char *fmt, ...);
extern const struct file_operations ecryptfs_main_fops;
@@ -581,10 +612,13 @@
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags);
int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode);
-int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid);
-int ecryptfs_process_quit(uid_t uid, pid_t pid);
-int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid,
- pid_t pid, u32 seq);
+int ecryptfs_process_helo(unsigned int transport, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid);
+int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid);
+int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid,
+ u32 seq);
int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
struct ecryptfs_msg_ctx **msg_ctx);
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
@@ -593,14 +627,14 @@
void ecryptfs_release_messaging(unsigned int transport);
int ecryptfs_send_netlink(char *data, int data_len,
- struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type,
- u16 msg_flags, pid_t daemon_pid);
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct pid *daemon_pid);
int ecryptfs_init_netlink(void);
void ecryptfs_release_netlink(void);
int ecryptfs_send_connector(char *data, int data_len,
- struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type,
- u16 msg_flags, pid_t daemon_pid);
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct pid *daemon_pid);
int ecryptfs_init_connector(void);
void ecryptfs_release_connector(void);
void
@@ -642,5 +676,21 @@
size_t offset_in_page, size_t size,
struct inode *ecryptfs_inode);
struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
+int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon);
+int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,
+ struct user_namespace *user_ns);
+int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
+ size_t *length_size);
+int ecryptfs_write_packet_length(char *dest, size_t size,
+ size_t *packet_size_length);
+int ecryptfs_init_ecryptfs_miscdev(void);
+void ecryptfs_destroy_ecryptfs_miscdev(void);
+int ecryptfs_send_miscdev(char *data, size_t data_size,
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct ecryptfs_daemon *daemon);
+void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx);
+int
+ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid);
#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 2b8f5ed..2258b8f 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -195,7 +195,9 @@
file, ecryptfs_inode_to_private(inode)->lower_file);
if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
+ mutex_lock(&crypt_stat->cs_mutex);
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+ mutex_unlock(&crypt_stat->cs_mutex);
rc = 0;
goto out;
}
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index e238611..0a13973 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -111,7 +111,7 @@
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
lower_dir_dentry = lock_parent(lower_dentry);
- if (unlikely(IS_ERR(lower_dir_dentry))) {
+ if (IS_ERR(lower_dir_dentry)) {
ecryptfs_printk(KERN_ERR, "Error locking directory of "
"dentry\n");
rc = PTR_ERR(lower_dir_dentry);
@@ -121,7 +121,7 @@
ecryptfs_dentry, mode, nd);
if (rc) {
printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
goto out_lock;
}
rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
@@ -908,7 +908,9 @@
if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
ia->ia_valid &= ~ATTR_MODE;
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
rc = notify_change(lower_dentry, ia);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
out:
fsstack_copy_attr_all(inode, lower_inode, NULL);
return rc;
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index 682b1b2..e82b457 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -65,7 +65,7 @@
}
/**
- * parse_packet_length
+ * ecryptfs_parse_packet_length
* @data: Pointer to memory containing length at offset
* @size: This function writes the decoded size to this memory
* address; zero on error
@@ -73,8 +73,8 @@
*
* Returns zero on success; non-zero on error
*/
-static int parse_packet_length(unsigned char *data, size_t *size,
- size_t *length_size)
+int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
+ size_t *length_size)
{
int rc = 0;
@@ -105,7 +105,7 @@
}
/**
- * write_packet_length
+ * ecryptfs_write_packet_length
* @dest: The byte array target into which to write the length. Must
* have at least 5 bytes allocated.
* @size: The length to write.
@@ -114,8 +114,8 @@
*
* Returns zero on success; non-zero on error.
*/
-static int write_packet_length(char *dest, size_t size,
- size_t *packet_size_length)
+int ecryptfs_write_packet_length(char *dest, size_t size,
+ size_t *packet_size_length)
{
int rc = 0;
@@ -162,8 +162,8 @@
goto out;
}
message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE;
- rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
- &packet_size_len);
+ rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
+ &packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "
"header; cannot generate packet length\n");
@@ -172,8 +172,9 @@
i += packet_size_len;
memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
i += ECRYPTFS_SIG_SIZE_HEX;
- rc = write_packet_length(&message[i], session_key->encrypted_key_size,
- &packet_size_len);
+ rc = ecryptfs_write_packet_length(&message[i],
+ session_key->encrypted_key_size,
+ &packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "
"header; cannot generate packet length\n");
@@ -225,7 +226,7 @@
rc = -EIO;
goto out;
}
- rc = parse_packet_length(&data[i], &m_size, &data_len);
+ rc = ecryptfs_parse_packet_length(&data[i], &m_size, &data_len);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
"rc = [%d]\n", rc);
@@ -304,8 +305,8 @@
goto out;
}
message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE;
- rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
- &packet_size_len);
+ rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
+ &packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
"header; cannot generate packet length\n");
@@ -315,8 +316,8 @@
memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
i += ECRYPTFS_SIG_SIZE_HEX;
/* The encrypted key includes 1 byte cipher code and 2 byte checksum */
- rc = write_packet_length(&message[i], crypt_stat->key_size + 3,
- &packet_size_len);
+ rc = ecryptfs_write_packet_length(&message[i], crypt_stat->key_size + 3,
+ &packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
"header; cannot generate packet length\n");
@@ -357,20 +358,25 @@
/* verify that everything through the encrypted FEK size is present */
if (message_len < 4) {
rc = -EIO;
+ printk(KERN_ERR "%s: message_len is [%Zd]; minimum acceptable "
+ "message length is [%d]\n", __func__, message_len, 4);
goto out;
}
if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) {
- ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_67\n");
rc = -EIO;
+ printk(KERN_ERR "%s: Type should be ECRYPTFS_TAG_67\n",
+ __func__);
goto out;
}
if (data[i++]) {
- ecryptfs_printk(KERN_ERR, "Status indicator has non zero value"
- " [%d]\n", data[i-1]);
rc = -EIO;
+ printk(KERN_ERR "%s: Status indicator has non zero "
+ "value [%d]\n", __func__, data[i-1]);
+
goto out;
}
- rc = parse_packet_length(&data[i], &key_rec->enc_key_size, &data_len);
+ rc = ecryptfs_parse_packet_length(&data[i], &key_rec->enc_key_size,
+ &data_len);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
"rc = [%d]\n", rc);
@@ -378,17 +384,17 @@
}
i += data_len;
if (message_len < (i + key_rec->enc_key_size)) {
- ecryptfs_printk(KERN_ERR, "message_len [%d]; max len is [%d]\n",
- message_len, (i + key_rec->enc_key_size));
rc = -EIO;
+ printk(KERN_ERR "%s: message_len [%Zd]; max len is [%Zd]\n",
+ __func__, message_len, (i + key_rec->enc_key_size));
goto out;
}
if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
- ecryptfs_printk(KERN_ERR, "Encrypted key_size [%d] larger than "
- "the maximum key size [%d]\n",
- key_rec->enc_key_size,
- ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);
rc = -EIO;
+ printk(KERN_ERR "%s: Encrypted key_size [%Zd] larger than "
+ "the maximum key size [%d]\n", __func__,
+ key_rec->enc_key_size,
+ ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);
goto out;
}
memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size);
@@ -445,7 +451,7 @@
rc = write_tag_64_packet(auth_tok_sig, &(auth_tok->session_key),
&netlink_message, &netlink_message_length);
if (rc) {
- ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet");
+ ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet\n");
goto out;
}
rc = ecryptfs_send_message(ecryptfs_transport, netlink_message,
@@ -570,8 +576,8 @@
goto out;
}
(*new_auth_tok) = &auth_tok_list_item->auth_tok;
- rc = parse_packet_length(&data[(*packet_size)], &body_size,
- &length_size);
+ rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
if (rc) {
printk(KERN_WARNING "Error parsing packet length; "
"rc = [%d]\n", rc);
@@ -704,8 +710,8 @@
goto out;
}
(*new_auth_tok) = &auth_tok_list_item->auth_tok;
- rc = parse_packet_length(&data[(*packet_size)], &body_size,
- &length_size);
+ rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
if (rc) {
printk(KERN_WARNING "Error parsing packet length; rc = [%d]\n",
rc);
@@ -852,8 +858,8 @@
rc = -EINVAL;
goto out;
}
- rc = parse_packet_length(&data[(*packet_size)], &body_size,
- &length_size);
+ rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
if (rc) {
printk(KERN_WARNING "Invalid tag 11 packet format\n");
goto out;
@@ -1405,8 +1411,8 @@
auth_tok->token.private_key.key_size;
rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec);
if (rc) {
- ecryptfs_printk(KERN_ERR, "Failed to encrypt session key "
- "via a pki");
+ printk(KERN_ERR "Failed to encrypt session key via a key "
+ "module; rc = [%d]\n", rc);
goto out;
}
if (ecryptfs_verbosity > 0) {
@@ -1430,8 +1436,9 @@
goto out;
}
dest[(*packet_size)++] = ECRYPTFS_TAG_1_PACKET_TYPE;
- rc = write_packet_length(&dest[(*packet_size)], (max_packet_size - 4),
- &packet_size_length);
+ rc = ecryptfs_write_packet_length(&dest[(*packet_size)],
+ (max_packet_size - 4),
+ &packet_size_length);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 1 packet "
"header; cannot generate packet length\n");
@@ -1489,8 +1496,9 @@
goto out;
}
dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE;
- rc = write_packet_length(&dest[(*packet_length)],
- (max_packet_size - 4), &packet_size_length);
+ rc = ecryptfs_write_packet_length(&dest[(*packet_length)],
+ (max_packet_size - 4),
+ &packet_size_length);
if (rc) {
printk(KERN_ERR "Error generating tag 11 packet header; cannot "
"generate packet length. rc = [%d]\n", rc);
@@ -1682,8 +1690,9 @@
dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE;
/* Chop off the Tag 3 identifier(1) and Tag 3 packet size(3)
* to get the number of octets in the actual Tag 3 packet */
- rc = write_packet_length(&dest[(*packet_size)], (max_packet_size - 4),
- &packet_size_length);
+ rc = ecryptfs_write_packet_length(&dest[(*packet_size)],
+ (max_packet_size - 4),
+ &packet_size_length);
if (rc) {
printk(KERN_ERR "Error generating tag 3 packet header; cannot "
"generate packet length. rc = [%d]\n", rc);
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index d25ac95..d603631 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -219,7 +219,7 @@
if (rc) {
printk(KERN_ERR "%s: Error attempting to initialize the "
"persistent file for the dentry with name [%s]; "
- "rc = [%d]\n", __FUNCTION__, dentry->d_name.name, rc);
+ "rc = [%d]\n", __func__, dentry->d_name.name, rc);
goto out;
}
out:
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index 9cc2aec..1b5c200 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -1,7 +1,7 @@
/**
* eCryptfs: Linux filesystem encryption layer
*
- * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Copyright (C) 2004-2008 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
* Tyler Hicks <tyhicks@ou.edu>
*
@@ -20,19 +20,21 @@
* 02111-1307, USA.
*/
#include <linux/sched.h>
+#include <linux/user_namespace.h>
+#include <linux/nsproxy.h>
#include "ecryptfs_kernel.h"
static LIST_HEAD(ecryptfs_msg_ctx_free_list);
static LIST_HEAD(ecryptfs_msg_ctx_alloc_list);
static struct mutex ecryptfs_msg_ctx_lists_mux;
-static struct hlist_head *ecryptfs_daemon_id_hash;
-static struct mutex ecryptfs_daemon_id_hash_mux;
+static struct hlist_head *ecryptfs_daemon_hash;
+struct mutex ecryptfs_daemon_hash_mux;
static int ecryptfs_hash_buckets;
#define ecryptfs_uid_hash(uid) \
hash_long((unsigned long)uid, ecryptfs_hash_buckets)
-static unsigned int ecryptfs_msg_counter;
+static u32 ecryptfs_msg_counter;
static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
/**
@@ -40,9 +42,10 @@
* @msg_ctx: The context that was acquired from the free list
*
* Acquires a context element from the free list and locks the mutex
- * on the context. Returns zero on success; non-zero on error or upon
- * failure to acquire a free context element. Be sure to lock the
- * list mutex before calling.
+ * on the context. Sets the msg_ctx task to current. Returns zero on
+ * success; non-zero on error or upon failure to acquire a free
+ * context element. Must be called with ecryptfs_msg_ctx_lists_mux
+ * held.
*/
static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
{
@@ -50,11 +53,11 @@
int rc;
if (list_empty(&ecryptfs_msg_ctx_free_list)) {
- ecryptfs_printk(KERN_WARNING, "The eCryptfs free "
- "context list is empty. It may be helpful to "
- "specify the ecryptfs_message_buf_len "
- "parameter to be greater than the current "
- "value of [%d]\n", ecryptfs_message_buf_len);
+ printk(KERN_WARNING "%s: The eCryptfs free "
+ "context list is empty. It may be helpful to "
+ "specify the ecryptfs_message_buf_len "
+ "parameter to be greater than the current "
+ "value of [%d]\n", __func__, ecryptfs_message_buf_len);
rc = -ENOMEM;
goto out;
}
@@ -75,8 +78,7 @@
* ecryptfs_msg_ctx_free_to_alloc
* @msg_ctx: The context to move from the free list to the alloc list
*
- * Be sure to lock the list mutex and the context mutex before
- * calling.
+ * Must be called with ecryptfs_msg_ctx_lists_mux held.
*/
static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
{
@@ -89,36 +91,39 @@
* ecryptfs_msg_ctx_alloc_to_free
* @msg_ctx: The context to move from the alloc list to the free list
*
- * Be sure to lock the list mutex and the context mutex before
- * calling.
+ * Must be called with ecryptfs_msg_ctx_lists_mux held.
*/
-static void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
+void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
{
list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list);
if (msg_ctx->msg)
kfree(msg_ctx->msg);
+ msg_ctx->msg = NULL;
msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE;
}
/**
- * ecryptfs_find_daemon_id
- * @uid: The user id which maps to the desired daemon id
- * @id: If return value is zero, points to the desired daemon id
- * pointer
+ * ecryptfs_find_daemon_by_euid
+ * @euid: The effective user id which maps to the desired daemon id
+ * @user_ns: The namespace in which @euid applies
+ * @daemon: If return value is zero, points to the desired daemon pointer
*
- * Search the hash list for the given user id. Returns zero if the
- * user id exists in the list; non-zero otherwise. The daemon id hash
- * mutex should be held before calling this function.
+ * Must be called with ecryptfs_daemon_hash_mux held.
+ *
+ * Search the hash list for the given user id.
+ *
+ * Returns zero if the user id exists in the list; non-zero otherwise.
*/
-static int ecryptfs_find_daemon_id(uid_t uid, struct ecryptfs_daemon_id **id)
+int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,
+ struct user_namespace *user_ns)
{
struct hlist_node *elem;
int rc;
- hlist_for_each_entry(*id, elem,
- &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)],
- id_chain) {
- if ((*id)->uid == uid) {
+ hlist_for_each_entry(*daemon, elem,
+ &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)],
+ euid_chain) {
+ if ((*daemon)->euid == euid && (*daemon)->user_ns == user_ns) {
rc = 0;
goto out;
}
@@ -128,181 +133,325 @@
return rc;
}
-static int ecryptfs_send_raw_message(unsigned int transport, u16 msg_type,
- pid_t pid)
+static int
+ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
+ u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx);
+
+/**
+ * ecryptfs_send_raw_message
+ * @transport: Transport type
+ * @msg_type: Message type
+ * @daemon: Daemon struct for recipient of message
+ *
+ * A raw message is one that does not include an ecryptfs_message
+ * struct. It simply has a type.
+ *
+ * Must be called with ecryptfs_daemon_hash_mux held.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_send_raw_message(unsigned int transport, u8 msg_type,
+ struct ecryptfs_daemon *daemon)
{
+ struct ecryptfs_msg_ctx *msg_ctx;
int rc;
switch(transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
- rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0, pid);
+ rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0,
+ daemon->pid);
+ break;
+ case ECRYPTFS_TRANSPORT_MISCDEV:
+ rc = ecryptfs_send_message_locked(transport, NULL, 0, msg_type,
+ &msg_ctx);
+ if (rc) {
+ printk(KERN_ERR "%s: Error whilst attempting to send "
+ "message via procfs; rc = [%d]\n", __func__, rc);
+ goto out;
+ }
+ /* Raw messages are logically context-free (e.g., no
+ * reply is expected), so we set the state of the
+ * ecryptfs_msg_ctx object to indicate that it should
+ * be freed as soon as the transport sends out the message. */
+ mutex_lock(&msg_ctx->mux);
+ msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_NO_REPLY;
+ mutex_unlock(&msg_ctx->mux);
break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
rc = -ENOSYS;
}
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_spawn_daemon - Create and initialize a new daemon struct
+ * @daemon: Pointer to set to newly allocated daemon struct
+ * @euid: Effective user id for the daemon
+ * @user_ns: The namespace in which @euid applies
+ * @pid: Process id for the daemon
+ *
+ * Must be called ceremoniously while in possession of
+ * ecryptfs_sacred_daemon_hash_mux
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int
+ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid)
+{
+ int rc = 0;
+
+ (*daemon) = kzalloc(sizeof(**daemon), GFP_KERNEL);
+ if (!(*daemon)) {
+ rc = -ENOMEM;
+ printk(KERN_ERR "%s: Failed to allocate [%Zd] bytes of "
+ "GFP_KERNEL memory\n", __func__, sizeof(**daemon));
+ goto out;
+ }
+ (*daemon)->euid = euid;
+ (*daemon)->user_ns = get_user_ns(user_ns);
+ (*daemon)->pid = get_pid(pid);
+ (*daemon)->task = current;
+ mutex_init(&(*daemon)->mux);
+ INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue);
+ init_waitqueue_head(&(*daemon)->wait);
+ (*daemon)->num_queued_msg_ctx = 0;
+ hlist_add_head(&(*daemon)->euid_chain,
+ &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)]);
+out:
return rc;
}
/**
* ecryptfs_process_helo
* @transport: The underlying transport (netlink, etc.)
- * @uid: The user ID owner of the message
+ * @euid: The user ID owner of the message
+ * @user_ns: The namespace in which @euid applies
* @pid: The process ID for the userspace program that sent the
* message
*
- * Adds the uid and pid values to the daemon id hash. If a uid
+ * Adds the euid and pid values to the daemon euid hash. If an euid
* already has a daemon pid registered, the daemon will be
- * unregistered before the new daemon id is put into the hash list.
- * Returns zero after adding a new daemon id to the hash list;
+ * unregistered before the new daemon is put into the hash list.
+ * Returns zero after adding a new daemon to the hash list;
* non-zero otherwise.
*/
-int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid)
+int ecryptfs_process_helo(unsigned int transport, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid)
{
- struct ecryptfs_daemon_id *new_id;
- struct ecryptfs_daemon_id *old_id;
+ struct ecryptfs_daemon *new_daemon;
+ struct ecryptfs_daemon *old_daemon;
int rc;
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
- new_id = kmalloc(sizeof(*new_id), GFP_KERNEL);
- if (!new_id) {
- rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Failed to allocate memory; unable "
- "to register daemon [%d] for user [%d]\n",
- pid, uid);
- goto unlock;
- }
- if (!ecryptfs_find_daemon_id(uid, &old_id)) {
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = ecryptfs_find_daemon_by_euid(&old_daemon, euid, user_ns);
+ if (rc != 0) {
printk(KERN_WARNING "Received request from user [%d] "
- "to register daemon [%d]; unregistering daemon "
- "[%d]\n", uid, pid, old_id->pid);
- hlist_del(&old_id->id_chain);
- rc = ecryptfs_send_raw_message(transport, ECRYPTFS_NLMSG_QUIT,
- old_id->pid);
+ "to register daemon [0x%p]; unregistering daemon "
+ "[0x%p]\n", euid, pid, old_daemon->pid);
+ rc = ecryptfs_send_raw_message(transport, ECRYPTFS_MSG_QUIT,
+ old_daemon);
if (rc)
printk(KERN_WARNING "Failed to send QUIT "
- "message to daemon [%d]; rc = [%d]\n",
- old_id->pid, rc);
- kfree(old_id);
+ "message to daemon [0x%p]; rc = [%d]\n",
+ old_daemon->pid, rc);
+ hlist_del(&old_daemon->euid_chain);
+ kfree(old_daemon);
}
- new_id->uid = uid;
- new_id->pid = pid;
- hlist_add_head(&new_id->id_chain,
- &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)]);
- rc = 0;
-unlock:
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ rc = ecryptfs_spawn_daemon(&new_daemon, euid, user_ns, pid);
+ if (rc)
+ printk(KERN_ERR "%s: The gods are displeased with this attempt "
+ "to create a new daemon object for euid [%d]; pid "
+ "[0x%p]; rc = [%d]\n", __func__, euid, pid, rc);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_exorcise_daemon - Destroy the daemon struct
+ *
+ * Must be called ceremoniously while in possession of
+ * ecryptfs_daemon_hash_mux and the daemon's own mux.
+ */
+int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
+{
+ struct ecryptfs_msg_ctx *msg_ctx, *msg_ctx_tmp;
+ int rc = 0;
+
+ mutex_lock(&daemon->mux);
+ if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ)
+ || (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) {
+ rc = -EBUSY;
+ printk(KERN_WARNING "%s: Attempt to destroy daemon with pid "
+ "[0x%p], but it is in the midst of a read or a poll\n",
+ __func__, daemon->pid);
+ mutex_unlock(&daemon->mux);
+ goto out;
+ }
+ list_for_each_entry_safe(msg_ctx, msg_ctx_tmp,
+ &daemon->msg_ctx_out_queue, daemon_out_list) {
+ list_del(&msg_ctx->daemon_out_list);
+ daemon->num_queued_msg_ctx--;
+ printk(KERN_WARNING "%s: Warning: dropping message that is in "
+ "the out queue of a dying daemon\n", __func__);
+ ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
+ }
+ hlist_del(&daemon->euid_chain);
+ if (daemon->task)
+ wake_up_process(daemon->task);
+ if (daemon->pid)
+ put_pid(daemon->pid);
+ if (daemon->user_ns)
+ put_user_ns(daemon->user_ns);
+ mutex_unlock(&daemon->mux);
+ memset(daemon, 0, sizeof(*daemon));
+ kfree(daemon);
+out:
return rc;
}
/**
* ecryptfs_process_quit
- * @uid: The user ID owner of the message
+ * @euid: The user ID owner of the message
+ * @user_ns: The namespace in which @euid applies
* @pid: The process ID for the userspace program that sent the
* message
*
- * Deletes the corresponding daemon id for the given uid and pid, if
+ * Deletes the corresponding daemon for the given euid and pid, if
* it is the registered that is requesting the deletion. Returns zero
- * after deleting the desired daemon id; non-zero otherwise.
+ * after deleting the desired daemon; non-zero otherwise.
*/
-int ecryptfs_process_quit(uid_t uid, pid_t pid)
+int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid)
{
- struct ecryptfs_daemon_id *id;
+ struct ecryptfs_daemon *daemon;
int rc;
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
- if (ecryptfs_find_daemon_id(uid, &id)) {
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid, user_ns);
+ if (rc || !daemon) {
rc = -EINVAL;
- ecryptfs_printk(KERN_ERR, "Received request from user [%d] to "
- "unregister unrecognized daemon [%d]\n", uid,
- pid);
- goto unlock;
+ printk(KERN_ERR "Received request from user [%d] to "
+ "unregister unrecognized daemon [0x%p]\n", euid, pid);
+ goto out_unlock;
}
- if (id->pid != pid) {
- rc = -EINVAL;
- ecryptfs_printk(KERN_WARNING, "Received request from user [%d] "
- "with pid [%d] to unregister daemon [%d]\n",
- uid, pid, id->pid);
- goto unlock;
- }
- hlist_del(&id->id_chain);
- kfree(id);
- rc = 0;
-unlock:
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ rc = ecryptfs_exorcise_daemon(daemon);
+out_unlock:
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
return rc;
}
/**
* ecryptfs_process_reponse
* @msg: The ecryptfs message received; the caller should sanity check
- * msg->data_len
+ * msg->data_len and free the memory
* @pid: The process ID of the userspace application that sent the
* message
- * @seq: The sequence number of the message
+ * @seq: The sequence number of the message; must match the sequence
+ * number for the existing message context waiting for this
+ * response
*
- * Processes a response message after sending a operation request to
- * userspace. Returns zero upon delivery to desired context element;
- * non-zero upon delivery failure or error.
+ * Processes a response message after sending an operation request to
+ * userspace. Some other process is awaiting this response. Before
+ * sending out its first communications, the other process allocated a
+ * msg_ctx from the ecryptfs_msg_ctx_arr at a particular index. The
+ * response message contains this index so that we can copy over the
+ * response message into the msg_ctx that the process holds a
+ * reference to. The other process is going to wake up, check to see
+ * that msg_ctx->state == ECRYPTFS_MSG_CTX_STATE_DONE, and then
+ * proceed to read off and process the response message. Returns zero
+ * upon delivery to desired context element; non-zero upon delivery
+ * failure or error.
+ *
+ * Returns zero on success; non-zero otherwise
*/
-int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid,
- pid_t pid, u32 seq)
+int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid,
+ u32 seq)
{
- struct ecryptfs_daemon_id *id;
+ struct ecryptfs_daemon *daemon;
struct ecryptfs_msg_ctx *msg_ctx;
- int msg_size;
+ size_t msg_size;
+ struct nsproxy *nsproxy;
+ struct user_namespace *current_user_ns;
int rc;
if (msg->index >= ecryptfs_message_buf_len) {
rc = -EINVAL;
- ecryptfs_printk(KERN_ERR, "Attempt to reference "
- "context buffer at index [%d]; maximum "
- "allowable is [%d]\n", msg->index,
- (ecryptfs_message_buf_len - 1));
+ printk(KERN_ERR "%s: Attempt to reference "
+ "context buffer at index [%d]; maximum "
+ "allowable is [%d]\n", __func__, msg->index,
+ (ecryptfs_message_buf_len - 1));
goto out;
}
msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
mutex_lock(&msg_ctx->mux);
- if (ecryptfs_find_daemon_id(msg_ctx->task->euid, &id)) {
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rcu_read_lock();
+ nsproxy = task_nsproxy(msg_ctx->task);
+ if (nsproxy == NULL) {
rc = -EBADMSG;
- ecryptfs_printk(KERN_WARNING, "User [%d] received a "
- "message response from process [%d] but does "
- "not have a registered daemon\n",
- msg_ctx->task->euid, pid);
+ printk(KERN_ERR "%s: Receiving process is a zombie. Dropping "
+ "message.\n", __func__);
+ rcu_read_unlock();
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
goto wake_up;
}
- if (msg_ctx->task->euid != uid) {
+ current_user_ns = nsproxy->user_ns;
+ rc = ecryptfs_find_daemon_by_euid(&daemon, msg_ctx->task->euid,
+ current_user_ns);
+ rcu_read_unlock();
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ if (rc) {
rc = -EBADMSG;
- ecryptfs_printk(KERN_WARNING, "Received message from user "
- "[%d]; expected message from user [%d]\n",
- uid, msg_ctx->task->euid);
+ printk(KERN_WARNING "%s: User [%d] received a "
+ "message response from process [0x%p] but does "
+ "not have a registered daemon\n", __func__,
+ msg_ctx->task->euid, pid);
+ goto wake_up;
+ }
+ if (msg_ctx->task->euid != euid) {
+ rc = -EBADMSG;
+ printk(KERN_WARNING "%s: Received message from user "
+ "[%d]; expected message from user [%d]\n", __func__,
+ euid, msg_ctx->task->euid);
goto unlock;
}
- if (id->pid != pid) {
+ if (current_user_ns != user_ns) {
rc = -EBADMSG;
- ecryptfs_printk(KERN_ERR, "User [%d] received a "
- "message response from an unrecognized "
- "process [%d]\n", msg_ctx->task->euid, pid);
+ printk(KERN_WARNING "%s: Received message from user_ns "
+ "[0x%p]; expected message from user_ns [0x%p]\n",
+ __func__, user_ns, nsproxy->user_ns);
+ goto unlock;
+ }
+ if (daemon->pid != pid) {
+ rc = -EBADMSG;
+ printk(KERN_ERR "%s: User [%d] sent a message response "
+ "from an unrecognized process [0x%p]\n",
+ __func__, msg_ctx->task->euid, pid);
goto unlock;
}
if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
rc = -EINVAL;
- ecryptfs_printk(KERN_WARNING, "Desired context element is not "
- "pending a response\n");
+ printk(KERN_WARNING "%s: Desired context element is not "
+ "pending a response\n", __func__);
goto unlock;
} else if (msg_ctx->counter != seq) {
rc = -EINVAL;
- ecryptfs_printk(KERN_WARNING, "Invalid message sequence; "
- "expected [%d]; received [%d]\n",
- msg_ctx->counter, seq);
+ printk(KERN_WARNING "%s: Invalid message sequence; "
+ "expected [%d]; received [%d]\n", __func__,
+ msg_ctx->counter, seq);
goto unlock;
}
- msg_size = sizeof(*msg) + msg->data_len;
+ msg_size = (sizeof(*msg) + msg->data_len);
msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL);
if (!msg_ctx->msg) {
rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
+ printk(KERN_ERR "%s: Failed to allocate [%Zd] bytes of "
+ "GFP_KERNEL memory\n", __func__, msg_size);
goto unlock;
}
memcpy(msg_ctx->msg, msg, msg_size);
@@ -317,34 +466,38 @@
}
/**
- * ecryptfs_send_message
+ * ecryptfs_send_message_locked
* @transport: The transport over which to send the message (i.e.,
* netlink)
* @data: The data to send
* @data_len: The length of data
* @msg_ctx: The message context allocated for the send
+ *
+ * Must be called with ecryptfs_daemon_hash_mux held.
+ *
+ * Returns zero on success; non-zero otherwise
*/
-int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
- struct ecryptfs_msg_ctx **msg_ctx)
+static int
+ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
+ u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx)
{
- struct ecryptfs_daemon_id *id;
+ struct ecryptfs_daemon *daemon;
int rc;
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
- if (ecryptfs_find_daemon_id(current->euid, &id)) {
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ if (rc || !daemon) {
rc = -ENOTCONN;
- ecryptfs_printk(KERN_ERR, "User [%d] does not have a daemon "
- "registered\n", current->euid);
+ printk(KERN_ERR "%s: User [%d] does not have a daemon "
+ "registered\n", __func__, current->euid);
goto out;
}
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
rc = ecryptfs_acquire_free_msg_ctx(msg_ctx);
if (rc) {
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
- ecryptfs_printk(KERN_WARNING, "Could not claim a free "
- "context element\n");
+ printk(KERN_WARNING "%s: Could not claim a free "
+ "context element\n", __func__);
goto out;
}
ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);
@@ -352,23 +505,50 @@
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
switch (transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
- rc = ecryptfs_send_netlink(data, data_len, *msg_ctx,
- ECRYPTFS_NLMSG_REQUEST, 0, id->pid);
+ rc = ecryptfs_send_netlink(data, data_len, *msg_ctx, msg_type,
+ 0, daemon->pid);
+ break;
+ case ECRYPTFS_TRANSPORT_MISCDEV:
+ rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type,
+ 0, daemon);
break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
rc = -ENOSYS;
}
- if (rc) {
- printk(KERN_ERR "Error attempting to send message to userspace "
- "daemon; rc = [%d]\n", rc);
- }
+ if (rc)
+ printk(KERN_ERR "%s: Error attempting to send message to "
+ "userspace daemon; rc = [%d]\n", __func__, rc);
out:
return rc;
}
/**
+ * ecryptfs_send_message
+ * @transport: The transport over which to send the message (i.e.,
+ * netlink)
+ * @data: The data to send
+ * @data_len: The length of data
+ * @msg_ctx: The message context allocated for the send
+ *
+ * Grabs ecryptfs_daemon_hash_mux.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
+ struct ecryptfs_msg_ctx **msg_ctx)
+{
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = ecryptfs_send_message_locked(transport, data, data_len,
+ ECRYPTFS_MSG_REQUEST, msg_ctx);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
* ecryptfs_wait_for_response
* @msg_ctx: The context that was assigned when sending a message
* @msg: The incoming message from userspace; not set if rc != 0
@@ -377,7 +557,7 @@
* of time exceeds ecryptfs_message_wait_timeout. If zero is
* returned, msg will point to a valid message from userspace; a
* non-zero value is returned upon failure to receive a message or an
- * error occurs.
+ * error occurs. Callee must free @msg on success.
*/
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
struct ecryptfs_message **msg)
@@ -413,32 +593,32 @@
if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) {
ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS;
- ecryptfs_printk(KERN_WARNING, "Specified number of users is "
- "too large, defaulting to [%d] users\n",
- ecryptfs_number_of_users);
+ printk(KERN_WARNING "%s: Specified number of users is "
+ "too large, defaulting to [%d] users\n", __func__,
+ ecryptfs_number_of_users);
}
- mutex_init(&ecryptfs_daemon_id_hash_mux);
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
+ mutex_init(&ecryptfs_daemon_hash_mux);
+ mutex_lock(&ecryptfs_daemon_hash_mux);
ecryptfs_hash_buckets = 1;
while (ecryptfs_number_of_users >> ecryptfs_hash_buckets)
ecryptfs_hash_buckets++;
- ecryptfs_daemon_id_hash = kmalloc(sizeof(struct hlist_head)
- * ecryptfs_hash_buckets, GFP_KERNEL);
- if (!ecryptfs_daemon_id_hash) {
+ ecryptfs_daemon_hash = kmalloc((sizeof(struct hlist_head)
+ * ecryptfs_hash_buckets), GFP_KERNEL);
+ if (!ecryptfs_daemon_hash) {
rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ printk(KERN_ERR "%s: Failed to allocate memory\n", __func__);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
goto out;
}
for (i = 0; i < ecryptfs_hash_buckets; i++)
- INIT_HLIST_HEAD(&ecryptfs_daemon_id_hash[i]);
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
-
+ INIT_HLIST_HEAD(&ecryptfs_daemon_hash[i]);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx)
- * ecryptfs_message_buf_len), GFP_KERNEL);
+ * ecryptfs_message_buf_len),
+ GFP_KERNEL);
if (!ecryptfs_msg_ctx_arr) {
rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
+ printk(KERN_ERR "%s: Failed to allocate memory\n", __func__);
goto out;
}
mutex_init(&ecryptfs_msg_ctx_lists_mux);
@@ -446,6 +626,7 @@
ecryptfs_msg_counter = 0;
for (i = 0; i < ecryptfs_message_buf_len; i++) {
INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node);
+ INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].daemon_out_list);
mutex_init(&ecryptfs_msg_ctx_arr[i].mux);
mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
ecryptfs_msg_ctx_arr[i].index = i;
@@ -464,6 +645,11 @@
if (rc)
ecryptfs_release_messaging(transport);
break;
+ case ECRYPTFS_TRANSPORT_MISCDEV:
+ rc = ecryptfs_init_ecryptfs_miscdev();
+ if (rc)
+ ecryptfs_release_messaging(transport);
+ break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
@@ -488,27 +674,37 @@
kfree(ecryptfs_msg_ctx_arr);
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
}
- if (ecryptfs_daemon_id_hash) {
+ if (ecryptfs_daemon_hash) {
struct hlist_node *elem;
- struct ecryptfs_daemon_id *id;
+ struct ecryptfs_daemon *daemon;
int i;
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
+ mutex_lock(&ecryptfs_daemon_hash_mux);
for (i = 0; i < ecryptfs_hash_buckets; i++) {
- hlist_for_each_entry(id, elem,
- &ecryptfs_daemon_id_hash[i],
- id_chain) {
- hlist_del(elem);
- kfree(id);
+ int rc;
+
+ hlist_for_each_entry(daemon, elem,
+ &ecryptfs_daemon_hash[i],
+ euid_chain) {
+ rc = ecryptfs_exorcise_daemon(daemon);
+ if (rc)
+ printk(KERN_ERR "%s: Error whilst "
+ "attempting to destroy daemon; "
+ "rc = [%d]. Dazed and confused, "
+ "but trying to continue.\n",
+ __func__, rc);
}
}
- kfree(ecryptfs_daemon_id_hash);
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ kfree(ecryptfs_daemon_hash);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
}
switch(transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
ecryptfs_release_netlink();
break;
+ case ECRYPTFS_TRANSPORT_MISCDEV:
+ ecryptfs_destroy_ecryptfs_miscdev();
+ break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
new file mode 100644
index 0000000..788995e
--- /dev/null
+++ b/fs/ecryptfs/miscdev.c
@@ -0,0 +1,598 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 2008 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/hash.h>
+#include <linux/random.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include "ecryptfs_kernel.h"
+
+static atomic_t ecryptfs_num_miscdev_opens;
+
+/**
+ * ecryptfs_miscdev_poll
+ * @file: dev file (ignored)
+ * @pt: dev poll table (ignored)
+ *
+ * Returns the poll mask
+ */
+static unsigned int
+ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
+{
+ struct ecryptfs_daemon *daemon;
+ unsigned int mask = 0;
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ /* TODO: Just use file->private_data? */
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ BUG_ON(rc || !daemon);
+ mutex_lock(&daemon->mux);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
+ printk(KERN_WARNING "%s: Attempt to poll on zombified "
+ "daemon\n", __func__);
+ goto out_unlock_daemon;
+ }
+ if (daemon->flags & ECRYPTFS_DAEMON_IN_READ)
+ goto out_unlock_daemon;
+ if (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)
+ goto out_unlock_daemon;
+ daemon->flags |= ECRYPTFS_DAEMON_IN_POLL;
+ mutex_unlock(&daemon->mux);
+ poll_wait(file, &daemon->wait, pt);
+ mutex_lock(&daemon->mux);
+ if (!list_empty(&daemon->msg_ctx_out_queue))
+ mask |= POLLIN | POLLRDNORM;
+out_unlock_daemon:
+ daemon->flags &= ~ECRYPTFS_DAEMON_IN_POLL;
+ mutex_unlock(&daemon->mux);
+ return mask;
+}
+
+/**
+ * ecryptfs_miscdev_open
+ * @inode: inode of miscdev handle (ignored)
+ * @file: file for miscdev handle (ignored)
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int
+ecryptfs_miscdev_open(struct inode *inode, struct file *file)
+{
+ struct ecryptfs_daemon *daemon = NULL;
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = try_module_get(THIS_MODULE);
+ if (rc == 0) {
+ rc = -EIO;
+ printk(KERN_ERR "%s: Error attempting to increment module use "
+ "count; rc = [%d]\n", __func__, rc);
+ goto out_unlock_daemon_list;
+ }
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ if (rc || !daemon) {
+ rc = ecryptfs_spawn_daemon(&daemon, current->euid,
+ current->nsproxy->user_ns,
+ task_pid(current));
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to spawn daemon; "
+ "rc = [%d]\n", __func__, rc);
+ goto out_module_put_unlock_daemon_list;
+ }
+ }
+ mutex_lock(&daemon->mux);
+ if (daemon->pid != task_pid(current)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "%s: pid [0x%p] has registered with euid [%d], "
+ "but pid [0x%p] has attempted to open the handle "
+ "instead\n", __func__, daemon->pid, daemon->euid,
+ task_pid(current));
+ goto out_unlock_daemon;
+ }
+ if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
+ rc = -EBUSY;
+ printk(KERN_ERR "%s: Miscellaneous device handle may only be "
+ "opened once per daemon; pid [0x%p] already has this "
+ "handle open\n", __func__, daemon->pid);
+ goto out_unlock_daemon;
+ }
+ daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
+ atomic_inc(&ecryptfs_num_miscdev_opens);
+out_unlock_daemon:
+ mutex_unlock(&daemon->mux);
+out_module_put_unlock_daemon_list:
+ if (rc)
+ module_put(THIS_MODULE);
+out_unlock_daemon_list:
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_release
+ * @inode: inode of fs/ecryptfs/euid handle (ignored)
+ * @file: file for fs/ecryptfs/euid handle (ignored)
+ *
+ * This keeps the daemon registered until the daemon sends another
+ * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int
+ecryptfs_miscdev_release(struct inode *inode, struct file *file)
+{
+ struct ecryptfs_daemon *daemon = NULL;
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ BUG_ON(rc || !daemon);
+ mutex_lock(&daemon->mux);
+ BUG_ON(daemon->pid != task_pid(current));
+ BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
+ daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
+ atomic_dec(&ecryptfs_num_miscdev_opens);
+ mutex_unlock(&daemon->mux);
+ rc = ecryptfs_exorcise_daemon(daemon);
+ if (rc) {
+ printk(KERN_CRIT "%s: Fatal error whilst attempting to "
+ "shut down daemon; rc = [%d]. Please report this "
+ "bug.\n", __func__, rc);
+ BUG();
+ }
+ module_put(THIS_MODULE);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_send_miscdev
+ * @data: Data to send to daemon; may be NULL
+ * @data_size: Amount of data to send to daemon
+ * @msg_ctx: Message context, which is used to handle the reply. If
+ * this is NULL, then we do not expect a reply.
+ * @msg_type: Type of message
+ * @msg_flags: Flags for message
+ * @daemon: eCryptfs daemon object
+ *
+ * Add msg_ctx to queue and then, if it exists, notify the blocked
+ * miscdevess about the data being available. Must be called with
+ * ecryptfs_daemon_hash_mux held.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_send_miscdev(char *data, size_t data_size,
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct ecryptfs_daemon *daemon)
+{
+ int rc = 0;
+
+ mutex_lock(&msg_ctx->mux);
+ if (data) {
+ msg_ctx->msg = kmalloc((sizeof(*msg_ctx->msg) + data_size),
+ GFP_KERNEL);
+ if (!msg_ctx->msg) {
+ rc = -ENOMEM;
+ printk(KERN_ERR "%s: Out of memory whilst attempting "
+ "to kmalloc(%Zd, GFP_KERNEL)\n", __func__,
+ (sizeof(*msg_ctx->msg) + data_size));
+ goto out_unlock;
+ }
+ } else
+ msg_ctx->msg = NULL;
+ msg_ctx->msg->index = msg_ctx->index;
+ msg_ctx->msg->data_len = data_size;
+ msg_ctx->type = msg_type;
+ if (data) {
+ memcpy(msg_ctx->msg->data, data, data_size);
+ msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
+ } else
+ msg_ctx->msg_size = 0;
+ mutex_lock(&daemon->mux);
+ list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
+ daemon->num_queued_msg_ctx++;
+ wake_up_interruptible(&daemon->wait);
+ mutex_unlock(&daemon->mux);
+out_unlock:
+ mutex_unlock(&msg_ctx->mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_read - format and send message from queue
+ * @file: fs/ecryptfs/euid miscdevfs handle (ignored)
+ * @buf: User buffer into which to copy the next message on the daemon queue
+ * @count: Amount of space available in @buf
+ * @ppos: Offset in file (ignored)
+ *
+ * Pulls the most recent message from the daemon queue, formats it for
+ * being sent via a miscdevfs handle, and copies it into @buf
+ *
+ * Returns the number of bytes copied into the user buffer
+ */
+static ssize_t
+ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct ecryptfs_daemon *daemon;
+ struct ecryptfs_msg_ctx *msg_ctx;
+ size_t packet_length_size;
+ u32 counter_nbo;
+ char packet_length[3];
+ size_t i;
+ size_t total_length;
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ /* TODO: Just use file->private_data? */
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ BUG_ON(rc || !daemon);
+ mutex_lock(&daemon->mux);
+ if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
+ rc = 0;
+ printk(KERN_WARNING "%s: Attempt to read from zombified "
+ "daemon\n", __func__);
+ goto out_unlock_daemon;
+ }
+ if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
+ rc = 0;
+ goto out_unlock_daemon;
+ }
+ /* This daemon will not go away so long as this flag is set */
+ daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+check_list:
+ if (list_empty(&daemon->msg_ctx_out_queue)) {
+ mutex_unlock(&daemon->mux);
+ rc = wait_event_interruptible(
+ daemon->wait, !list_empty(&daemon->msg_ctx_out_queue));
+ mutex_lock(&daemon->mux);
+ if (rc < 0) {
+ rc = 0;
+ goto out_unlock_daemon;
+ }
+ }
+ if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
+ rc = 0;
+ goto out_unlock_daemon;
+ }
+ if (list_empty(&daemon->msg_ctx_out_queue)) {
+ /* Something else jumped in since the
+ * wait_event_interruptable() and removed the
+ * message from the queue; try again */
+ goto check_list;
+ }
+ BUG_ON(current->euid != daemon->euid);
+ BUG_ON(current->nsproxy->user_ns != daemon->user_ns);
+ BUG_ON(task_pid(current) != daemon->pid);
+ msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
+ struct ecryptfs_msg_ctx, daemon_out_list);
+ BUG_ON(!msg_ctx);
+ mutex_lock(&msg_ctx->mux);
+ if (msg_ctx->msg) {
+ rc = ecryptfs_write_packet_length(packet_length,
+ msg_ctx->msg_size,
+ &packet_length_size);
+ if (rc) {
+ rc = 0;
+ printk(KERN_WARNING "%s: Error writing packet length; "
+ "rc = [%d]\n", __func__, rc);
+ goto out_unlock_msg_ctx;
+ }
+ } else {
+ packet_length_size = 0;
+ msg_ctx->msg_size = 0;
+ }
+ /* miscdevfs packet format:
+ * Octet 0: Type
+ * Octets 1-4: network byte order msg_ctx->counter
+ * Octets 5-N0: Size of struct ecryptfs_message to follow
+ * Octets N0-N1: struct ecryptfs_message (including data)
+ *
+ * Octets 5-N1 not written if the packet type does not
+ * include a message */
+ total_length = (1 + 4 + packet_length_size + msg_ctx->msg_size);
+ if (count < total_length) {
+ rc = 0;
+ printk(KERN_WARNING "%s: Only given user buffer of "
+ "size [%Zd], but we need [%Zd] to read the "
+ "pending message\n", __func__, count, total_length);
+ goto out_unlock_msg_ctx;
+ }
+ i = 0;
+ buf[i++] = msg_ctx->type;
+ counter_nbo = cpu_to_be32(msg_ctx->counter);
+ memcpy(&buf[i], (char *)&counter_nbo, 4);
+ i += 4;
+ if (msg_ctx->msg) {
+ memcpy(&buf[i], packet_length, packet_length_size);
+ i += packet_length_size;
+ rc = copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size);
+ if (rc) {
+ printk(KERN_ERR "%s: copy_to_user returned error "
+ "[%d]\n", __func__, rc);
+ goto out_unlock_msg_ctx;
+ }
+ i += msg_ctx->msg_size;
+ }
+ rc = i;
+ list_del(&msg_ctx->daemon_out_list);
+ kfree(msg_ctx->msg);
+ msg_ctx->msg = NULL;
+ /* We do not expect a reply from the userspace daemon for any
+ * message type other than ECRYPTFS_MSG_REQUEST */
+ if (msg_ctx->type != ECRYPTFS_MSG_REQUEST)
+ ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
+out_unlock_msg_ctx:
+ mutex_unlock(&msg_ctx->mux);
+out_unlock_daemon:
+ daemon->flags &= ~ECRYPTFS_DAEMON_IN_READ;
+ mutex_unlock(&daemon->mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_helo
+ * @euid: effective user id of miscdevess sending helo packet
+ * @user_ns: The namespace in which @euid applies
+ * @pid: miscdevess id of miscdevess sending helo packet
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_miscdev_helo(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid)
+{
+ int rc;
+
+ rc = ecryptfs_process_helo(ECRYPTFS_TRANSPORT_MISCDEV, euid, user_ns,
+ pid);
+ if (rc)
+ printk(KERN_WARNING "Error processing HELO; rc = [%d]\n", rc);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_quit
+ * @euid: effective user id of miscdevess sending quit packet
+ * @user_ns: The namespace in which @euid applies
+ * @pid: miscdevess id of miscdevess sending quit packet
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_miscdev_quit(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid)
+{
+ int rc;
+
+ rc = ecryptfs_process_quit(euid, user_ns, pid);
+ if (rc)
+ printk(KERN_WARNING
+ "Error processing QUIT message; rc = [%d]\n", rc);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
+ * @data: Bytes comprising struct ecryptfs_message
+ * @data_size: sizeof(struct ecryptfs_message) + data len
+ * @euid: Effective user id of miscdevess sending the miscdev response
+ * @user_ns: The namespace in which @euid applies
+ * @pid: Miscdevess id of miscdevess sending the miscdev response
+ * @seq: Sequence number for miscdev response packet
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_miscdev_response(char *data, size_t data_size,
+ uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid, u32 seq)
+{
+ struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
+ int rc;
+
+ if ((sizeof(*msg) + msg->data_len) != data_size) {
+ printk(KERN_WARNING "%s: (sizeof(*msg) + msg->data_len) = "
+ "[%Zd]; data_size = [%Zd]. Invalid packet.\n", __func__,
+ (sizeof(*msg) + msg->data_len), data_size);
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = ecryptfs_process_response(msg, euid, user_ns, pid, seq);
+ if (rc)
+ printk(KERN_ERR
+ "Error processing response message; rc = [%d]\n", rc);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_write - handle write to daemon miscdev handle
+ * @file: File for misc dev handle (ignored)
+ * @buf: Buffer containing user data
+ * @count: Amount of data in @buf
+ * @ppos: Pointer to offset in file (ignored)
+ *
+ * miscdevfs packet format:
+ * Octet 0: Type
+ * Octets 1-4: network byte order msg_ctx->counter (0's for non-response)
+ * Octets 5-N0: Size of struct ecryptfs_message to follow
+ * Octets N0-N1: struct ecryptfs_message (including data)
+ *
+ * Returns the number of bytes read from @buf
+ */
+static ssize_t
+ecryptfs_miscdev_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ u32 counter_nbo, seq;
+ size_t packet_size, packet_size_length, i;
+ ssize_t sz = 0;
+ char *data;
+ int rc;
+
+ if (count == 0)
+ goto out;
+ data = kmalloc(count, GFP_KERNEL);
+ if (!data) {
+ printk(KERN_ERR "%s: Out of memory whilst attempting to "
+ "kmalloc([%Zd], GFP_KERNEL)\n", __func__, count);
+ goto out;
+ }
+ rc = copy_from_user(data, buf, count);
+ if (rc) {
+ printk(KERN_ERR "%s: copy_from_user returned error [%d]\n",
+ __func__, rc);
+ goto out_free;
+ }
+ sz = count;
+ i = 0;
+ switch (data[i++]) {
+ case ECRYPTFS_MSG_RESPONSE:
+ if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) {
+ printk(KERN_WARNING "%s: Minimum acceptable packet "
+ "size is [%Zd], but amount of data written is "
+ "only [%Zd]. Discarding response packet.\n",
+ __func__,
+ (1 + 4 + 1 + sizeof(struct ecryptfs_message)),
+ count);
+ goto out_free;
+ }
+ memcpy((char *)&counter_nbo, &data[i], 4);
+ seq = be32_to_cpu(counter_nbo);
+ i += 4;
+ rc = ecryptfs_parse_packet_length(&data[i], &packet_size,
+ &packet_size_length);
+ if (rc) {
+ printk(KERN_WARNING "%s: Error parsing packet length; "
+ "rc = [%d]\n", __func__, rc);
+ goto out_free;
+ }
+ i += packet_size_length;
+ if ((1 + 4 + packet_size_length + packet_size) != count) {
+ printk(KERN_WARNING "%s: (1 + packet_size_length([%Zd])"
+ " + packet_size([%Zd]))([%Zd]) != "
+ "count([%Zd]). Invalid packet format.\n",
+ __func__, packet_size_length, packet_size,
+ (1 + packet_size_length + packet_size), count);
+ goto out_free;
+ }
+ rc = ecryptfs_miscdev_response(&data[i], packet_size,
+ current->euid,
+ current->nsproxy->user_ns,
+ task_pid(current), seq);
+ if (rc)
+ printk(KERN_WARNING "%s: Failed to deliver miscdev "
+ "response to requesting operation; rc = [%d]\n",
+ __func__, rc);
+ break;
+ case ECRYPTFS_MSG_HELO:
+ rc = ecryptfs_miscdev_helo(current->euid,
+ current->nsproxy->user_ns,
+ task_pid(current));
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to process "
+ "helo from pid [0x%p]; rc = [%d]\n", __func__,
+ task_pid(current), rc);
+ goto out_free;
+ }
+ break;
+ case ECRYPTFS_MSG_QUIT:
+ rc = ecryptfs_miscdev_quit(current->euid,
+ current->nsproxy->user_ns,
+ task_pid(current));
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to process "
+ "quit from pid [0x%p]; rc = [%d]\n", __func__,
+ task_pid(current), rc);
+ goto out_free;
+ }
+ break;
+ default:
+ ecryptfs_printk(KERN_WARNING, "Dropping miscdev "
+ "message of unrecognized type [%d]\n",
+ data[0]);
+ break;
+ }
+out_free:
+ kfree(data);
+out:
+ return sz;
+}
+
+
+static const struct file_operations ecryptfs_miscdev_fops = {
+ .open = ecryptfs_miscdev_open,
+ .poll = ecryptfs_miscdev_poll,
+ .read = ecryptfs_miscdev_read,
+ .write = ecryptfs_miscdev_write,
+ .release = ecryptfs_miscdev_release,
+};
+
+static struct miscdevice ecryptfs_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ecryptfs",
+ .fops = &ecryptfs_miscdev_fops
+};
+
+/**
+ * ecryptfs_init_ecryptfs_miscdev
+ *
+ * Messages sent to the userspace daemon from the kernel are placed on
+ * a queue associated with the daemon. The next read against the
+ * miscdev handle by that daemon will return the oldest message placed
+ * on the message queue for the daemon.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_init_ecryptfs_miscdev(void)
+{
+ int rc;
+
+ atomic_set(&ecryptfs_num_miscdev_opens, 0);
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = misc_register(&ecryptfs_miscdev);
+ if (rc)
+ printk(KERN_ERR "%s: Failed to register miscellaneous device "
+ "for communications with userspace daemons; rc = [%d]\n",
+ __func__, rc);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_destroy_ecryptfs_miscdev
+ *
+ * All of the daemons must be exorcised prior to calling this
+ * function.
+ */
+void ecryptfs_destroy_ecryptfs_miscdev(void)
+{
+ BUG_ON(atomic_read(&ecryptfs_num_miscdev_opens) != 0);
+ misc_deregister(&ecryptfs_miscdev);
+}
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 6df1deb..2b6fe1e 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -153,7 +153,7 @@
flush_dcache_page(page);
if (rc) {
printk(KERN_ERR "%s: Error reading xattr "
- "region; rc = [%d]\n", __FUNCTION__, rc);
+ "region; rc = [%d]\n", __func__, rc);
goto out;
}
} else {
@@ -169,7 +169,7 @@
if (rc) {
printk(KERN_ERR "%s: Error attempting to read "
"extent at offset [%lld] in the lower "
- "file; rc = [%d]\n", __FUNCTION__,
+ "file; rc = [%d]\n", __func__,
lower_offset, rc);
goto out;
}
@@ -212,7 +212,7 @@
"the encrypted content from the lower "
"file whilst inserting the metadata "
"from the xattr into the header; rc = "
- "[%d]\n", __FUNCTION__, rc);
+ "[%d]\n", __func__, rc);
goto out;
}
@@ -293,7 +293,7 @@
if (rc) {
printk(KERN_ERR "%s: Error attemping to read "
"lower page segment; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
ClearPageUptodate(page);
goto out;
} else
@@ -308,7 +308,7 @@
"from the lower file whilst "
"inserting the metadata from "
"the xattr into the header; rc "
- "= [%d]\n", __FUNCTION__, rc);
+ "= [%d]\n", __func__, rc);
ClearPageUptodate(page);
goto out;
}
@@ -320,7 +320,7 @@
if (rc) {
printk(KERN_ERR "%s: Error reading "
"page; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
ClearPageUptodate(page);
goto out;
}
@@ -331,7 +331,7 @@
if (rc) {
printk(KERN_ERR "%s: Error decrypting page "
"at index [%ld]; rc = [%d]\n",
- __FUNCTION__, page->index, rc);
+ __func__, page->index, rc);
ClearPageUptodate(page);
goto out;
}
@@ -348,7 +348,7 @@
if (rc) {
printk(KERN_ERR "%s: Error on attempt to "
"truncate to (higher) offset [%lld];"
- " rc = [%d]\n", __FUNCTION__,
+ " rc = [%d]\n", __func__,
prev_page_end_size, rc);
goto out;
}
@@ -389,7 +389,7 @@
kfree(file_size_virt);
if (rc)
printk(KERN_ERR "%s: Error writing file size to header; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
out:
return rc;
}
diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c
index f638a69..e0abad6 100644
--- a/fs/ecryptfs/netlink.c
+++ b/fs/ecryptfs/netlink.c
@@ -44,8 +44,8 @@
* upon sending the message; non-zero upon error.
*/
int ecryptfs_send_netlink(char *data, int data_len,
- struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type,
- u16 msg_flags, pid_t daemon_pid)
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct pid *daemon_pid)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
@@ -60,7 +60,7 @@
ecryptfs_printk(KERN_ERR, "Failed to allocate socket buffer\n");
goto out;
}
- nlh = NLMSG_PUT(skb, daemon_pid, msg_ctx ? msg_ctx->counter : 0,
+ nlh = NLMSG_PUT(skb, pid_nr(daemon_pid), msg_ctx ? msg_ctx->counter : 0,
msg_type, payload_len);
nlh->nlmsg_flags = msg_flags;
if (msg_ctx && payload_len) {
@@ -69,7 +69,7 @@
msg->data_len = data_len;
memcpy(msg->data, data, data_len);
}
- rc = netlink_unicast(ecryptfs_nl_sock, skb, daemon_pid, 0);
+ rc = netlink_unicast(ecryptfs_nl_sock, skb, pid_nr(daemon_pid), 0);
if (rc < 0) {
ecryptfs_printk(KERN_ERR, "Failed to send eCryptfs netlink "
"message; rc = [%d]\n", rc);
@@ -99,6 +99,7 @@
{
struct nlmsghdr *nlh = nlmsg_hdr(skb);
struct ecryptfs_message *msg = NLMSG_DATA(nlh);
+ struct pid *pid;
int rc;
if (skb->len - NLMSG_HDRLEN - sizeof(*msg) != msg->data_len) {
@@ -107,8 +108,10 @@
"incorrectly specified data length\n");
goto out;
}
- rc = ecryptfs_process_response(msg, NETLINK_CREDS(skb)->uid,
- NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq);
+ pid = find_get_pid(NETLINK_CREDS(skb)->pid);
+ rc = ecryptfs_process_response(msg, NETLINK_CREDS(skb)->uid, NULL,
+ pid, nlh->nlmsg_seq);
+ put_pid(pid);
if (rc)
printk(KERN_ERR
"Error processing response message; rc = [%d]\n", rc);
@@ -126,11 +129,13 @@
*/
static int ecryptfs_process_nl_helo(struct sk_buff *skb)
{
+ struct pid *pid;
int rc;
+ pid = find_get_pid(NETLINK_CREDS(skb)->pid);
rc = ecryptfs_process_helo(ECRYPTFS_TRANSPORT_NETLINK,
- NETLINK_CREDS(skb)->uid,
- NETLINK_CREDS(skb)->pid);
+ NETLINK_CREDS(skb)->uid, NULL, pid);
+ put_pid(pid);
if (rc)
printk(KERN_WARNING "Error processing HELO; rc = [%d]\n", rc);
return rc;
@@ -147,10 +152,12 @@
*/
static int ecryptfs_process_nl_quit(struct sk_buff *skb)
{
+ struct pid *pid;
int rc;
- rc = ecryptfs_process_quit(NETLINK_CREDS(skb)->uid,
- NETLINK_CREDS(skb)->pid);
+ pid = find_get_pid(NETLINK_CREDS(skb)->pid);
+ rc = ecryptfs_process_quit(NETLINK_CREDS(skb)->uid, NULL, pid);
+ put_pid(pid);
if (rc)
printk(KERN_WARNING
"Error processing QUIT message; rc = [%d]\n", rc);
@@ -176,20 +183,20 @@
goto free;
}
switch (nlh->nlmsg_type) {
- case ECRYPTFS_NLMSG_RESPONSE:
+ case ECRYPTFS_MSG_RESPONSE:
if (ecryptfs_process_nl_response(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to "
"deliver netlink response to "
"requesting operation\n");
}
break;
- case ECRYPTFS_NLMSG_HELO:
+ case ECRYPTFS_MSG_HELO:
if (ecryptfs_process_nl_helo(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to "
"fulfill HELO request\n");
}
break;
- case ECRYPTFS_NLMSG_QUIT:
+ case ECRYPTFS_MSG_QUIT:
if (ecryptfs_process_nl_quit(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to "
"fulfill QUIT request\n");
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index 0c49286..ebf5515 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -55,7 +55,7 @@
set_fs(fs_save);
if (octets_written < 0) {
printk(KERN_ERR "%s: octets_written = [%td]; "
- "expected [%td]\n", __FUNCTION__, octets_written, size);
+ "expected [%td]\n", __func__, octets_written, size);
rc = -EINVAL;
}
mutex_unlock(&inode_info->lower_file_mutex);
@@ -153,7 +153,7 @@
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR "%s: Error getting page at "
"index [%ld] from eCryptfs inode "
- "mapping; rc = [%d]\n", __FUNCTION__,
+ "mapping; rc = [%d]\n", __func__,
ecryptfs_page_idx, rc);
goto out;
}
@@ -165,7 +165,7 @@
if (rc) {
printk(KERN_ERR "%s: Error decrypting "
"page; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
ClearPageUptodate(ecryptfs_page);
page_cache_release(ecryptfs_page);
goto out;
@@ -202,7 +202,7 @@
page_cache_release(ecryptfs_page);
if (rc) {
printk(KERN_ERR "%s: Error encrypting "
- "page; rc = [%d]\n", __FUNCTION__, rc);
+ "page; rc = [%d]\n", __func__, rc);
goto out;
}
pos += num_bytes;
@@ -254,7 +254,7 @@
set_fs(fs_save);
if (octets_read < 0) {
printk(KERN_ERR "%s: octets_read = [%td]; "
- "expected [%td]\n", __FUNCTION__, octets_read, size);
+ "expected [%td]\n", __func__, octets_read, size);
rc = -EINVAL;
}
mutex_unlock(&inode_info->lower_file_mutex);
@@ -327,7 +327,7 @@
printk(KERN_ERR "%s: Attempt to read data past the end of the "
"file; offset = [%lld]; size = [%td]; "
"ecryptfs_file_size = [%lld]\n",
- __FUNCTION__, offset, size, ecryptfs_file_size);
+ __func__, offset, size, ecryptfs_file_size);
goto out;
}
pos = offset;
@@ -345,14 +345,14 @@
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR "%s: Error getting page at "
"index [%ld] from eCryptfs inode "
- "mapping; rc = [%d]\n", __FUNCTION__,
+ "mapping; rc = [%d]\n", __func__,
ecryptfs_page_idx, rc);
goto out;
}
rc = ecryptfs_decrypt_page(ecryptfs_page);
if (rc) {
printk(KERN_ERR "%s: Error decrypting "
- "page; rc = [%d]\n", __FUNCTION__, rc);
+ "page; rc = [%d]\n", __func__, rc);
ClearPageUptodate(ecryptfs_page);
page_cache_release(ecryptfs_page);
goto out;
diff --git a/fs/eventfd.c b/fs/eventfd.c
index a9f130c..343942d 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -200,10 +200,8 @@
asmlinkage long sys_eventfd(unsigned int count)
{
- int error, fd;
+ int fd;
struct eventfd_ctx *ctx;
- struct file *file;
- struct inode *inode;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
@@ -216,12 +214,9 @@
* When we call this, the initialization must be complete, since
* anon_inode_getfd() will install the fd.
*/
- error = anon_inode_getfd(&fd, &inode, &file, "[eventfd]",
- &eventfd_fops, ctx);
- if (!error)
- return fd;
-
- kfree(ctx);
- return error;
+ fd = anon_inode_getfd("[eventfd]", &eventfd_fops, ctx);
+ if (fd < 0)
+ kfree(ctx);
+ return fd;
}
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index a415f42..990c01d 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -257,25 +257,6 @@
(p1->file < p2->file ? -1 : p1->fd - p2->fd));
}
-/* Special initialization for the RB tree node to detect linkage */
-static inline void ep_rb_initnode(struct rb_node *n)
-{
- rb_set_parent(n, n);
-}
-
-/* Removes a node from the RB tree and marks it for a fast is-linked check */
-static inline void ep_rb_erase(struct rb_node *n, struct rb_root *r)
-{
- rb_erase(n, r);
- rb_set_parent(n, n);
-}
-
-/* Fast check to verify that the item is linked to the main RB tree */
-static inline int ep_rb_linked(struct rb_node *n)
-{
- return rb_parent(n) != n;
-}
-
/* Tells us if the item is currently linked */
static inline int ep_is_linked(struct list_head *p)
{
@@ -283,13 +264,13 @@
}
/* Get the "struct epitem" from a wait queue pointer */
-static inline struct epitem * ep_item_from_wait(wait_queue_t *p)
+static inline struct epitem *ep_item_from_wait(wait_queue_t *p)
{
return container_of(p, struct eppoll_entry, wait)->base;
}
/* Get the "struct epitem" from an epoll queue wrapper */
-static inline struct epitem * ep_item_from_epqueue(poll_table *p)
+static inline struct epitem *ep_item_from_epqueue(poll_table *p)
{
return container_of(p, struct ep_pqueue, pt)->epi;
}
@@ -411,8 +392,7 @@
list_del_init(&epi->fllink);
spin_unlock(&file->f_ep_lock);
- if (ep_rb_linked(&epi->rbn))
- ep_rb_erase(&epi->rbn, &ep->rbr);
+ rb_erase(&epi->rbn, &ep->rbr);
spin_lock_irqsave(&ep->lock, flags);
if (ep_is_linked(&epi->rdllink))
@@ -728,7 +708,6 @@
goto error_return;
/* Item initialization follow here ... */
- ep_rb_initnode(&epi->rbn);
INIT_LIST_HEAD(&epi->rdllink);
INIT_LIST_HEAD(&epi->fllink);
INIT_LIST_HEAD(&epi->pwqlist);
@@ -1071,8 +1050,6 @@
{
int error, fd = -1;
struct eventpoll *ep;
- struct inode *inode;
- struct file *file;
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
current, size));
@@ -1082,29 +1059,24 @@
* structure ( "struct eventpoll" ).
*/
error = -EINVAL;
- if (size <= 0 || (error = ep_alloc(&ep)) != 0)
+ if (size <= 0 || (error = ep_alloc(&ep)) < 0) {
+ fd = error;
goto error_return;
+ }
/*
* Creates all the items needed to setup an eventpoll file. That is,
- * a file structure, and inode and a free file descriptor.
+ * a file structure and a free file descriptor.
*/
- error = anon_inode_getfd(&fd, &inode, &file, "[eventpoll]",
- &eventpoll_fops, ep);
- if (error)
- goto error_free;
+ fd = anon_inode_getfd("[eventpoll]", &eventpoll_fops, ep);
+ if (fd < 0)
+ ep_free(ep);
+error_return:
DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
current, size, fd));
return fd;
-
-error_free:
- ep_free(ep);
-error_return:
- DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d) = %d\n",
- current, size, error));
- return error;
}
/*
@@ -1262,7 +1234,7 @@
return error;
}
-#ifdef TIF_RESTORE_SIGMASK
+#ifdef HAVE_SET_RESTORE_SIGMASK
/*
* Implement the event wait interface for the eventpoll file. It is the kernel
@@ -1300,7 +1272,7 @@
if (error == -EINTR) {
memcpy(¤t->saved_sigmask, &sigsaved,
sizeof(sigsaved));
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
} else
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
}
@@ -1308,7 +1280,7 @@
return error;
}
-#endif /* #ifdef TIF_RESTORE_SIGMASK */
+#endif /* HAVE_SET_RESTORE_SIGMASK */
static int __init eventpoll_init(void)
{
@@ -1330,4 +1302,3 @@
return 0;
}
fs_initcall(eventpoll_init);
-
diff --git a/fs/exec.c b/fs/exec.c
index b152029..aeaa979 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/mman.h>
#include <linux/a.out.h>
#include <linux/stat.h>
@@ -735,6 +736,7 @@
tsk->active_mm = mm;
activate_mm(active_mm, mm);
task_unlock(tsk);
+ mm_update_next_owner(mm);
arch_pick_mmap_layout(mm);
if (old_mm) {
up_read(&old_mm->mmap_sem);
@@ -765,9 +767,7 @@
/*
* Kill all other threads in the thread group.
- * We must hold tasklist_lock to call zap_other_threads.
*/
- read_lock(&tasklist_lock);
spin_lock_irq(lock);
if (signal_group_exit(sig)) {
/*
@@ -775,21 +775,10 @@
* return so that the signal is processed.
*/
spin_unlock_irq(lock);
- read_unlock(&tasklist_lock);
return -EAGAIN;
}
-
- /*
- * child_reaper ignores SIGKILL, change it now.
- * Reparenting needs write_lock on tasklist_lock,
- * so it is safe to do it under read_lock.
- */
- if (unlikely(tsk->group_leader == task_child_reaper(tsk)))
- task_active_pid_ns(tsk)->child_reaper = tsk;
-
sig->group_exit_task = tsk;
zap_other_threads(tsk);
- read_unlock(&tasklist_lock);
/* Account for the thread group leader hanging around: */
count = thread_group_leader(tsk) ? 1 : 2;
@@ -810,7 +799,7 @@
if (!thread_group_leader(tsk)) {
leader = tsk->group_leader;
- sig->notify_count = -1;
+ sig->notify_count = -1; /* for exit_notify() */
for (;;) {
write_lock_irq(&tasklist_lock);
if (likely(leader->exit_state))
@@ -820,6 +809,8 @@
schedule();
}
+ if (unlikely(task_child_reaper(tsk) == leader))
+ task_active_pid_ns(tsk)->child_reaper = tsk;
/*
* The only record we have of the real-time age of a
* process, regardless of execs it's done, is start_time.
@@ -963,6 +954,8 @@
if (retval)
goto out;
+ set_mm_exe_file(bprm->mm, bprm->file);
+
/*
* Release all of the old mmap stuff
*/
@@ -1268,7 +1261,6 @@
{
struct linux_binprm *bprm;
struct file *file;
- unsigned long env_p;
struct files_struct *displaced;
int retval;
@@ -1321,11 +1313,9 @@
if (retval < 0)
goto out;
- env_p = bprm->p;
retval = copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
goto out;
- bprm->argv_len = env_p - bprm->p;
retval = search_binary_handler(bprm,regs);
if (retval >= 0) {
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 109ab5e..cc91227 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -150,12 +150,12 @@
if (IS_ERR(ppd)) {
err = PTR_ERR(ppd);
dprintk("%s: get_parent of %ld failed, err %d\n",
- __FUNCTION__, pd->d_inode->i_ino, err);
+ __func__, pd->d_inode->i_ino, err);
dput(pd);
break;
}
- dprintk("%s: find name of %lu in %lu\n", __FUNCTION__,
+ dprintk("%s: find name of %lu in %lu\n", __func__,
pd->d_inode->i_ino, ppd->d_inode->i_ino);
err = exportfs_get_name(mnt, ppd, nbuf, pd);
if (err) {
@@ -168,14 +168,14 @@
continue;
break;
}
- dprintk("%s: found name: %s\n", __FUNCTION__, nbuf);
+ dprintk("%s: found name: %s\n", __func__, nbuf);
mutex_lock(&ppd->d_inode->i_mutex);
npd = lookup_one_len(nbuf, ppd, strlen(nbuf));
mutex_unlock(&ppd->d_inode->i_mutex);
if (IS_ERR(npd)) {
err = PTR_ERR(npd);
dprintk("%s: lookup failed: %d\n",
- __FUNCTION__, err);
+ __func__, err);
dput(ppd);
dput(pd);
break;
@@ -188,7 +188,7 @@
if (npd == pd)
noprogress = 0;
else
- printk("%s: npd != pd\n", __FUNCTION__);
+ printk("%s: npd != pd\n", __func__);
dput(npd);
dput(ppd);
if (IS_ROOT(pd)) {
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index cc47b76..6ae4ecf 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -1261,10 +1261,11 @@
new_i_size = pos + copied;
if (new_i_size > EXT3_I(inode)->i_disksize)
EXT3_I(inode)->i_disksize = new_i_size;
- copied = ext3_generic_write_end(file, mapping, pos, len, copied,
+ ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
page, fsdata);
- if (copied < 0)
- ret = copied;
+ copied = ret2;
+ if (ret2 < 0)
+ ret = ret2;
}
ret2 = ext3_journal_stop(handle);
if (!ret)
@@ -1289,10 +1290,11 @@
if (new_i_size > EXT3_I(inode)->i_disksize)
EXT3_I(inode)->i_disksize = new_i_size;
- copied = ext3_generic_write_end(file, mapping, pos, len, copied,
+ ret2 = ext3_generic_write_end(file, mapping, pos, len, copied,
page, fsdata);
- if (copied < 0)
- ret = copied;
+ copied = ret2;
+ if (ret2 < 0)
+ ret = ret2;
ret2 = ext3_journal_stop(handle);
if (!ret)
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
index a8bae8c..3c8dab8 100644
--- a/fs/ext4/acl.c
+++ b/fs/ext4/acl.c
@@ -9,8 +9,8 @@
#include <linux/slab.h>
#include <linux/capability.h>
#include <linux/fs.h>
-#include <linux/ext4_jbd2.h>
-#include <linux/ext4_fs.h>
+#include "ext4_jbd2.h"
+#include "ext4.h"
#include "xattr.h"
#include "acl.h"
@@ -37,7 +37,7 @@
return ERR_PTR(-EINVAL);
if (count == 0)
return NULL;
- acl = posix_acl_alloc(count, GFP_KERNEL);
+ acl = posix_acl_alloc(count, GFP_NOFS);
if (!acl)
return ERR_PTR(-ENOMEM);
for (n=0; n < count; n++) {
@@ -91,7 +91,7 @@
*size = ext4_acl_size(acl->a_count);
ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count *
- sizeof(ext4_acl_entry), GFP_KERNEL);
+ sizeof(ext4_acl_entry), GFP_NOFS);
if (!ext_acl)
return ERR_PTR(-ENOMEM);
ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION);
@@ -187,7 +187,7 @@
}
retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
if (retval > 0) {
- value = kmalloc(retval, GFP_KERNEL);
+ value = kmalloc(retval, GFP_NOFS);
if (!value)
return ERR_PTR(-ENOMEM);
retval = ext4_xattr_get(inode, name_index, "", value, retval);
@@ -335,7 +335,7 @@
if (error)
goto cleanup;
}
- clone = posix_acl_clone(acl, GFP_KERNEL);
+ clone = posix_acl_clone(acl, GFP_NOFS);
error = -ENOMEM;
if (!clone)
goto cleanup;
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
index 0737e05..da99437 100644
--- a/fs/ext4/balloc.c
+++ b/fs/ext4/balloc.c
@@ -15,12 +15,12 @@
#include <linux/capability.h>
#include <linux/fs.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
-#include <linux/ext4_jbd2.h>
#include <linux/quotaops.h>
#include <linux/buffer_head.h>
-
+#include "ext4.h"
+#include "ext4_jbd2.h"
#include "group.h"
+
/*
* balloc.c contains the blocks allocation and deallocation routines
*/
@@ -48,7 +48,6 @@
unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
ext4_group_t block_group, struct ext4_group_desc *gdp)
{
- unsigned long start;
int bit, bit_max;
unsigned free_blocks, group_blocks;
struct ext4_sb_info *sbi = EXT4_SB(sb);
@@ -59,7 +58,7 @@
/* If checksum is bad mark all blocks used to prevent allocation
* essentially implementing a per-group read-only flag. */
if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"Checksum bad for group %lu\n", block_group);
gdp->bg_free_blocks_count = 0;
gdp->bg_free_inodes_count = 0;
@@ -106,11 +105,12 @@
free_blocks = group_blocks - bit_max;
if (bh) {
+ ext4_fsblk_t start;
+
for (bit = 0; bit < bit_max; bit++)
ext4_set_bit(bit, bh->b_data);
- start = block_group * EXT4_BLOCKS_PER_GROUP(sb) +
- le32_to_cpu(sbi->s_es->s_first_data_block);
+ start = ext4_group_first_block_no(sb, block_group);
/* Set bits for block and inode bitmaps, and inode table */
ext4_set_bit(ext4_block_bitmap(sb, gdp) - start, bh->b_data);
@@ -235,7 +235,7 @@
return 1;
err_out:
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"Invalid block bitmap - "
"block_group = %d, block = %llu",
block_group, bitmap_blk);
@@ -264,7 +264,7 @@
bitmap_blk = ext4_block_bitmap(sb, desc);
bh = sb_getblk(sb, bitmap_blk);
if (unlikely(!bh)) {
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %llu",
(int)block_group, (unsigned long long)bitmap_blk);
@@ -281,7 +281,7 @@
}
if (bh_submit_read(bh) < 0) {
put_bh(bh);
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"Cannot read block bitmap - "
"block_group = %d, block_bitmap = %llu",
(int)block_group, (unsigned long long)bitmap_blk);
@@ -360,7 +360,7 @@
BUG();
}
#define rsv_window_dump(root, verbose) \
- __rsv_window_dump((root), (verbose), __FUNCTION__)
+ __rsv_window_dump((root), (verbose), __func__)
#else
#define rsv_window_dump(root, verbose) do {} while (0)
#endif
@@ -740,7 +740,7 @@
if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
bit + i, bitmap_bh->b_data)) {
jbd_unlock_bh_state(bitmap_bh);
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"bit already cleared for block %llu",
(ext4_fsblk_t)(block + i));
jbd_lock_bh_state(bitmap_bh);
@@ -752,9 +752,7 @@
jbd_unlock_bh_state(bitmap_bh);
spin_lock(sb_bgl_lock(sbi, block_group));
- desc->bg_free_blocks_count =
- cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) +
- group_freed);
+ le16_add_cpu(&desc->bg_free_blocks_count, group_freed);
desc->bg_checksum = ext4_group_desc_csum(sbi, block_group, desc);
spin_unlock(sb_bgl_lock(sbi, block_group));
percpu_counter_add(&sbi->s_freeblocks_counter, count);
@@ -1798,7 +1796,7 @@
if (ext4_test_bit(grp_alloc_blk+i,
bh2jh(bitmap_bh)->b_committed_data)) {
printk("%s: block was unexpectedly set in "
- "b_committed_data\n", __FUNCTION__);
+ "b_committed_data\n", __func__);
}
}
}
@@ -1823,8 +1821,7 @@
spin_lock(sb_bgl_lock(sbi, group_no));
if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))
gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
- gdp->bg_free_blocks_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num);
+ le16_add_cpu(&gdp->bg_free_blocks_count, -num);
gdp->bg_checksum = ext4_group_desc_csum(sbi, group_no, gdp);
spin_unlock(sb_bgl_lock(sbi, group_no));
percpu_counter_sub(&sbi->s_freeblocks_counter, num);
diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c
index 420554f8..d37ea67 100644
--- a/fs/ext4/bitmap.c
+++ b/fs/ext4/bitmap.c
@@ -9,7 +9,7 @@
#include <linux/buffer_head.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
+#include "ext4.h"
#ifdef EXT4FS_DEBUG
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
index 2c23bad..2bf0331 100644
--- a/fs/ext4/dir.c
+++ b/fs/ext4/dir.c
@@ -23,10 +23,10 @@
#include <linux/fs.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
#include <linux/buffer_head.h>
#include <linux/slab.h>
#include <linux/rbtree.h>
+#include "ext4.h"
static unsigned char ext4_filetype_table[] = {
DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
@@ -42,7 +42,7 @@
.llseek = generic_file_llseek,
.read = generic_read_dir,
.readdir = ext4_readdir, /* we take BKL. needed?*/
- .ioctl = ext4_ioctl, /* BKL held */
+ .unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext4_compat_ioctl,
#endif
diff --git a/include/linux/ext4_fs.h b/fs/ext4/ext4.h
similarity index 98%
rename from include/linux/ext4_fs.h
rename to fs/ext4/ext4.h
index 2500325..8158083 100644
--- a/include/linux/ext4_fs.h
+++ b/fs/ext4/ext4.h
@@ -1,5 +1,5 @@
/*
- * linux/include/linux/ext4_fs.h
+ * ext4.h
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
@@ -13,14 +13,13 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#ifndef _LINUX_EXT4_FS_H
-#define _LINUX_EXT4_FS_H
+#ifndef _EXT4_H
+#define _EXT4_H
#include <linux/types.h>
#include <linux/blkdev.h>
#include <linux/magic.h>
-
-#include <linux/ext4_fs_i.h>
+#include "ext4_i.h"
/*
* The second extended filesystem constants/structures
@@ -176,8 +175,7 @@
#define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */
#ifdef __KERNEL__
-#include <linux/ext4_fs_i.h>
-#include <linux/ext4_fs_sb.h>
+#include "ext4_sb.h"
#endif
/*
* Macro-instructions used to manage group descriptors
@@ -231,6 +229,7 @@
#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
+#define EXT4_EXT_MIGRATE 0x00100000 /* Inode is migrating */
#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
#define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */
@@ -1049,8 +1048,7 @@
struct address_space *mapping, loff_t from);
/* ioctl.c */
-extern int ext4_ioctl (struct inode *, struct file *, unsigned int,
- unsigned long);
+extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long);
/* migrate.c */
@@ -1204,4 +1202,4 @@
int extend_disksize);
#endif /* __KERNEL__ */
-#endif /* _LINUX_EXT4_FS_H */
+#endif /* _EXT4_H */
diff --git a/include/linux/ext4_fs_extents.h b/fs/ext4/ext4_extents.h
similarity index 97%
rename from include/linux/ext4_fs_extents.h
rename to fs/ext4/ext4_extents.h
index 1285c58..75333b5 100644
--- a/include/linux/ext4_fs_extents.h
+++ b/fs/ext4/ext4_extents.h
@@ -16,10 +16,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
*/
-#ifndef _LINUX_EXT4_EXTENTS
-#define _LINUX_EXT4_EXTENTS
+#ifndef _EXT4_EXTENTS
+#define _EXT4_EXTENTS
-#include <linux/ext4_fs.h>
+#include "ext4.h"
/*
* With AGGRESSIVE_TEST defined, the capacity of index/leaf blocks
@@ -228,5 +228,5 @@
extern int ext4_ext_search_right(struct inode *, struct ext4_ext_path *,
ext4_lblk_t *, ext4_fsblk_t *);
extern void ext4_ext_drop_refs(struct ext4_ext_path *);
-#endif /* _LINUX_EXT4_EXTENTS */
+#endif /* _EXT4_EXTENTS */
diff --git a/include/linux/ext4_fs_i.h b/fs/ext4/ext4_i.h
similarity index 96%
rename from include/linux/ext4_fs_i.h
rename to fs/ext4/ext4_i.h
index d5508d3..26a4ae2 100644
--- a/include/linux/ext4_fs_i.h
+++ b/fs/ext4/ext4_i.h
@@ -1,5 +1,5 @@
/*
- * linux/include/linux/ext4_fs_i.h
+ * ext4_i.h
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
@@ -13,8 +13,8 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#ifndef _LINUX_EXT4_FS_I
-#define _LINUX_EXT4_FS_I
+#ifndef _EXT4_I
+#define _EXT4_I
#include <linux/rwsem.h>
#include <linux/rbtree.h>
@@ -164,4 +164,4 @@
spinlock_t i_prealloc_lock;
};
-#endif /* _LINUX_EXT4_FS_I */
+#endif /* _EXT4_I */
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c
index d6afe4e..c75384b 100644
--- a/fs/ext4/ext4_jbd2.c
+++ b/fs/ext4/ext4_jbd2.c
@@ -2,14 +2,14 @@
* Interface between ext4 and JBD
*/
-#include <linux/ext4_jbd2.h>
+#include "ext4_jbd2.h"
int __ext4_journal_get_undo_access(const char *where, handle_t *handle,
struct buffer_head *bh)
{
int err = jbd2_journal_get_undo_access(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext4_journal_abort_handle(where, __func__, bh, handle, err);
return err;
}
@@ -18,7 +18,7 @@
{
int err = jbd2_journal_get_write_access(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext4_journal_abort_handle(where, __func__, bh, handle, err);
return err;
}
@@ -27,7 +27,7 @@
{
int err = jbd2_journal_forget(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext4_journal_abort_handle(where, __func__, bh, handle, err);
return err;
}
@@ -36,7 +36,7 @@
{
int err = jbd2_journal_revoke(handle, blocknr, bh);
if (err)
- ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext4_journal_abort_handle(where, __func__, bh, handle, err);
return err;
}
@@ -45,7 +45,7 @@
{
int err = jbd2_journal_get_create_access(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext4_journal_abort_handle(where, __func__, bh, handle, err);
return err;
}
@@ -54,6 +54,6 @@
{
int err = jbd2_journal_dirty_metadata(handle, bh);
if (err)
- ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ ext4_journal_abort_handle(where, __func__, bh, handle, err);
return err;
}
diff --git a/include/linux/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h
similarity index 97%
rename from include/linux/ext4_jbd2.h
rename to fs/ext4/ext4_jbd2.h
index 38c71d3..9255a7d2 100644
--- a/include/linux/ext4_jbd2.h
+++ b/fs/ext4/ext4_jbd2.h
@@ -1,5 +1,5 @@
/*
- * linux/include/linux/ext4_jbd2.h
+ * ext4_jbd2.h
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1999
*
@@ -12,12 +12,12 @@
* Ext4-specific journaling extensions.
*/
-#ifndef _LINUX_EXT4_JBD2_H
-#define _LINUX_EXT4_JBD2_H
+#ifndef _EXT4_JBD2_H
+#define _EXT4_JBD2_H
#include <linux/fs.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
+#include "ext4.h"
#define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal)
@@ -228,4 +228,4 @@
return 0;
}
-#endif /* _LINUX_EXT4_JBD2_H */
+#endif /* _EXT4_JBD2_H */
diff --git a/include/linux/ext4_fs_sb.h b/fs/ext4/ext4_sb.h
similarity index 96%
rename from include/linux/ext4_fs_sb.h
rename to fs/ext4/ext4_sb.h
index abaae2c..5802e69 100644
--- a/include/linux/ext4_fs_sb.h
+++ b/fs/ext4/ext4_sb.h
@@ -1,5 +1,5 @@
/*
- * linux/include/linux/ext4_fs_sb.h
+ * ext4_sb.h
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
@@ -13,8 +13,8 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#ifndef _LINUX_EXT4_FS_SB
-#define _LINUX_EXT4_FS_SB
+#ifndef _EXT4_SB
+#define _EXT4_SB
#ifdef __KERNEL__
#include <linux/timer.h>
@@ -145,4 +145,4 @@
struct ext4_locality_group *s_locality_groups;
};
-#endif /* _LINUX_EXT4_FS_SB */
+#endif /* _EXT4_SB */
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 9ae6e67..47929c4 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -32,7 +32,6 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/time.h>
-#include <linux/ext4_jbd2.h>
#include <linux/jbd2.h>
#include <linux/highuid.h>
#include <linux/pagemap.h>
@@ -40,8 +39,9 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/falloc.h>
-#include <linux/ext4_fs_extents.h>
#include <asm/uaccess.h>
+#include "ext4_jbd2.h"
+#include "ext4_extents.h"
/*
@@ -308,7 +308,7 @@
}
#define ext4_ext_check_header(inode, eh, depth) \
- __ext4_ext_check_header(__FUNCTION__, inode, eh, depth)
+ __ext4_ext_check_header(__func__, inode, eh, depth)
#ifdef EXT_DEBUG
static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
@@ -614,7 +614,7 @@
ix->ei_block = cpu_to_le32(logical);
ext4_idx_store_pblock(ix, ptr);
- curp->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(curp->p_hdr->eh_entries)+1);
+ le16_add_cpu(&curp->p_hdr->eh_entries, 1);
BUG_ON(le16_to_cpu(curp->p_hdr->eh_entries)
> le16_to_cpu(curp->p_hdr->eh_max));
@@ -736,7 +736,7 @@
}
if (m) {
memmove(ex, path[depth].p_ext-m, sizeof(struct ext4_extent)*m);
- neh->eh_entries = cpu_to_le16(le16_to_cpu(neh->eh_entries)+m);
+ le16_add_cpu(&neh->eh_entries, m);
}
set_buffer_uptodate(bh);
@@ -753,8 +753,7 @@
err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
goto cleanup;
- path[depth].p_hdr->eh_entries =
- cpu_to_le16(le16_to_cpu(path[depth].p_hdr->eh_entries)-m);
+ le16_add_cpu(&path[depth].p_hdr->eh_entries, -m);
err = ext4_ext_dirty(handle, inode, path + depth);
if (err)
goto cleanup;
@@ -817,8 +816,7 @@
if (m) {
memmove(++fidx, path[i].p_idx - m,
sizeof(struct ext4_extent_idx) * m);
- neh->eh_entries =
- cpu_to_le16(le16_to_cpu(neh->eh_entries) + m);
+ le16_add_cpu(&neh->eh_entries, m);
}
set_buffer_uptodate(bh);
unlock_buffer(bh);
@@ -834,7 +832,7 @@
err = ext4_ext_get_access(handle, inode, path + i);
if (err)
goto cleanup;
- path[i].p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path[i].p_hdr->eh_entries)-m);
+ le16_add_cpu(&path[i].p_hdr->eh_entries, -m);
err = ext4_ext_dirty(handle, inode, path + i);
if (err)
goto cleanup;
@@ -1369,7 +1367,7 @@
* sizeof(struct ext4_extent);
memmove(ex + 1, ex + 2, len);
}
- eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries) - 1);
+ le16_add_cpu(&eh->eh_entries, -1);
merge_done = 1;
WARN_ON(eh->eh_entries == 0);
if (!eh->eh_entries)
@@ -1560,7 +1558,7 @@
path[depth].p_ext = nearex;
}
- eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)+1);
+ le16_add_cpu(&eh->eh_entries, 1);
nearex = path[depth].p_ext;
nearex->ee_block = newext->ee_block;
ext4_ext_store_pblock(nearex, ext_pblock(newext));
@@ -1699,7 +1697,7 @@
err = ext4_ext_get_access(handle, inode, path);
if (err)
return err;
- path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1);
+ le16_add_cpu(&path->p_hdr->eh_entries, -1);
err = ext4_ext_dirty(handle, inode, path);
if (err)
return err;
@@ -1902,7 +1900,7 @@
if (num == 0) {
/* this extent is removed; mark slot entirely unused */
ext4_ext_store_pblock(ex, 0);
- eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
+ le16_add_cpu(&eh->eh_entries, -1);
}
ex->ee_block = cpu_to_le32(block);
@@ -1979,7 +1977,7 @@
* We start scanning from right side, freeing all the blocks
* after i_size and walking into the tree depth-wise.
*/
- path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL);
+ path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_NOFS);
if (path == NULL) {
ext4_journal_stop(handle);
return -ENOMEM;
@@ -2138,6 +2136,82 @@
#endif
}
+static void bi_complete(struct bio *bio, int error)
+{
+ complete((struct completion *)bio->bi_private);
+}
+
+/* FIXME!! we need to try to merge to left or right after zero-out */
+static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
+{
+ int ret = -EIO;
+ struct bio *bio;
+ int blkbits, blocksize;
+ sector_t ee_pblock;
+ struct completion event;
+ unsigned int ee_len, len, done, offset;
+
+
+ blkbits = inode->i_blkbits;
+ blocksize = inode->i_sb->s_blocksize;
+ ee_len = ext4_ext_get_actual_len(ex);
+ ee_pblock = ext_pblock(ex);
+
+ /* convert ee_pblock to 512 byte sectors */
+ ee_pblock = ee_pblock << (blkbits - 9);
+
+ while (ee_len > 0) {
+
+ if (ee_len > BIO_MAX_PAGES)
+ len = BIO_MAX_PAGES;
+ else
+ len = ee_len;
+
+ bio = bio_alloc(GFP_NOIO, len);
+ if (!bio)
+ return -ENOMEM;
+ bio->bi_sector = ee_pblock;
+ bio->bi_bdev = inode->i_sb->s_bdev;
+
+ done = 0;
+ offset = 0;
+ while (done < len) {
+ ret = bio_add_page(bio, ZERO_PAGE(0),
+ blocksize, offset);
+ if (ret != blocksize) {
+ /*
+ * We can't add any more pages because of
+ * hardware limitations. Start a new bio.
+ */
+ break;
+ }
+ done++;
+ offset += blocksize;
+ if (offset >= PAGE_CACHE_SIZE)
+ offset = 0;
+ }
+
+ init_completion(&event);
+ bio->bi_private = &event;
+ bio->bi_end_io = bi_complete;
+ submit_bio(WRITE, bio);
+ wait_for_completion(&event);
+
+ if (test_bit(BIO_UPTODATE, &bio->bi_flags))
+ ret = 0;
+ else {
+ ret = -EIO;
+ break;
+ }
+ bio_put(bio);
+ ee_len -= done;
+ ee_pblock += done << (blkbits - 9);
+ }
+ return ret;
+}
+
+#define EXT4_EXT_ZERO_LEN 7
+
/*
* This function is called by ext4_ext_get_blocks() if someone tries to write
* to an uninitialized extent. It may result in splitting the uninitialized
@@ -2154,7 +2228,7 @@
ext4_lblk_t iblock,
unsigned long max_blocks)
{
- struct ext4_extent *ex, newex;
+ struct ext4_extent *ex, newex, orig_ex;
struct ext4_extent *ex1 = NULL;
struct ext4_extent *ex2 = NULL;
struct ext4_extent *ex3 = NULL;
@@ -2173,10 +2247,26 @@
allocated = ee_len - (iblock - ee_block);
newblock = iblock - ee_block + ext_pblock(ex);
ex2 = ex;
+ orig_ex.ee_block = ex->ee_block;
+ orig_ex.ee_len = cpu_to_le16(ee_len);
+ ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
err = ext4_ext_get_access(handle, inode, path + depth);
if (err)
goto out;
+ /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */
+ if (ee_len <= 2*EXT4_EXT_ZERO_LEN) {
+ err = ext4_ext_zeroout(inode, &orig_ex);
+ if (err)
+ goto fix_extent_len;
+ /* update the extent length and mark as initialized */
+ ex->ee_block = orig_ex.ee_block;
+ ex->ee_len = orig_ex.ee_len;
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_dirty(handle, inode, path + depth);
+ /* zeroed the full extent */
+ return allocated;
+ }
/* ex1: ee_block to iblock - 1 : uninitialized */
if (iblock > ee_block) {
@@ -2195,19 +2285,103 @@
/* ex3: to ee_block + ee_len : uninitialised */
if (allocated > max_blocks) {
unsigned int newdepth;
+ /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
+ if (allocated <= EXT4_EXT_ZERO_LEN) {
+ /* Mark first half uninitialized.
+ * Mark second half initialized and zero out the
+ * initialized extent
+ */
+ ex->ee_block = orig_ex.ee_block;
+ ex->ee_len = cpu_to_le16(ee_len - allocated);
+ ext4_ext_mark_uninitialized(ex);
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_dirty(handle, inode, path + depth);
+
+ ex3 = &newex;
+ ex3->ee_block = cpu_to_le32(iblock);
+ ext4_ext_store_pblock(ex3, newblock);
+ ex3->ee_len = cpu_to_le16(allocated);
+ err = ext4_ext_insert_extent(handle, inode, path, ex3);
+ if (err == -ENOSPC) {
+ err = ext4_ext_zeroout(inode, &orig_ex);
+ if (err)
+ goto fix_extent_len;
+ ex->ee_block = orig_ex.ee_block;
+ ex->ee_len = orig_ex.ee_len;
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_dirty(handle, inode, path + depth);
+ /* zeroed the full extent */
+ return allocated;
+
+ } else if (err)
+ goto fix_extent_len;
+
+ /*
+ * We need to zero out the second half because
+ * an fallocate request can update file size and
+ * converting the second half to initialized extent
+ * implies that we can leak some junk data to user
+ * space.
+ */
+ err = ext4_ext_zeroout(inode, ex3);
+ if (err) {
+ /*
+ * We should actually mark the
+ * second half as uninit and return error
+ * Insert would have changed the extent
+ */
+ depth = ext_depth(inode);
+ ext4_ext_drop_refs(path);
+ path = ext4_ext_find_extent(inode,
+ iblock, path);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ return err;
+ }
+ ex = path[depth].p_ext;
+ err = ext4_ext_get_access(handle, inode,
+ path + depth);
+ if (err)
+ return err;
+ ext4_ext_mark_uninitialized(ex);
+ ext4_ext_dirty(handle, inode, path + depth);
+ return err;
+ }
+
+ /* zeroed the second half */
+ return allocated;
+ }
ex3 = &newex;
ex3->ee_block = cpu_to_le32(iblock + max_blocks);
ext4_ext_store_pblock(ex3, newblock + max_blocks);
ex3->ee_len = cpu_to_le16(allocated - max_blocks);
ext4_ext_mark_uninitialized(ex3);
err = ext4_ext_insert_extent(handle, inode, path, ex3);
- if (err)
- goto out;
+ if (err == -ENOSPC) {
+ err = ext4_ext_zeroout(inode, &orig_ex);
+ if (err)
+ goto fix_extent_len;
+ /* update the extent length and mark as initialized */
+ ex->ee_block = orig_ex.ee_block;
+ ex->ee_len = orig_ex.ee_len;
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_dirty(handle, inode, path + depth);
+ /* zeroed the full extent */
+ return allocated;
+
+ } else if (err)
+ goto fix_extent_len;
/*
* The depth, and hence eh & ex might change
* as part of the insert above.
*/
newdepth = ext_depth(inode);
+ /*
+ * update the extent length after successfull insert of the
+ * split extent
+ */
+ orig_ex.ee_len = cpu_to_le16(ee_len -
+ ext4_ext_get_actual_len(ex3));
if (newdepth != depth) {
depth = newdepth;
ext4_ext_drop_refs(path);
@@ -2226,6 +2400,24 @@
goto out;
}
allocated = max_blocks;
+
+ /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying
+ * to insert a extent in the middle zerout directly
+ * otherwise give the extent a chance to merge to left
+ */
+ if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN &&
+ iblock != ee_block) {
+ err = ext4_ext_zeroout(inode, &orig_ex);
+ if (err)
+ goto fix_extent_len;
+ /* update the extent length and mark as initialized */
+ ex->ee_block = orig_ex.ee_block;
+ ex->ee_len = orig_ex.ee_len;
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_dirty(handle, inode, path + depth);
+ /* zero out the first half */
+ return allocated;
+ }
}
/*
* If there was a change of depth as part of the
@@ -2282,8 +2474,29 @@
goto out;
insert:
err = ext4_ext_insert_extent(handle, inode, path, &newex);
+ if (err == -ENOSPC) {
+ err = ext4_ext_zeroout(inode, &orig_ex);
+ if (err)
+ goto fix_extent_len;
+ /* update the extent length and mark as initialized */
+ ex->ee_block = orig_ex.ee_block;
+ ex->ee_len = orig_ex.ee_len;
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_dirty(handle, inode, path + depth);
+ /* zero out the first half */
+ return allocated;
+ } else if (err)
+ goto fix_extent_len;
out:
return err ? err : allocated;
+
+fix_extent_len:
+ ex->ee_block = orig_ex.ee_block;
+ ex->ee_len = orig_ex.ee_len;
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+ ext4_ext_mark_uninitialized(ex);
+ ext4_ext_dirty(handle, inode, path + depth);
+ return err;
}
/*
@@ -2393,8 +2606,20 @@
}
if (create == EXT4_CREATE_UNINITIALIZED_EXT)
goto out;
- if (!create)
+ if (!create) {
+ /*
+ * We have blocks reserved already. We
+ * return allocated blocks so that delalloc
+ * won't do block reservation for us. But
+ * the buffer head will be unmapped so that
+ * a read from the block returns 0s.
+ */
+ if (allocated > max_blocks)
+ allocated = max_blocks;
+ /* mark the buffer unwritten */
+ __set_bit(BH_Unwritten, &bh_result->b_state);
goto out2;
+ }
ret = ext4_ext_convert_to_initialized(handle, inode,
path, iblock,
@@ -2584,6 +2809,8 @@
ext4_orphan_del(handle, inode);
up_write(&EXT4_I(inode)->i_data_sem);
+ inode->i_mtime = inode->i_ctime = ext4_current_time(inode);
+ ext4_mark_inode_dirty(handle, inode);
ext4_journal_stop(handle);
}
@@ -2608,6 +2835,28 @@
return needed;
}
+static void ext4_falloc_update_inode(struct inode *inode,
+ int mode, loff_t new_size, int update_ctime)
+{
+ struct timespec now;
+
+ if (update_ctime) {
+ now = current_fs_time(inode->i_sb);
+ if (!timespec_equal(&inode->i_ctime, &now))
+ inode->i_ctime = now;
+ }
+ /*
+ * Update only when preallocation was requested beyond
+ * the file size.
+ */
+ if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+ new_size > i_size_read(inode)) {
+ i_size_write(inode, new_size);
+ EXT4_I(inode)->i_disksize = new_size;
+ }
+
+}
+
/*
* preallocate space for a file. This implements ext4's fallocate inode
* operation, which gets called from sys_fallocate system call.
@@ -2619,8 +2868,8 @@
{
handle_t *handle;
ext4_lblk_t block;
+ loff_t new_size;
unsigned long max_blocks;
- ext4_fsblk_t nblocks = 0;
int ret = 0;
int ret2 = 0;
int retries = 0;
@@ -2639,9 +2888,12 @@
return -ENODEV;
block = offset >> blkbits;
+ /*
+ * We can't just convert len to max_blocks because
+ * If blocksize = 4096 offset = 3072 and len = 2048
+ */
max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
- - block;
-
+ - block;
/*
* credits to insert 1 extent into extent tree + buffers to be able to
* modify 1 super block, 1 block bitmap and 1 group descriptor.
@@ -2657,7 +2909,6 @@
ret = PTR_ERR(handle);
break;
}
-
ret = ext4_get_blocks_wrap(handle, inode, block,
max_blocks, &map_bh,
EXT4_CREATE_UNINITIALIZED_EXT, 0);
@@ -2673,61 +2924,24 @@
ret2 = ext4_journal_stop(handle);
break;
}
- if (ret > 0) {
- /* check wrap through sign-bit/zero here */
- if ((block + ret) < 0 || (block + ret) < block) {
- ret = -EIO;
- ext4_mark_inode_dirty(handle, inode);
- ret2 = ext4_journal_stop(handle);
- break;
- }
- if (buffer_new(&map_bh) && ((block + ret) >
- (EXT4_BLOCK_ALIGN(i_size_read(inode), blkbits)
- >> blkbits)))
- nblocks = nblocks + ret;
- }
+ if ((block + ret) >= (EXT4_BLOCK_ALIGN(offset + len,
+ blkbits) >> blkbits))
+ new_size = offset + len;
+ else
+ new_size = (block + ret) << blkbits;
- /* Update ctime if new blocks get allocated */
- if (nblocks) {
- struct timespec now;
-
- now = current_fs_time(inode->i_sb);
- if (!timespec_equal(&inode->i_ctime, &now))
- inode->i_ctime = now;
- }
-
+ ext4_falloc_update_inode(inode, mode, new_size,
+ buffer_new(&map_bh));
ext4_mark_inode_dirty(handle, inode);
ret2 = ext4_journal_stop(handle);
if (ret2)
break;
}
-
- if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ if (ret == -ENOSPC &&
+ ext4_should_retry_alloc(inode->i_sb, &retries)) {
+ ret = 0;
goto retry;
-
- /*
- * Time to update the file size.
- * Update only when preallocation was requested beyond the file size.
- */
- if (!(mode & FALLOC_FL_KEEP_SIZE) &&
- (offset + len) > i_size_read(inode)) {
- if (ret > 0) {
- /*
- * if no error, we assume preallocation succeeded
- * completely
- */
- i_size_write(inode, offset + len);
- EXT4_I(inode)->i_disksize = i_size_read(inode);
- } else if (ret < 0 && nblocks) {
- /* Handle partial allocation scenario */
- loff_t newsize;
-
- newsize = (nblocks << blkbits) + i_size_read(inode);
- i_size_write(inode, EXT4_BLOCK_ALIGN(newsize, blkbits));
- EXT4_I(inode)->i_disksize = i_size_read(inode);
- }
}
-
mutex_unlock(&inode->i_mutex);
return ret > 0 ? ret2 : ret;
}
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index ac35ec5..4159be6 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -21,8 +21,8 @@
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
-#include <linux/ext4_jbd2.h>
+#include "ext4.h"
+#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
@@ -129,7 +129,7 @@
.write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = ext4_file_write,
- .ioctl = ext4_ioctl,
+ .unlocked_ioctl = ext4_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = ext4_compat_ioctl,
#endif
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
index 8d50879..1c8ba48 100644
--- a/fs/ext4/fsync.c
+++ b/fs/ext4/fsync.c
@@ -27,8 +27,8 @@
#include <linux/sched.h>
#include <linux/writeback.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
-#include <linux/ext4_jbd2.h>
+#include "ext4.h"
+#include "ext4_jbd2.h"
/*
* akpm: A new design for ext4_sync_file().
@@ -72,6 +72,9 @@
goto out;
}
+ if (datasync && !(inode->i_state & I_DIRTY_DATASYNC))
+ goto out;
+
/*
* The VFS has written the file data. If the inode is unaltered
* then we need not start a commit.
diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c
index 1555024..1d6329d 100644
--- a/fs/ext4/hash.c
+++ b/fs/ext4/hash.c
@@ -11,8 +11,8 @@
#include <linux/fs.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
#include <linux/cryptohash.h>
+#include "ext4.h"
#define DELTA 0x9E3779B9
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index 486e46a..c6efbab0 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -15,8 +15,6 @@
#include <linux/time.h>
#include <linux/fs.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
-#include <linux/ext4_jbd2.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/quotaops.h>
@@ -25,7 +23,8 @@
#include <linux/bitops.h>
#include <linux/blkdev.h>
#include <asm/byteorder.h>
-
+#include "ext4.h"
+#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
#include "group.h"
@@ -75,7 +74,7 @@
/* If checksum is bad mark all blocks and inodes use to prevent
* allocation, essentially implementing a per-group read-only flag. */
if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
- ext4_error(sb, __FUNCTION__, "Checksum bad for group %lu\n",
+ ext4_error(sb, __func__, "Checksum bad for group %lu\n",
block_group);
gdp->bg_free_blocks_count = 0;
gdp->bg_free_inodes_count = 0;
@@ -223,11 +222,9 @@
if (gdp) {
spin_lock(sb_bgl_lock(sbi, block_group));
- gdp->bg_free_inodes_count = cpu_to_le16(
- le16_to_cpu(gdp->bg_free_inodes_count) + 1);
+ le16_add_cpu(&gdp->bg_free_inodes_count, 1);
if (is_directory)
- gdp->bg_used_dirs_count = cpu_to_le16(
- le16_to_cpu(gdp->bg_used_dirs_count) - 1);
+ le16_add_cpu(&gdp->bg_used_dirs_count, -1);
gdp->bg_checksum = ext4_group_desc_csum(sbi,
block_group, gdp);
spin_unlock(sb_bgl_lock(sbi, block_group));
@@ -588,7 +585,7 @@
ino++;
if ((group == 0 && ino < EXT4_FIRST_INO(sb)) ||
ino > EXT4_INODES_PER_GROUP(sb)) {
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"reserved inode or inode > inodes count - "
"block_group = %lu, inode=%lu", group,
ino + group * EXT4_INODES_PER_GROUP(sb));
@@ -664,11 +661,9 @@
cpu_to_le16(EXT4_INODES_PER_GROUP(sb) - ino);
}
- gdp->bg_free_inodes_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
+ le16_add_cpu(&gdp->bg_free_inodes_count, -1);
if (S_ISDIR(mode)) {
- gdp->bg_used_dirs_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
+ le16_add_cpu(&gdp->bg_used_dirs_count, 1);
}
gdp->bg_checksum = ext4_group_desc_csum(sbi, group, gdp);
spin_unlock(sb_bgl_lock(sbi, group));
@@ -744,23 +739,24 @@
if (err)
goto fail_free_drop;
- err = ext4_mark_inode_dirty(handle, inode);
- if (err) {
- ext4_std_error(sb, err);
- goto fail_free_drop;
- }
if (test_opt(sb, EXTENTS)) {
- /* set extent flag only for directory and file */
- if (S_ISDIR(mode) || S_ISREG(mode)) {
+ /* set extent flag only for diretory, file and normal symlink*/
+ if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) {
EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL;
ext4_ext_tree_init(handle, inode);
err = ext4_update_incompat_feature(handle, sb,
EXT4_FEATURE_INCOMPAT_EXTENTS);
if (err)
- goto fail;
+ goto fail_free_drop;
}
}
+ err = ext4_mark_inode_dirty(handle, inode);
+ if (err) {
+ ext4_std_error(sb, err);
+ goto fail_free_drop;
+ }
+
ext4_debug("allocating inode %lu\n", inode->i_ino);
goto really_out;
fail:
@@ -796,7 +792,7 @@
/* Error cases - e2fsck has already cleaned up for us */
if (ino > max_ino) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"bad orphan ino %lu! e2fsck was run?", ino);
goto error;
}
@@ -805,7 +801,7 @@
bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
bitmap_bh = read_inode_bitmap(sb, block_group);
if (!bitmap_bh) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"inode bitmap error for orphan %lu", ino);
goto error;
}
@@ -830,7 +826,7 @@
err = PTR_ERR(inode);
inode = NULL;
bad_orphan:
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"bad orphan inode %lu! e2fsck was run?", ino);
printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
bit, (unsigned long long)bitmap_bh->b_blocknr,
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 8fab233..8d97077 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -25,7 +25,6 @@
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/time.h>
-#include <linux/ext4_jbd2.h>
#include <linux/jbd2.h>
#include <linux/highuid.h>
#include <linux/pagemap.h>
@@ -36,6 +35,7 @@
#include <linux/mpage.h>
#include <linux/uio.h>
#include <linux/bio.h>
+#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
@@ -93,7 +93,7 @@
BUFFER_TRACE(bh, "call ext4_journal_revoke");
err = ext4_journal_revoke(handle, blocknr, bh);
if (err)
- ext4_abort(inode->i_sb, __FUNCTION__,
+ ext4_abort(inode->i_sb, __func__,
"error %d when attempting revoke", err);
BUFFER_TRACE(bh, "exit");
return err;
@@ -985,6 +985,16 @@
} else {
retval = ext4_get_blocks_handle(handle, inode, block,
max_blocks, bh, create, extend_disksize);
+
+ if (retval > 0 && buffer_new(bh)) {
+ /*
+ * We allocated new blocks which will result in
+ * i_data's format changing. Force the migrate
+ * to fail by clearing migrate flags
+ */
+ EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags &
+ ~EXT4_EXT_MIGRATE;
+ }
}
up_write((&EXT4_I(inode)->i_data_sem));
return retval;
@@ -1230,7 +1240,7 @@
{
int err = jbd2_journal_dirty_data(handle, bh);
if (err)
- ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__,
+ ext4_journal_abort_handle(__func__, __func__,
bh, handle, err);
return err;
}
@@ -1301,10 +1311,11 @@
new_i_size = pos + copied;
if (new_i_size > EXT4_I(inode)->i_disksize)
EXT4_I(inode)->i_disksize = new_i_size;
- copied = ext4_generic_write_end(file, mapping, pos, len, copied,
+ ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
page, fsdata);
- if (copied < 0)
- ret = copied;
+ copied = ret2;
+ if (ret2 < 0)
+ ret = ret2;
}
ret2 = ext4_journal_stop(handle);
if (!ret)
@@ -1329,10 +1340,11 @@
if (new_i_size > EXT4_I(inode)->i_disksize)
EXT4_I(inode)->i_disksize = new_i_size;
- copied = ext4_generic_write_end(file, mapping, pos, len, copied,
+ ret2 = ext4_generic_write_end(file, mapping, pos, len, copied,
page, fsdata);
- if (copied < 0)
- ret = copied;
+ copied = ret2;
+ if (ret2 < 0)
+ ret = ret2;
ret2 = ext4_journal_stop(handle);
if (!ret)
@@ -2501,12 +2513,10 @@
static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
unsigned long ino, struct ext4_iloc *iloc)
{
- unsigned long desc, group_desc;
ext4_group_t block_group;
unsigned long offset;
ext4_fsblk_t block;
- struct buffer_head *bh;
- struct ext4_group_desc * gdp;
+ struct ext4_group_desc *gdp;
if (!ext4_valid_inum(sb, ino)) {
/*
@@ -2518,22 +2528,10 @@
}
block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
- if (block_group >= EXT4_SB(sb)->s_groups_count) {
- ext4_error(sb,"ext4_get_inode_block","group >= groups count");
+ gdp = ext4_get_group_desc(sb, block_group, NULL);
+ if (!gdp)
return 0;
- }
- smp_rmb();
- group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
- desc = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
- bh = EXT4_SB(sb)->s_group_desc[group_desc];
- if (!bh) {
- ext4_error (sb, "ext4_get_inode_block",
- "Descriptor not loaded");
- return 0;
- }
- gdp = (struct ext4_group_desc *)((__u8 *)bh->b_data +
- desc * EXT4_DESC_SIZE(sb));
/*
* Figure out the offset within the block group inode table
*/
@@ -2976,7 +2974,8 @@
if (ext4_inode_blocks_set(handle, raw_inode, ei))
goto out_brelse;
raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
- raw_inode->i_flags = cpu_to_le32(ei->i_flags);
+ /* clear the migrate flag in the raw_inode */
+ raw_inode->i_flags = cpu_to_le32(ei->i_flags & ~EXT4_EXT_MIGRATE);
if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
cpu_to_le32(EXT4_OS_HURD))
raw_inode->i_file_acl_high =
@@ -3374,7 +3373,7 @@
EXT4_I(inode)->i_state |= EXT4_STATE_NO_EXPAND;
if (mnt_count !=
le16_to_cpu(sbi->s_es->s_mnt_count)) {
- ext4_warning(inode->i_sb, __FUNCTION__,
+ ext4_warning(inode->i_sb, __func__,
"Unable to expand inode %lu. Delete"
" some EAs or run e2fsck.",
inode->i_ino);
@@ -3415,7 +3414,7 @@
current_handle->h_transaction != handle->h_transaction) {
/* This task has a transaction open against a different fs */
printk(KERN_EMERG "%s: transactions do not match!\n",
- __FUNCTION__);
+ __func__);
} else {
jbd_debug(5, "marking dirty. outer handle=%p\n",
current_handle);
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
index 25b13ed..7a6c2f1 100644
--- a/fs/ext4/ioctl.c
+++ b/fs/ext4/ioctl.c
@@ -10,17 +10,17 @@
#include <linux/fs.h>
#include <linux/jbd2.h>
#include <linux/capability.h>
-#include <linux/ext4_fs.h>
-#include <linux/ext4_jbd2.h>
#include <linux/time.h>
#include <linux/compat.h>
#include <linux/smp_lock.h>
#include <linux/mount.h>
#include <asm/uaccess.h>
+#include "ext4_jbd2.h"
+#include "ext4.h"
-int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
- unsigned long arg)
+long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ struct inode *inode = filp->f_dentry->d_inode;
struct ext4_inode_info *ei = EXT4_I(inode);
unsigned int flags;
unsigned short rsv_window_size;
@@ -277,9 +277,6 @@
#ifdef CONFIG_COMPAT
long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_path.dentry->d_inode;
- int ret;
-
/* These are just misnamed, they actually get/put from/to user an int */
switch (cmd) {
case EXT4_IOC32_GETFLAGS:
@@ -319,9 +316,6 @@
default:
return -ENOIOCTLCMD;
}
- lock_kernel();
- ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
- unlock_kernel();
- return ret;
+ return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg));
}
#endif
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index ef97f19..fbec2ef 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -21,21 +21,7 @@
* mballoc.c contains the multiblocks allocation routines
*/
-#include <linux/time.h>
-#include <linux/fs.h>
-#include <linux/namei.h>
-#include <linux/ext4_jbd2.h>
-#include <linux/ext4_fs.h>
-#include <linux/quotaops.h>
-#include <linux/buffer_head.h>
-#include <linux/module.h>
-#include <linux/swap.h>
-#include <linux/proc_fs.h>
-#include <linux/pagemap.h>
-#include <linux/seq_file.h>
-#include <linux/version.h>
-#include "group.h"
-
+#include "mballoc.h"
/*
* MUSTDO:
* - test ext4_ext_search_left() and ext4_ext_search_right()
@@ -345,288 +331,6 @@
*
*/
-/*
- * with AGGRESSIVE_CHECK allocator runs consistency checks over
- * structures. these checks slow things down a lot
- */
-#define AGGRESSIVE_CHECK__
-
-/*
- * with DOUBLE_CHECK defined mballoc creates persistent in-core
- * bitmaps, maintains and uses them to check for double allocations
- */
-#define DOUBLE_CHECK__
-
-/*
- */
-#define MB_DEBUG__
-#ifdef MB_DEBUG
-#define mb_debug(fmt, a...) printk(fmt, ##a)
-#else
-#define mb_debug(fmt, a...)
-#endif
-
-/*
- * with EXT4_MB_HISTORY mballoc stores last N allocations in memory
- * and you can monitor it in /proc/fs/ext4/<dev>/mb_history
- */
-#define EXT4_MB_HISTORY
-#define EXT4_MB_HISTORY_ALLOC 1 /* allocation */
-#define EXT4_MB_HISTORY_PREALLOC 2 /* preallocated blocks used */
-#define EXT4_MB_HISTORY_DISCARD 4 /* preallocation discarded */
-#define EXT4_MB_HISTORY_FREE 8 /* free */
-
-#define EXT4_MB_HISTORY_DEFAULT (EXT4_MB_HISTORY_ALLOC | \
- EXT4_MB_HISTORY_PREALLOC)
-
-/*
- * How long mballoc can look for a best extent (in found extents)
- */
-#define MB_DEFAULT_MAX_TO_SCAN 200
-
-/*
- * How long mballoc must look for a best extent
- */
-#define MB_DEFAULT_MIN_TO_SCAN 10
-
-/*
- * How many groups mballoc will scan looking for the best chunk
- */
-#define MB_DEFAULT_MAX_GROUPS_TO_SCAN 5
-
-/*
- * with 'ext4_mb_stats' allocator will collect stats that will be
- * shown at umount. The collecting costs though!
- */
-#define MB_DEFAULT_STATS 1
-
-/*
- * files smaller than MB_DEFAULT_STREAM_THRESHOLD are served
- * by the stream allocator, which purpose is to pack requests
- * as close each to other as possible to produce smooth I/O traffic
- * We use locality group prealloc space for stream request.
- * We can tune the same via /proc/fs/ext4/<parition>/stream_req
- */
-#define MB_DEFAULT_STREAM_THRESHOLD 16 /* 64K */
-
-/*
- * for which requests use 2^N search using buddies
- */
-#define MB_DEFAULT_ORDER2_REQS 2
-
-/*
- * default group prealloc size 512 blocks
- */
-#define MB_DEFAULT_GROUP_PREALLOC 512
-
-static struct kmem_cache *ext4_pspace_cachep;
-static struct kmem_cache *ext4_ac_cachep;
-
-#ifdef EXT4_BB_MAX_BLOCKS
-#undef EXT4_BB_MAX_BLOCKS
-#endif
-#define EXT4_BB_MAX_BLOCKS 30
-
-struct ext4_free_metadata {
- ext4_group_t group;
- unsigned short num;
- ext4_grpblk_t blocks[EXT4_BB_MAX_BLOCKS];
- struct list_head list;
-};
-
-struct ext4_group_info {
- unsigned long bb_state;
- unsigned long bb_tid;
- struct ext4_free_metadata *bb_md_cur;
- unsigned short bb_first_free;
- unsigned short bb_free;
- unsigned short bb_fragments;
- struct list_head bb_prealloc_list;
-#ifdef DOUBLE_CHECK
- void *bb_bitmap;
-#endif
- unsigned short bb_counters[];
-};
-
-#define EXT4_GROUP_INFO_NEED_INIT_BIT 0
-#define EXT4_GROUP_INFO_LOCKED_BIT 1
-
-#define EXT4_MB_GRP_NEED_INIT(grp) \
- (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
-
-
-struct ext4_prealloc_space {
- struct list_head pa_inode_list;
- struct list_head pa_group_list;
- union {
- struct list_head pa_tmp_list;
- struct rcu_head pa_rcu;
- } u;
- spinlock_t pa_lock;
- atomic_t pa_count;
- unsigned pa_deleted;
- ext4_fsblk_t pa_pstart; /* phys. block */
- ext4_lblk_t pa_lstart; /* log. block */
- unsigned short pa_len; /* len of preallocated chunk */
- unsigned short pa_free; /* how many blocks are free */
- unsigned short pa_linear; /* consumed in one direction
- * strictly, for grp prealloc */
- spinlock_t *pa_obj_lock;
- struct inode *pa_inode; /* hack, for history only */
-};
-
-
-struct ext4_free_extent {
- ext4_lblk_t fe_logical;
- ext4_grpblk_t fe_start;
- ext4_group_t fe_group;
- int fe_len;
-};
-
-/*
- * Locality group:
- * we try to group all related changes together
- * so that writeback can flush/allocate them together as well
- */
-struct ext4_locality_group {
- /* for allocator */
- struct mutex lg_mutex; /* to serialize allocates */
- struct list_head lg_prealloc_list;/* list of preallocations */
- spinlock_t lg_prealloc_lock;
-};
-
-struct ext4_allocation_context {
- struct inode *ac_inode;
- struct super_block *ac_sb;
-
- /* original request */
- struct ext4_free_extent ac_o_ex;
-
- /* goal request (after normalization) */
- struct ext4_free_extent ac_g_ex;
-
- /* the best found extent */
- struct ext4_free_extent ac_b_ex;
-
- /* copy of the bext found extent taken before preallocation efforts */
- struct ext4_free_extent ac_f_ex;
-
- /* number of iterations done. we have to track to limit searching */
- unsigned long ac_ex_scanned;
- __u16 ac_groups_scanned;
- __u16 ac_found;
- __u16 ac_tail;
- __u16 ac_buddy;
- __u16 ac_flags; /* allocation hints */
- __u8 ac_status;
- __u8 ac_criteria;
- __u8 ac_repeats;
- __u8 ac_2order; /* if request is to allocate 2^N blocks and
- * N > 0, the field stores N, otherwise 0 */
- __u8 ac_op; /* operation, for history only */
- struct page *ac_bitmap_page;
- struct page *ac_buddy_page;
- struct ext4_prealloc_space *ac_pa;
- struct ext4_locality_group *ac_lg;
-};
-
-#define AC_STATUS_CONTINUE 1
-#define AC_STATUS_FOUND 2
-#define AC_STATUS_BREAK 3
-
-struct ext4_mb_history {
- struct ext4_free_extent orig; /* orig allocation */
- struct ext4_free_extent goal; /* goal allocation */
- struct ext4_free_extent result; /* result allocation */
- unsigned pid;
- unsigned ino;
- __u16 found; /* how many extents have been found */
- __u16 groups; /* how many groups have been scanned */
- __u16 tail; /* what tail broke some buddy */
- __u16 buddy; /* buddy the tail ^^^ broke */
- __u16 flags;
- __u8 cr:3; /* which phase the result extent was found at */
- __u8 op:4;
- __u8 merged:1;
-};
-
-struct ext4_buddy {
- struct page *bd_buddy_page;
- void *bd_buddy;
- struct page *bd_bitmap_page;
- void *bd_bitmap;
- struct ext4_group_info *bd_info;
- struct super_block *bd_sb;
- __u16 bd_blkbits;
- ext4_group_t bd_group;
-};
-#define EXT4_MB_BITMAP(e4b) ((e4b)->bd_bitmap)
-#define EXT4_MB_BUDDY(e4b) ((e4b)->bd_buddy)
-
-#ifndef EXT4_MB_HISTORY
-static inline void ext4_mb_store_history(struct ext4_allocation_context *ac)
-{
- return;
-}
-#else
-static void ext4_mb_store_history(struct ext4_allocation_context *ac);
-#endif
-
-#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
-
-static struct proc_dir_entry *proc_root_ext4;
-struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t);
-ext4_fsblk_t ext4_new_blocks_old(handle_t *handle, struct inode *inode,
- ext4_fsblk_t goal, unsigned long *count, int *errp);
-
-static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
- ext4_group_t group);
-static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *);
-static void ext4_mb_free_committed_blocks(struct super_block *);
-static void ext4_mb_return_to_preallocation(struct inode *inode,
- struct ext4_buddy *e4b, sector_t block,
- int count);
-static void ext4_mb_put_pa(struct ext4_allocation_context *,
- struct super_block *, struct ext4_prealloc_space *pa);
-static int ext4_mb_init_per_dev_proc(struct super_block *sb);
-static int ext4_mb_destroy_per_dev_proc(struct super_block *sb);
-
-
-static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group)
-{
- struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
-
- bit_spin_lock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state));
-}
-
-static inline void ext4_unlock_group(struct super_block *sb,
- ext4_group_t group)
-{
- struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
-
- bit_spin_unlock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state));
-}
-
-static inline int ext4_is_group_locked(struct super_block *sb,
- ext4_group_t group)
-{
- struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
-
- return bit_spin_is_locked(EXT4_GROUP_INFO_LOCKED_BIT,
- &(grinfo->bb_state));
-}
-
-static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
- struct ext4_free_extent *fex)
-{
- ext4_fsblk_t block;
-
- block = (ext4_fsblk_t) fex->fe_group * EXT4_BLOCKS_PER_GROUP(sb)
- + fex->fe_start
- + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
- return block;
-}
-
static inline void *mb_correct_addr_and_bit(int *bit, void *addr)
{
#if BITS_PER_LONG == 64
@@ -736,7 +440,7 @@
blocknr +=
le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
- ext4_error(sb, __FUNCTION__, "double-free of inode"
+ ext4_error(sb, __func__, "double-free of inode"
" %lu's block %llu(bit %u in group %lu)\n",
inode ? inode->i_ino : 0, blocknr,
first + i, e4b->bd_group);
@@ -898,17 +602,17 @@
list_for_each(cur, &grp->bb_prealloc_list) {
ext4_group_t groupnr;
struct ext4_prealloc_space *pa;
- pa = list_entry(cur, struct ext4_prealloc_space, group_list);
- ext4_get_group_no_and_offset(sb, pa->pstart, &groupnr, &k);
+ pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list);
+ ext4_get_group_no_and_offset(sb, pa->pa_pstart, &groupnr, &k);
MB_CHECK_ASSERT(groupnr == e4b->bd_group);
- for (i = 0; i < pa->len; i++)
+ for (i = 0; i < pa->pa_len; i++)
MB_CHECK_ASSERT(mb_test_bit(k + i, buddy));
}
return 0;
}
#undef MB_CHECK_ASSERT
#define mb_check_buddy(e4b) __mb_check_buddy(e4b, \
- __FILE__, __FUNCTION__, __LINE__)
+ __FILE__, __func__, __LINE__)
#else
#define mb_check_buddy(e4b)
#endif
@@ -982,7 +686,7 @@
grp->bb_fragments = fragments;
if (free != grp->bb_free) {
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"EXT4-fs: group %lu: %u blocks in bitmap, %u in gd\n",
group, free, grp->bb_free);
/*
@@ -1168,8 +872,9 @@
return err;
}
-static int ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
- struct ext4_buddy *e4b)
+static noinline_for_stack int
+ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group,
+ struct ext4_buddy *e4b)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
struct inode *inode = sbi->s_buddy_cache;
@@ -1367,7 +1072,7 @@
blocknr +=
le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
- ext4_error(sb, __FUNCTION__, "double-free of inode"
+ ext4_error(sb, __func__, "double-free of inode"
" %lu's block %llu(bit %u in group %lu)\n",
inode ? inode->i_ino : 0, blocknr, block,
e4b->bd_group);
@@ -1848,7 +1553,7 @@
* free blocks even though group info says we
* we have free blocks
*/
- ext4_error(sb, __FUNCTION__, "%d free blocks as per "
+ ext4_error(sb, __func__, "%d free blocks as per "
"group info. But bitmap says 0\n",
free);
break;
@@ -1857,7 +1562,7 @@
mb_find_extent(e4b, 0, i, ac->ac_g_ex.fe_len, &ex);
BUG_ON(ex.fe_len <= 0);
if (free < ex.fe_len) {
- ext4_error(sb, __FUNCTION__, "%d free blocks as per "
+ ext4_error(sb, __func__, "%d free blocks as per "
"group info. But got %d blocks\n",
free, ex.fe_len);
/*
@@ -1965,7 +1670,8 @@
return 0;
}
-static int ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
+static noinline_for_stack int
+ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
{
ext4_group_t group;
ext4_group_t i;
@@ -2449,17 +2155,10 @@
int i;
if (sbi->s_mb_proc != NULL) {
- struct proc_dir_entry *p;
- p = create_proc_entry("mb_history", S_IRUGO, sbi->s_mb_proc);
- if (p) {
- p->proc_fops = &ext4_mb_seq_history_fops;
- p->data = sb;
- }
- p = create_proc_entry("mb_groups", S_IRUGO, sbi->s_mb_proc);
- if (p) {
- p->proc_fops = &ext4_mb_seq_groups_fops;
- p->data = sb;
- }
+ proc_create_data("mb_history", S_IRUGO, sbi->s_mb_proc,
+ &ext4_mb_seq_history_fops, sb);
+ proc_create_data("mb_groups", S_IRUGO, sbi->s_mb_proc,
+ &ext4_mb_seq_groups_fops, sb);
}
sbi->s_mb_history_max = 1000;
@@ -2472,7 +2171,8 @@
/* if we can't allocate history, then we simple won't use it */
}
-static void ext4_mb_store_history(struct ext4_allocation_context *ac)
+static noinline_for_stack void
+ext4_mb_store_history(struct ext4_allocation_context *ac)
{
struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb);
struct ext4_mb_history h;
@@ -2572,13 +2272,13 @@
meta_group_info[j] = kzalloc(len, GFP_KERNEL);
if (meta_group_info[j] == NULL) {
printk(KERN_ERR "EXT4-fs: can't allocate buddy mem\n");
- i--;
goto err_freebuddy;
}
desc = ext4_get_group_desc(sb, i, NULL);
if (desc == NULL) {
printk(KERN_ERR
"EXT4-fs: can't read descriptor %lu\n", i);
+ i++;
goto err_freebuddy;
}
memset(meta_group_info[j], 0, len);
@@ -2618,13 +2318,11 @@
return 0;
err_freebuddy:
- while (i >= 0) {
+ while (i-- > 0)
kfree(ext4_get_group_info(sb, i));
- i--;
- }
i = num_meta_group_infos;
err_freemeta:
- while (--i >= 0)
+ while (i-- > 0)
kfree(sbi->s_group_info[i]);
iput(sbi->s_buddy_cache);
err_freesgi:
@@ -2808,7 +2506,8 @@
return 0;
}
-static void ext4_mb_free_committed_blocks(struct super_block *sb)
+static noinline_for_stack void
+ext4_mb_free_committed_blocks(struct super_block *sb)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
int err;
@@ -2867,7 +2566,6 @@
mb_debug("freed %u blocks in %u structures\n", count, count2);
}
-#define EXT4_ROOT "ext4"
#define EXT4_MB_STATS_NAME "stats"
#define EXT4_MB_MAX_TO_SCAN_NAME "max_to_scan"
#define EXT4_MB_MIN_TO_SCAN_NAME "min_to_scan"
@@ -3007,9 +2705,9 @@
return -ENOMEM;
}
#ifdef CONFIG_PROC_FS
- proc_root_ext4 = proc_mkdir(EXT4_ROOT, proc_root_fs);
+ proc_root_ext4 = proc_mkdir("fs/ext4", NULL);
if (proc_root_ext4 == NULL)
- printk(KERN_ERR "EXT4-fs: Unable to create %s\n", EXT4_ROOT);
+ printk(KERN_ERR "EXT4-fs: Unable to create fs/ext4\n");
#endif
return 0;
}
@@ -3020,7 +2718,7 @@
kmem_cache_destroy(ext4_pspace_cachep);
kmem_cache_destroy(ext4_ac_cachep);
#ifdef CONFIG_PROC_FS
- remove_proc_entry(EXT4_ROOT, proc_root_fs);
+ remove_proc_entry("fs/ext4", NULL);
#endif
}
@@ -3029,7 +2727,8 @@
* Check quota and mark choosed space (ac->ac_b_ex) non-free in bitmaps
* Returns 0 if success or error code
*/
-static int ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
+static noinline_for_stack int
+ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
handle_t *handle)
{
struct buffer_head *bitmap_bh = NULL;
@@ -3078,7 +2777,7 @@
in_range(block, ext4_inode_table(sb, gdp),
EXT4_SB(sb)->s_itb_per_group)) {
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"Allocating block in system zone - block = %llu",
block);
}
@@ -3102,9 +2801,7 @@
ac->ac_b_ex.fe_group,
gdp));
}
- gdp->bg_free_blocks_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)
- - ac->ac_b_ex.fe_len);
+ le16_add_cpu(&gdp->bg_free_blocks_count, -ac->ac_b_ex.fe_len);
gdp->bg_checksum = ext4_group_desc_csum(sbi, ac->ac_b_ex.fe_group, gdp);
spin_unlock(sb_bgl_lock(sbi, ac->ac_b_ex.fe_group));
percpu_counter_sub(&sbi->s_freeblocks_counter, ac->ac_b_ex.fe_len);
@@ -3138,7 +2835,7 @@
ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_stripe;
else
ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc;
- mb_debug("#%u: goal %lu blocks for locality group\n",
+ mb_debug("#%u: goal %u blocks for locality group\n",
current->pid, ac->ac_g_ex.fe_len);
}
@@ -3146,15 +2843,16 @@
* Normalization means making request better in terms of
* size and alignment
*/
-static void ext4_mb_normalize_request(struct ext4_allocation_context *ac,
+static noinline_for_stack void
+ext4_mb_normalize_request(struct ext4_allocation_context *ac,
struct ext4_allocation_request *ar)
{
int bsbits, max;
ext4_lblk_t end;
- struct list_head *cur;
loff_t size, orig_size, start_off;
ext4_lblk_t start, orig_start;
struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
+ struct ext4_prealloc_space *pa;
/* do normalize only data requests, metadata requests
do not need preallocation */
@@ -3240,12 +2938,9 @@
/* check we don't cross already preallocated blocks */
rcu_read_lock();
- list_for_each_rcu(cur, &ei->i_prealloc_list) {
- struct ext4_prealloc_space *pa;
+ list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) {
unsigned long pa_end;
- pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list);
-
if (pa->pa_deleted)
continue;
spin_lock(&pa->pa_lock);
@@ -3287,10 +2982,8 @@
/* XXX: extra loop to check we really don't overlap preallocations */
rcu_read_lock();
- list_for_each_rcu(cur, &ei->i_prealloc_list) {
- struct ext4_prealloc_space *pa;
+ list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) {
unsigned long pa_end;
- pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list);
spin_lock(&pa->pa_lock);
if (pa->pa_deleted == 0) {
pa_end = pa->pa_lstart + pa->pa_len;
@@ -3382,7 +3075,7 @@
BUG_ON(pa->pa_free < len);
pa->pa_free -= len;
- mb_debug("use %llu/%lu from inode pa %p\n", start, len, pa);
+ mb_debug("use %llu/%u from inode pa %p\n", start, len, pa);
}
/*
@@ -3412,12 +3105,12 @@
/*
* search goal blocks in preallocated space
*/
-static int ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
+static noinline_for_stack int
+ext4_mb_use_preallocated(struct ext4_allocation_context *ac)
{
struct ext4_inode_info *ei = EXT4_I(ac->ac_inode);
struct ext4_locality_group *lg;
struct ext4_prealloc_space *pa;
- struct list_head *cur;
/* only data can be preallocated */
if (!(ac->ac_flags & EXT4_MB_HINT_DATA))
@@ -3425,8 +3118,7 @@
/* first, try per-file preallocation */
rcu_read_lock();
- list_for_each_rcu(cur, &ei->i_prealloc_list) {
- pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list);
+ list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) {
/* all fields in this condition don't change,
* so we can skip locking for them */
@@ -3458,8 +3150,7 @@
return 0;
rcu_read_lock();
- list_for_each_rcu(cur, &lg->lg_prealloc_list) {
- pa = list_entry(cur, struct ext4_prealloc_space, pa_inode_list);
+ list_for_each_entry_rcu(pa, &lg->lg_prealloc_list, pa_inode_list) {
spin_lock(&pa->pa_lock);
if (pa->pa_deleted == 0 && pa->pa_free >= ac->ac_o_ex.fe_len) {
atomic_inc(&pa->pa_count);
@@ -3579,7 +3270,8 @@
/*
* creates new preallocated space for given inode
*/
-static int ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
+static noinline_for_stack int
+ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
{
struct super_block *sb = ac->ac_sb;
struct ext4_prealloc_space *pa;
@@ -3666,7 +3358,8 @@
/*
* creates new preallocated space for locality group inodes belongs to
*/
-static int ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
+static noinline_for_stack int
+ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
{
struct super_block *sb = ac->ac_sb;
struct ext4_locality_group *lg;
@@ -3739,11 +3432,11 @@
* the caller MUST hold group/inode locks.
* TODO: optimize the case when there are no in-core structures yet
*/
-static int ext4_mb_release_inode_pa(struct ext4_buddy *e4b,
- struct buffer_head *bitmap_bh,
- struct ext4_prealloc_space *pa)
+static noinline_for_stack int
+ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh,
+ struct ext4_prealloc_space *pa,
+ struct ext4_allocation_context *ac)
{
- struct ext4_allocation_context *ac;
struct super_block *sb = e4b->bd_sb;
struct ext4_sb_info *sbi = EXT4_SB(sb);
unsigned long end;
@@ -3759,8 +3452,6 @@
BUG_ON(group != e4b->bd_group && pa->pa_len != 0);
end = bit + pa->pa_len;
- ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
-
if (ac) {
ac->ac_sb = sb;
ac->ac_inode = pa->pa_inode;
@@ -3797,7 +3488,7 @@
pa, (unsigned long) pa->pa_lstart,
(unsigned long) pa->pa_pstart,
(unsigned long) pa->pa_len);
- ext4_error(sb, __FUNCTION__, "free %u, pa_free %u\n",
+ ext4_error(sb, __func__, "free %u, pa_free %u\n",
free, pa->pa_free);
/*
* pa is already deleted so we use the value obtained
@@ -3805,22 +3496,19 @@
*/
}
atomic_add(free, &sbi->s_mb_discarded);
- if (ac)
- kmem_cache_free(ext4_ac_cachep, ac);
return err;
}
-static int ext4_mb_release_group_pa(struct ext4_buddy *e4b,
- struct ext4_prealloc_space *pa)
+static noinline_for_stack int
+ext4_mb_release_group_pa(struct ext4_buddy *e4b,
+ struct ext4_prealloc_space *pa,
+ struct ext4_allocation_context *ac)
{
- struct ext4_allocation_context *ac;
struct super_block *sb = e4b->bd_sb;
ext4_group_t group;
ext4_grpblk_t bit;
- ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
-
if (ac)
ac->ac_op = EXT4_MB_HISTORY_DISCARD;
@@ -3838,7 +3526,6 @@
ac->ac_b_ex.fe_len = pa->pa_len;
ac->ac_b_ex.fe_logical = 0;
ext4_mb_store_history(ac);
- kmem_cache_free(ext4_ac_cachep, ac);
}
return 0;
@@ -3853,12 +3540,14 @@
* - how many do we discard
* 1) how many requested
*/
-static int ext4_mb_discard_group_preallocations(struct super_block *sb,
+static noinline_for_stack int
+ext4_mb_discard_group_preallocations(struct super_block *sb,
ext4_group_t group, int needed)
{
struct ext4_group_info *grp = ext4_get_group_info(sb, group);
struct buffer_head *bitmap_bh = NULL;
struct ext4_prealloc_space *pa, *tmp;
+ struct ext4_allocation_context *ac;
struct list_head list;
struct ext4_buddy e4b;
int err;
@@ -3886,6 +3575,7 @@
grp = ext4_get_group_info(sb, group);
INIT_LIST_HEAD(&list);
+ ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
repeat:
ext4_lock_group(sb, group);
list_for_each_entry_safe(pa, tmp,
@@ -3940,9 +3630,9 @@
spin_unlock(pa->pa_obj_lock);
if (pa->pa_linear)
- ext4_mb_release_group_pa(&e4b, pa);
+ ext4_mb_release_group_pa(&e4b, pa, ac);
else
- ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa);
+ ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac);
list_del(&pa->u.pa_tmp_list);
call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback);
@@ -3950,6 +3640,8 @@
out:
ext4_unlock_group(sb, group);
+ if (ac)
+ kmem_cache_free(ext4_ac_cachep, ac);
ext4_mb_release_desc(&e4b);
put_bh(bitmap_bh);
return free;
@@ -3970,6 +3662,7 @@
struct super_block *sb = inode->i_sb;
struct buffer_head *bitmap_bh = NULL;
struct ext4_prealloc_space *pa, *tmp;
+ struct ext4_allocation_context *ac;
ext4_group_t group = 0;
struct list_head list;
struct ext4_buddy e4b;
@@ -3984,6 +3677,7 @@
INIT_LIST_HEAD(&list);
+ ac = kmem_cache_alloc(ext4_ac_cachep, GFP_NOFS);
repeat:
/* first, collect all pa's in the inode */
spin_lock(&ei->i_prealloc_lock);
@@ -4048,7 +3742,7 @@
ext4_lock_group(sb, group);
list_del(&pa->pa_group_list);
- ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa);
+ ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa, ac);
ext4_unlock_group(sb, group);
ext4_mb_release_desc(&e4b);
@@ -4057,6 +3751,8 @@
list_del(&pa->u.pa_tmp_list);
call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback);
}
+ if (ac)
+ kmem_cache_free(ext4_ac_cachep, ac);
}
/*
@@ -4116,7 +3812,7 @@
printk(KERN_ERR "PA:%lu:%d:%u \n", i,
start, pa->pa_len);
}
- ext4_lock_group(sb, i);
+ ext4_unlock_group(sb, i);
if (grp->bb_free == 0)
continue;
@@ -4175,7 +3871,8 @@
mutex_lock(&ac->ac_lg->lg_mutex);
}
-static int ext4_mb_initialize_context(struct ext4_allocation_context *ac,
+static noinline_for_stack int
+ext4_mb_initialize_context(struct ext4_allocation_context *ac,
struct ext4_allocation_request *ar)
{
struct super_block *sb = ar->inode->i_sb;
@@ -4406,7 +4103,8 @@
ext4_mb_free_committed_blocks(sb);
}
-static int ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
+static noinline_for_stack int
+ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b,
ext4_group_t group, ext4_grpblk_t block, int count)
{
struct ext4_group_info *db = e4b->bd_info;
@@ -4497,7 +4195,7 @@
if (block < le32_to_cpu(es->s_first_data_block) ||
block + count < block ||
block + count > ext4_blocks_count(es)) {
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"Freeing blocks not in datazone - "
"block = %lu, count = %lu", block, count);
goto error_return;
@@ -4538,7 +4236,7 @@
in_range(block + count - 1, ext4_inode_table(sb, gdp),
EXT4_SB(sb)->s_itb_per_group)) {
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"Freeing blocks in system zone - "
"Block = %lu, count = %lu", block, count);
}
@@ -4596,8 +4294,7 @@
}
spin_lock(sb_bgl_lock(sbi, block_group));
- gdp->bg_free_blocks_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) + count);
+ le16_add_cpu(&gdp->bg_free_blocks_count, count);
gdp->bg_checksum = ext4_group_desc_csum(sbi, block_group, gdp);
spin_unlock(sb_bgl_lock(sbi, block_group));
percpu_counter_add(&sbi->s_freeblocks_counter, count);
diff --git a/fs/ext4/mballoc.h b/fs/ext4/mballoc.h
new file mode 100644
index 0000000..bfe6add
--- /dev/null
+++ b/fs/ext4/mballoc.h
@@ -0,0 +1,304 @@
+/*
+ * fs/ext4/mballoc.h
+ *
+ * Written by: Alex Tomas <alex@clusterfs.com>
+ *
+ */
+#ifndef _EXT4_MBALLOC_H
+#define _EXT4_MBALLOC_H
+
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/quotaops.h>
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/swap.h>
+#include <linux/proc_fs.h>
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/version.h>
+#include "ext4_jbd2.h"
+#include "ext4.h"
+#include "group.h"
+
+/*
+ * with AGGRESSIVE_CHECK allocator runs consistency checks over
+ * structures. these checks slow things down a lot
+ */
+#define AGGRESSIVE_CHECK__
+
+/*
+ * with DOUBLE_CHECK defined mballoc creates persistent in-core
+ * bitmaps, maintains and uses them to check for double allocations
+ */
+#define DOUBLE_CHECK__
+
+/*
+ */
+#define MB_DEBUG__
+#ifdef MB_DEBUG
+#define mb_debug(fmt, a...) printk(fmt, ##a)
+#else
+#define mb_debug(fmt, a...)
+#endif
+
+/*
+ * with EXT4_MB_HISTORY mballoc stores last N allocations in memory
+ * and you can monitor it in /proc/fs/ext4/<dev>/mb_history
+ */
+#define EXT4_MB_HISTORY
+#define EXT4_MB_HISTORY_ALLOC 1 /* allocation */
+#define EXT4_MB_HISTORY_PREALLOC 2 /* preallocated blocks used */
+#define EXT4_MB_HISTORY_DISCARD 4 /* preallocation discarded */
+#define EXT4_MB_HISTORY_FREE 8 /* free */
+
+#define EXT4_MB_HISTORY_DEFAULT (EXT4_MB_HISTORY_ALLOC | \
+ EXT4_MB_HISTORY_PREALLOC)
+
+/*
+ * How long mballoc can look for a best extent (in found extents)
+ */
+#define MB_DEFAULT_MAX_TO_SCAN 200
+
+/*
+ * How long mballoc must look for a best extent
+ */
+#define MB_DEFAULT_MIN_TO_SCAN 10
+
+/*
+ * How many groups mballoc will scan looking for the best chunk
+ */
+#define MB_DEFAULT_MAX_GROUPS_TO_SCAN 5
+
+/*
+ * with 'ext4_mb_stats' allocator will collect stats that will be
+ * shown at umount. The collecting costs though!
+ */
+#define MB_DEFAULT_STATS 1
+
+/*
+ * files smaller than MB_DEFAULT_STREAM_THRESHOLD are served
+ * by the stream allocator, which purpose is to pack requests
+ * as close each to other as possible to produce smooth I/O traffic
+ * We use locality group prealloc space for stream request.
+ * We can tune the same via /proc/fs/ext4/<parition>/stream_req
+ */
+#define MB_DEFAULT_STREAM_THRESHOLD 16 /* 64K */
+
+/*
+ * for which requests use 2^N search using buddies
+ */
+#define MB_DEFAULT_ORDER2_REQS 2
+
+/*
+ * default group prealloc size 512 blocks
+ */
+#define MB_DEFAULT_GROUP_PREALLOC 512
+
+static struct kmem_cache *ext4_pspace_cachep;
+static struct kmem_cache *ext4_ac_cachep;
+
+#ifdef EXT4_BB_MAX_BLOCKS
+#undef EXT4_BB_MAX_BLOCKS
+#endif
+#define EXT4_BB_MAX_BLOCKS 30
+
+struct ext4_free_metadata {
+ ext4_group_t group;
+ unsigned short num;
+ ext4_grpblk_t blocks[EXT4_BB_MAX_BLOCKS];
+ struct list_head list;
+};
+
+struct ext4_group_info {
+ unsigned long bb_state;
+ unsigned long bb_tid;
+ struct ext4_free_metadata *bb_md_cur;
+ unsigned short bb_first_free;
+ unsigned short bb_free;
+ unsigned short bb_fragments;
+ struct list_head bb_prealloc_list;
+#ifdef DOUBLE_CHECK
+ void *bb_bitmap;
+#endif
+ unsigned short bb_counters[];
+};
+
+#define EXT4_GROUP_INFO_NEED_INIT_BIT 0
+#define EXT4_GROUP_INFO_LOCKED_BIT 1
+
+#define EXT4_MB_GRP_NEED_INIT(grp) \
+ (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
+
+
+struct ext4_prealloc_space {
+ struct list_head pa_inode_list;
+ struct list_head pa_group_list;
+ union {
+ struct list_head pa_tmp_list;
+ struct rcu_head pa_rcu;
+ } u;
+ spinlock_t pa_lock;
+ atomic_t pa_count;
+ unsigned pa_deleted;
+ ext4_fsblk_t pa_pstart; /* phys. block */
+ ext4_lblk_t pa_lstart; /* log. block */
+ unsigned short pa_len; /* len of preallocated chunk */
+ unsigned short pa_free; /* how many blocks are free */
+ unsigned short pa_linear; /* consumed in one direction
+ * strictly, for grp prealloc */
+ spinlock_t *pa_obj_lock;
+ struct inode *pa_inode; /* hack, for history only */
+};
+
+
+struct ext4_free_extent {
+ ext4_lblk_t fe_logical;
+ ext4_grpblk_t fe_start;
+ ext4_group_t fe_group;
+ int fe_len;
+};
+
+/*
+ * Locality group:
+ * we try to group all related changes together
+ * so that writeback can flush/allocate them together as well
+ */
+struct ext4_locality_group {
+ /* for allocator */
+ struct mutex lg_mutex; /* to serialize allocates */
+ struct list_head lg_prealloc_list;/* list of preallocations */
+ spinlock_t lg_prealloc_lock;
+};
+
+struct ext4_allocation_context {
+ struct inode *ac_inode;
+ struct super_block *ac_sb;
+
+ /* original request */
+ struct ext4_free_extent ac_o_ex;
+
+ /* goal request (after normalization) */
+ struct ext4_free_extent ac_g_ex;
+
+ /* the best found extent */
+ struct ext4_free_extent ac_b_ex;
+
+ /* copy of the bext found extent taken before preallocation efforts */
+ struct ext4_free_extent ac_f_ex;
+
+ /* number of iterations done. we have to track to limit searching */
+ unsigned long ac_ex_scanned;
+ __u16 ac_groups_scanned;
+ __u16 ac_found;
+ __u16 ac_tail;
+ __u16 ac_buddy;
+ __u16 ac_flags; /* allocation hints */
+ __u8 ac_status;
+ __u8 ac_criteria;
+ __u8 ac_repeats;
+ __u8 ac_2order; /* if request is to allocate 2^N blocks and
+ * N > 0, the field stores N, otherwise 0 */
+ __u8 ac_op; /* operation, for history only */
+ struct page *ac_bitmap_page;
+ struct page *ac_buddy_page;
+ struct ext4_prealloc_space *ac_pa;
+ struct ext4_locality_group *ac_lg;
+};
+
+#define AC_STATUS_CONTINUE 1
+#define AC_STATUS_FOUND 2
+#define AC_STATUS_BREAK 3
+
+struct ext4_mb_history {
+ struct ext4_free_extent orig; /* orig allocation */
+ struct ext4_free_extent goal; /* goal allocation */
+ struct ext4_free_extent result; /* result allocation */
+ unsigned pid;
+ unsigned ino;
+ __u16 found; /* how many extents have been found */
+ __u16 groups; /* how many groups have been scanned */
+ __u16 tail; /* what tail broke some buddy */
+ __u16 buddy; /* buddy the tail ^^^ broke */
+ __u16 flags;
+ __u8 cr:3; /* which phase the result extent was found at */
+ __u8 op:4;
+ __u8 merged:1;
+};
+
+struct ext4_buddy {
+ struct page *bd_buddy_page;
+ void *bd_buddy;
+ struct page *bd_bitmap_page;
+ void *bd_bitmap;
+ struct ext4_group_info *bd_info;
+ struct super_block *bd_sb;
+ __u16 bd_blkbits;
+ ext4_group_t bd_group;
+};
+#define EXT4_MB_BITMAP(e4b) ((e4b)->bd_bitmap)
+#define EXT4_MB_BUDDY(e4b) ((e4b)->bd_buddy)
+
+#ifndef EXT4_MB_HISTORY
+static inline void ext4_mb_store_history(struct ext4_allocation_context *ac)
+{
+ return;
+}
+#else
+static void ext4_mb_store_history(struct ext4_allocation_context *ac);
+#endif
+
+#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
+
+static struct proc_dir_entry *proc_root_ext4;
+struct buffer_head *read_block_bitmap(struct super_block *, ext4_group_t);
+
+static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap,
+ ext4_group_t group);
+static void ext4_mb_poll_new_transaction(struct super_block *, handle_t *);
+static void ext4_mb_free_committed_blocks(struct super_block *);
+static void ext4_mb_return_to_preallocation(struct inode *inode,
+ struct ext4_buddy *e4b, sector_t block,
+ int count);
+static void ext4_mb_put_pa(struct ext4_allocation_context *,
+ struct super_block *, struct ext4_prealloc_space *pa);
+static int ext4_mb_init_per_dev_proc(struct super_block *sb);
+static int ext4_mb_destroy_per_dev_proc(struct super_block *sb);
+
+
+static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group)
+{
+ struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
+
+ bit_spin_lock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state));
+}
+
+static inline void ext4_unlock_group(struct super_block *sb,
+ ext4_group_t group)
+{
+ struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
+
+ bit_spin_unlock(EXT4_GROUP_INFO_LOCKED_BIT, &(grinfo->bb_state));
+}
+
+static inline int ext4_is_group_locked(struct super_block *sb,
+ ext4_group_t group)
+{
+ struct ext4_group_info *grinfo = ext4_get_group_info(sb, group);
+
+ return bit_spin_is_locked(EXT4_GROUP_INFO_LOCKED_BIT,
+ &(grinfo->bb_state));
+}
+
+static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
+ struct ext4_free_extent *fex)
+{
+ ext4_fsblk_t block;
+
+ block = (ext4_fsblk_t) fex->fe_group * EXT4_BLOCKS_PER_GROUP(sb)
+ + fex->fe_start
+ + le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
+ return block;
+}
+#endif
diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
index 5c1e27d..b9e077b 100644
--- a/fs/ext4/migrate.c
+++ b/fs/ext4/migrate.c
@@ -13,8 +13,8 @@
*/
#include <linux/module.h>
-#include <linux/ext4_jbd2.h>
-#include <linux/ext4_fs_extents.h>
+#include "ext4_jbd2.h"
+#include "ext4_extents.h"
/*
* The contiguous blocks details which can be
@@ -327,7 +327,7 @@
}
static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode,
- struct inode *tmp_inode)
+ struct inode *tmp_inode)
{
int retval;
__le32 i_data[3];
@@ -339,7 +339,7 @@
* i_data field of the original inode
*/
retval = ext4_journal_extend(handle, 1);
- if (retval != 0) {
+ if (retval) {
retval = ext4_journal_restart(handle, 1);
if (retval)
goto err_out;
@@ -351,6 +351,18 @@
down_write(&EXT4_I(inode)->i_data_sem);
/*
+ * if EXT4_EXT_MIGRATE is cleared a block allocation
+ * happened after we started the migrate. We need to
+ * fail the migrate
+ */
+ if (!(EXT4_I(inode)->i_flags & EXT4_EXT_MIGRATE)) {
+ retval = -EAGAIN;
+ up_write(&EXT4_I(inode)->i_data_sem);
+ goto err_out;
+ } else
+ EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags &
+ ~EXT4_EXT_MIGRATE;
+ /*
* We have the extent map build with the tmp inode.
* Now copy the i_data across
*/
@@ -508,6 +520,17 @@
* switch the inode format to prevent read.
*/
mutex_lock(&(inode->i_mutex));
+ /*
+ * Even though we take i_mutex we can still cause block allocation
+ * via mmap write to holes. If we have allocated new blocks we fail
+ * migrate. New block allocation will clear EXT4_EXT_MIGRATE flag.
+ * The flag is updated with i_data_sem held to prevent racing with
+ * block allocation.
+ */
+ down_read((&EXT4_I(inode)->i_data_sem));
+ EXT4_I(inode)->i_flags = EXT4_I(inode)->i_flags | EXT4_EXT_MIGRATE;
+ up_read((&EXT4_I(inode)->i_data_sem));
+
handle = ext4_journal_start(inode, 1);
ei = EXT4_I(inode);
@@ -559,9 +582,15 @@
* tmp_inode
*/
free_ext_block(handle, tmp_inode);
- else
- retval = ext4_ext_swap_inode_data(handle, inode,
- tmp_inode);
+ else {
+ retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode);
+ if (retval)
+ /*
+ * if we fail to swap inode data free the extent
+ * details of the tmp inode
+ */
+ free_ext_block(handle, tmp_inode);
+ }
/* We mark the tmp_inode dirty via ext4_ext_tree_init. */
if (ext4_journal_extend(handle, 1) != 0)
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 28aa2ed..ab16bea 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -28,14 +28,14 @@
#include <linux/pagemap.h>
#include <linux/jbd2.h>
#include <linux/time.h>
-#include <linux/ext4_fs.h>
-#include <linux/ext4_jbd2.h>
#include <linux/fcntl.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/quotaops.h>
#include <linux/buffer_head.h>
#include <linux/bio.h>
+#include "ext4.h"
+#include "ext4_jbd2.h"
#include "namei.h"
#include "xattr.h"
@@ -57,10 +57,15 @@
*block = inode->i_size >> inode->i_sb->s_blocksize_bits;
- if ((bh = ext4_bread(handle, inode, *block, 1, err))) {
+ bh = ext4_bread(handle, inode, *block, 1, err);
+ if (bh) {
inode->i_size += inode->i_sb->s_blocksize;
EXT4_I(inode)->i_disksize = inode->i_size;
- ext4_journal_get_write_access(handle,bh);
+ *err = ext4_journal_get_write_access(handle, bh);
+ if (*err) {
+ brelse(bh);
+ bh = NULL;
+ }
}
return bh;
}
@@ -348,7 +353,7 @@
if (root->info.hash_version != DX_HASH_TEA &&
root->info.hash_version != DX_HASH_HALF_MD4 &&
root->info.hash_version != DX_HASH_LEGACY) {
- ext4_warning(dir->i_sb, __FUNCTION__,
+ ext4_warning(dir->i_sb, __func__,
"Unrecognised inode hash code %d",
root->info.hash_version);
brelse(bh);
@@ -362,7 +367,7 @@
hash = hinfo->hash;
if (root->info.unused_flags & 1) {
- ext4_warning(dir->i_sb, __FUNCTION__,
+ ext4_warning(dir->i_sb, __func__,
"Unimplemented inode hash flags: %#06x",
root->info.unused_flags);
brelse(bh);
@@ -371,7 +376,7 @@
}
if ((indirect = root->info.indirect_levels) > 1) {
- ext4_warning(dir->i_sb, __FUNCTION__,
+ ext4_warning(dir->i_sb, __func__,
"Unimplemented inode hash depth: %#06x",
root->info.indirect_levels);
brelse(bh);
@@ -384,7 +389,7 @@
if (dx_get_limit(entries) != dx_root_limit(dir,
root->info.info_length)) {
- ext4_warning(dir->i_sb, __FUNCTION__,
+ ext4_warning(dir->i_sb, __func__,
"dx entry: limit != root limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
@@ -396,7 +401,7 @@
{
count = dx_get_count(entries);
if (!count || count > dx_get_limit(entries)) {
- ext4_warning(dir->i_sb, __FUNCTION__,
+ ext4_warning(dir->i_sb, __func__,
"dx entry: no count or count > limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
@@ -441,7 +446,7 @@
goto fail2;
at = entries = ((struct dx_node *) bh->b_data)->entries;
if (dx_get_limit(entries) != dx_node_limit (dir)) {
- ext4_warning(dir->i_sb, __FUNCTION__,
+ ext4_warning(dir->i_sb, __func__,
"dx entry: limit != node limit");
brelse(bh);
*err = ERR_BAD_DX_DIR;
@@ -457,7 +462,7 @@
}
fail:
if (*err == ERR_BAD_DX_DIR)
- ext4_warning(dir->i_sb, __FUNCTION__,
+ ext4_warning(dir->i_sb, __func__,
"Corrupt dir inode %ld, running e2fsck is "
"recommended.", dir->i_ino);
return NULL;
@@ -914,7 +919,7 @@
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
/* read error, skip block & hope for the best */
- ext4_error(sb, __FUNCTION__, "reading directory #%lu "
+ ext4_error(sb, __func__, "reading directory #%lu "
"offset %lu", dir->i_ino,
(unsigned long)block);
brelse(bh);
@@ -1007,7 +1012,7 @@
retval = ext4_htree_next_block(dir, hash, frame,
frames, NULL);
if (retval < 0) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"error reading index page in directory #%lu",
dir->i_ino);
*err = retval;
@@ -1532,7 +1537,7 @@
if (levels && (dx_get_count(frames->entries) ==
dx_get_limit(frames->entries))) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Directory index full!");
err = -ENOSPC;
goto cleanup;
@@ -1860,11 +1865,11 @@
if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||
!(bh = ext4_bread (NULL, inode, 0, 0, &err))) {
if (err)
- ext4_error(inode->i_sb, __FUNCTION__,
+ ext4_error(inode->i_sb, __func__,
"error %d reading directory #%lu offset 0",
err, inode->i_ino);
else
- ext4_warning(inode->i_sb, __FUNCTION__,
+ ext4_warning(inode->i_sb, __func__,
"bad directory (dir #%lu) - no data block",
inode->i_ino);
return 1;
@@ -1893,7 +1898,7 @@
offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err);
if (!bh) {
if (err)
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"error %d reading directory"
" #%lu offset %lu",
err, inode->i_ino, offset);
@@ -2217,6 +2222,8 @@
goto out_stop;
}
} else {
+ /* clear the extent format for fast symlink */
+ EXT4_I(inode)->i_flags &= ~EXT4_EXTENTS_FL;
inode->i_op = &ext4_fast_symlink_inode_operations;
memcpy((char*)&EXT4_I(inode)->i_data,symname,l);
inode->i_size = l-1;
@@ -2347,6 +2354,9 @@
EXT4_FEATURE_INCOMPAT_FILETYPE))
new_de->file_type = old_de->file_type;
new_dir->i_version++;
+ new_dir->i_ctime = new_dir->i_mtime =
+ ext4_current_time(new_dir);
+ ext4_mark_inode_dirty(handle, new_dir);
BUFFER_TRACE(new_bh, "call ext4_journal_dirty_metadata");
ext4_journal_dirty_metadata(handle, new_bh);
brelse(new_bh);
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
index e29efa0..9f086a6 100644
--- a/fs/ext4/resize.c
+++ b/fs/ext4/resize.c
@@ -11,11 +11,10 @@
#define EXT4FS_DEBUG
-#include <linux/ext4_jbd2.h>
-
#include <linux/errno.h>
#include <linux/slab.h>
+#include "ext4_jbd2.h"
#include "group.h"
#define outside(b, first, last) ((b) < (first) || (b) >= (last))
@@ -50,63 +49,63 @@
ext4_get_group_no_and_offset(sb, start, NULL, &offset);
if (group != sbi->s_groups_count)
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Cannot add at group %u (only %lu groups)",
input->group, sbi->s_groups_count);
else if (offset != 0)
- ext4_warning(sb, __FUNCTION__, "Last group not full");
+ ext4_warning(sb, __func__, "Last group not full");
else if (input->reserved_blocks > input->blocks_count / 5)
- ext4_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)",
+ ext4_warning(sb, __func__, "Reserved blocks too high (%u)",
input->reserved_blocks);
else if (free_blocks_count < 0)
- ext4_warning(sb, __FUNCTION__, "Bad blocks count %u",
+ ext4_warning(sb, __func__, "Bad blocks count %u",
input->blocks_count);
else if (!(bh = sb_bread(sb, end - 1)))
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Cannot read last block (%llu)",
end - 1);
else if (outside(input->block_bitmap, start, end))
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Block bitmap not in group (block %llu)",
(unsigned long long)input->block_bitmap);
else if (outside(input->inode_bitmap, start, end))
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Inode bitmap not in group (block %llu)",
(unsigned long long)input->inode_bitmap);
else if (outside(input->inode_table, start, end) ||
outside(itend - 1, start, end))
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Inode table not in group (blocks %llu-%llu)",
(unsigned long long)input->inode_table, itend - 1);
else if (input->inode_bitmap == input->block_bitmap)
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Block bitmap same as inode bitmap (%llu)",
(unsigned long long)input->block_bitmap);
else if (inside(input->block_bitmap, input->inode_table, itend))
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Block bitmap (%llu) in inode table (%llu-%llu)",
(unsigned long long)input->block_bitmap,
(unsigned long long)input->inode_table, itend - 1);
else if (inside(input->inode_bitmap, input->inode_table, itend))
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Inode bitmap (%llu) in inode table (%llu-%llu)",
(unsigned long long)input->inode_bitmap,
(unsigned long long)input->inode_table, itend - 1);
else if (inside(input->block_bitmap, start, metaend))
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Block bitmap (%llu) in GDT table"
" (%llu-%llu)",
(unsigned long long)input->block_bitmap,
start, metaend - 1);
else if (inside(input->inode_bitmap, start, metaend))
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Inode bitmap (%llu) in GDT table"
" (%llu-%llu)",
(unsigned long long)input->inode_bitmap,
start, metaend - 1);
else if (inside(input->inode_table, start, metaend) ||
inside(itend - 1, start, metaend))
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Inode table (%llu-%llu) overlaps"
"GDT table (%llu-%llu)",
(unsigned long long)input->inode_table,
@@ -368,7 +367,7 @@
while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) {
if (le32_to_cpu(*p++) !=
grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"reserved GDT %llu"
" missing grp %d (%llu)",
blk, grp,
@@ -424,7 +423,7 @@
*/
if (EXT4_SB(sb)->s_sbh->b_blocknr !=
le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"won't resize using backup superblock at %llu",
(unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr);
return -EPERM;
@@ -448,7 +447,7 @@
data = (__le32 *)dind->b_data;
if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"new group %u GDT block %llu not reserved",
input->group, gdblock);
err = -EINVAL;
@@ -469,10 +468,10 @@
goto exit_dindj;
n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *),
- GFP_KERNEL);
+ GFP_NOFS);
if (!n_group_desc) {
err = -ENOMEM;
- ext4_warning (sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"not enough memory for %lu groups", gdb_num + 1);
goto exit_inode;
}
@@ -502,8 +501,7 @@
EXT4_SB(sb)->s_gdb_count++;
kfree(o_group_desc);
- es->s_reserved_gdt_blocks =
- cpu_to_le16(le16_to_cpu(es->s_reserved_gdt_blocks) - 1);
+ le16_add_cpu(&es->s_reserved_gdt_blocks, -1);
ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
return 0;
@@ -553,7 +551,7 @@
int res, i;
int err;
- primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_KERNEL);
+ primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_NOFS);
if (!primary)
return -ENOMEM;
@@ -571,7 +569,7 @@
/* Get each reserved primary GDT block and verify it holds backups */
for (res = 0; res < reserved_gdb; res++, blk++) {
if (le32_to_cpu(*data) != blk) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"reserved block %llu"
" not at offset %ld",
blk,
@@ -715,7 +713,7 @@
*/
exit_err:
if (err) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"can't update backup for group %lu (err %d), "
"forcing fsck on next reboot", group, err);
sbi->s_mount_state &= ~EXT4_VALID_FS;
@@ -755,33 +753,33 @@
if (gdb_off == 0 && !EXT4_HAS_RO_COMPAT_FEATURE(sb,
EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Can't resize non-sparse filesystem further");
return -EPERM;
}
if (ext4_blocks_count(es) + input->blocks_count <
ext4_blocks_count(es)) {
- ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n");
+ ext4_warning(sb, __func__, "blocks_count overflow\n");
return -EINVAL;
}
if (le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb) <
le32_to_cpu(es->s_inodes_count)) {
- ext4_warning(sb, __FUNCTION__, "inodes_count overflow\n");
+ ext4_warning(sb, __func__, "inodes_count overflow\n");
return -EINVAL;
}
if (reserved_gdb || gdb_off == 0) {
if (!EXT4_HAS_COMPAT_FEATURE(sb,
EXT4_FEATURE_COMPAT_RESIZE_INODE)){
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"No reserved GDT blocks, can't resize");
return -EPERM;
}
inode = ext4_iget(sb, EXT4_RESIZE_INO);
if (IS_ERR(inode)) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"Error opening resize inode");
return PTR_ERR(inode);
}
@@ -810,7 +808,7 @@
lock_super(sb);
if (input->group != sbi->s_groups_count) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"multiple resizers run on filesystem!");
err = -EBUSY;
goto exit_journal;
@@ -877,8 +875,7 @@
*/
ext4_blocks_count_set(es, ext4_blocks_count(es) +
input->blocks_count);
- es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) +
- EXT4_INODES_PER_GROUP(sb));
+ le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb));
/*
* We need to protect s_groups_count against other CPUs seeing
@@ -977,13 +974,13 @@
" too large to resize to %llu blocks safely\n",
sb->s_id, n_blocks_count);
if (sizeof(sector_t) < 8)
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"CONFIG_LBD not enabled\n");
return -EINVAL;
}
if (n_blocks_count < o_blocks_count) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"can't shrink FS - resize aborted");
return -EBUSY;
}
@@ -992,7 +989,7 @@
ext4_get_group_no_and_offset(sb, o_blocks_count, NULL, &last);
if (last == 0) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"need to use ext2online to resize further");
return -EPERM;
}
@@ -1000,7 +997,7 @@
add = EXT4_BLOCKS_PER_GROUP(sb) - last;
if (o_blocks_count + add < o_blocks_count) {
- ext4_warning(sb, __FUNCTION__, "blocks_count overflow");
+ ext4_warning(sb, __func__, "blocks_count overflow");
return -EINVAL;
}
@@ -1008,7 +1005,7 @@
add = n_blocks_count - o_blocks_count;
if (o_blocks_count + add < n_blocks_count)
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"will only finish group (%llu"
" blocks, %u new)",
o_blocks_count + add, add);
@@ -1016,7 +1013,7 @@
/* See if the device is actually as big as what was requested */
bh = sb_bread(sb, o_blocks_count + add -1);
if (!bh) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"can't read last block, resize aborted");
return -ENOSPC;
}
@@ -1028,13 +1025,13 @@
handle = ext4_journal_start_sb(sb, 3);
if (IS_ERR(handle)) {
err = PTR_ERR(handle);
- ext4_warning(sb, __FUNCTION__, "error %d on journal start",err);
+ ext4_warning(sb, __func__, "error %d on journal start", err);
goto exit_put;
}
lock_super(sb);
if (o_blocks_count != ext4_blocks_count(es)) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"multiple resizers run on filesystem!");
unlock_super(sb);
ext4_journal_stop(handle);
@@ -1044,7 +1041,7 @@
if ((err = ext4_journal_get_write_access(handle,
EXT4_SB(sb)->s_sbh))) {
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"error %d on journal write access", err);
unlock_super(sb);
ext4_journal_stop(handle);
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index c81a8e7..52dd067 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -21,8 +21,6 @@
#include <linux/fs.h>
#include <linux/time.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
-#include <linux/ext4_jbd2.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/blkdev.h>
@@ -38,9 +36,10 @@
#include <linux/seq_file.h>
#include <linux/log2.h>
#include <linux/crc16.h>
-
#include <asm/uaccess.h>
+#include "ext4.h"
+#include "ext4_jbd2.h"
#include "xattr.h"
#include "acl.h"
#include "namei.h"
@@ -135,7 +134,7 @@
* take the FS itself readonly cleanly. */
journal = EXT4_SB(sb)->s_journal;
if (is_journal_aborted(journal)) {
- ext4_abort(sb, __FUNCTION__,
+ ext4_abort(sb, __func__,
"Detected aborted journal");
return ERR_PTR(-EROFS);
}
@@ -355,7 +354,7 @@
if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV)
return;
- ext4_warning(sb, __FUNCTION__,
+ ext4_warning(sb, __func__,
"updating to rev %d because of new feature flag, "
"running e2fsck is recommended",
EXT4_DYNAMIC_REV);
@@ -945,8 +944,8 @@
{Opt_mballoc, "mballoc"},
{Opt_nomballoc, "nomballoc"},
{Opt_stripe, "stripe=%u"},
- {Opt_err, NULL},
{Opt_resize, "resize"},
+ {Opt_err, NULL},
};
static ext4_fsblk_t get_sb_block(void **data)
@@ -1388,11 +1387,11 @@
* a plain journaled filesystem we can keep it set as
* valid forever! :)
*/
- es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT4_VALID_FS);
+ es->s_state &= cpu_to_le16(~EXT4_VALID_FS);
#endif
if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT);
- es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
+ le16_add_cpu(&es->s_mnt_count, 1);
es->s_mtime = cpu_to_le32(get_seconds());
ext4_update_dynamic_rev(sb);
EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
@@ -1485,36 +1484,33 @@
block_bitmap = ext4_block_bitmap(sb, gdp);
if (block_bitmap < first_block || block_bitmap > last_block)
{
- ext4_error (sb, "ext4_check_descriptors",
- "Block bitmap for group %lu"
- " not in group (block %llu)!",
- i, block_bitmap);
+ printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+ "Block bitmap for group %lu not in group "
+ "(block %llu)!", i, block_bitmap);
return 0;
}
inode_bitmap = ext4_inode_bitmap(sb, gdp);
if (inode_bitmap < first_block || inode_bitmap > last_block)
{
- ext4_error (sb, "ext4_check_descriptors",
- "Inode bitmap for group %lu"
- " not in group (block %llu)!",
- i, inode_bitmap);
+ printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+ "Inode bitmap for group %lu not in group "
+ "(block %llu)!", i, inode_bitmap);
return 0;
}
inode_table = ext4_inode_table(sb, gdp);
if (inode_table < first_block ||
inode_table + sbi->s_itb_per_group - 1 > last_block)
{
- ext4_error (sb, "ext4_check_descriptors",
- "Inode table for group %lu"
- " not in group (block %llu)!",
- i, inode_table);
+ printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+ "Inode table for group %lu not in group "
+ "(block %llu)!", i, inode_table);
return 0;
}
if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
- ext4_error(sb, __FUNCTION__,
- "Checksum for group %lu failed (%u!=%u)\n",
- i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
- gdp)), le16_to_cpu(gdp->bg_checksum));
+ printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+ "Checksum for group %lu failed (%u!=%u)\n",
+ i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
+ gdp)), le16_to_cpu(gdp->bg_checksum));
return 0;
}
if (!flexbg_flag)
@@ -1594,8 +1590,8 @@
while (es->s_last_orphan) {
struct inode *inode;
- if (!(inode =
- ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) {
+ inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan));
+ if (IS_ERR(inode)) {
es->s_last_orphan = 0;
break;
}
@@ -1605,7 +1601,7 @@
if (inode->i_nlink) {
printk(KERN_DEBUG
"%s: truncating inode %lu to %Ld bytes\n",
- __FUNCTION__, inode->i_ino, inode->i_size);
+ __func__, inode->i_ino, inode->i_size);
jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
inode->i_ino, inode->i_size);
ext4_truncate(inode);
@@ -1613,7 +1609,7 @@
} else {
printk(KERN_DEBUG
"%s: deleting unreferenced inode %lu\n",
- __FUNCTION__, inode->i_ino);
+ __func__, inode->i_ino);
jbd_debug(2, "deleting unreferenced inode %lu\n",
inode->i_ino);
nr_orphans++;
@@ -2699,9 +2695,9 @@
char nbuf[16];
errstr = ext4_decode_error(sb, j_errno, nbuf);
- ext4_warning(sb, __FUNCTION__, "Filesystem error recorded "
+ ext4_warning(sb, __func__, "Filesystem error recorded "
"from previous mount: %s", errstr);
- ext4_warning(sb, __FUNCTION__, "Marking fs in need of "
+ ext4_warning(sb, __func__, "Marking fs in need of "
"filesystem check.");
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
@@ -2828,7 +2824,7 @@
}
if (sbi->s_mount_opt & EXT4_MOUNT_ABORT)
- ext4_abort(sb, __FUNCTION__, "Abort forced by user");
+ ext4_abort(sb, __func__, "Abort forced by user");
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
@@ -3040,8 +3036,14 @@
/* We may delete quota structure so we need to reserve enough blocks */
handle = ext4_journal_start(inode, 2*EXT4_QUOTA_DEL_BLOCKS(inode->i_sb));
- if (IS_ERR(handle))
+ if (IS_ERR(handle)) {
+ /*
+ * We call dquot_drop() anyway to at least release references
+ * to quota structures so that umount does not hang.
+ */
+ dquot_drop(inode);
return PTR_ERR(handle);
+ }
ret = dquot_drop(inode);
err = ext4_journal_stop(handle);
if (!ret)
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index e6f9da4..e917864 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -19,8 +19,8 @@
#include <linux/fs.h>
#include <linux/jbd2.h>
-#include <linux/ext4_fs.h>
#include <linux/namei.h>
+#include "ext4.h"
#include "xattr.h"
static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index e9054c1..3fbc2c6 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -53,11 +53,11 @@
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
-#include <linux/ext4_jbd2.h>
-#include <linux/ext4_fs.h>
#include <linux/mbcache.h>
#include <linux/quotaops.h>
#include <linux/rwsem.h>
+#include "ext4_jbd2.h"
+#include "ext4.h"
#include "xattr.h"
#include "acl.h"
@@ -92,6 +92,8 @@
struct mb_cache_entry **);
static void ext4_xattr_rehash(struct ext4_xattr_header *,
struct ext4_xattr_entry *);
+static int ext4_xattr_list(struct inode *inode, char *buffer,
+ size_t buffer_size);
static struct mb_cache *ext4_xattr_cache;
@@ -225,7 +227,7 @@
ea_bdebug(bh, "b_count=%d, refcount=%d",
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext4_xattr_check_block(bh)) {
-bad_block: ext4_error(inode->i_sb, __FUNCTION__,
+bad_block: ext4_error(inode->i_sb, __func__,
"inode %lu: bad block %llu", inode->i_ino,
EXT4_I(inode)->i_file_acl);
error = -EIO;
@@ -367,7 +369,7 @@
ea_bdebug(bh, "b_count=%d, refcount=%d",
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext4_xattr_check_block(bh)) {
- ext4_error(inode->i_sb, __FUNCTION__,
+ ext4_error(inode->i_sb, __func__,
"inode %lu: bad block %llu", inode->i_ino,
EXT4_I(inode)->i_file_acl);
error = -EIO;
@@ -420,7 +422,7 @@
* Returns a negative error number on failure, or the number of bytes
* used / required on success.
*/
-int
+static int
ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
{
int i_error, b_error;
@@ -484,8 +486,7 @@
get_bh(bh);
ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
} else {
- BHDR(bh)->h_refcount = cpu_to_le32(
- le32_to_cpu(BHDR(bh)->h_refcount) - 1);
+ le32_add_cpu(&BHDR(bh)->h_refcount, -1);
error = ext4_journal_dirty_metadata(handle, bh);
if (IS_SYNC(inode))
handle->h_sync = 1;
@@ -660,7 +661,7 @@
atomic_read(&(bs->bh->b_count)),
le32_to_cpu(BHDR(bs->bh)->h_refcount));
if (ext4_xattr_check_block(bs->bh)) {
- ext4_error(sb, __FUNCTION__,
+ ext4_error(sb, __func__,
"inode %lu: bad block %llu", inode->i_ino,
EXT4_I(inode)->i_file_acl);
error = -EIO;
@@ -738,7 +739,7 @@
ce = NULL;
}
ea_bdebug(bs->bh, "cloning");
- s->base = kmalloc(bs->bh->b_size, GFP_KERNEL);
+ s->base = kmalloc(bs->bh->b_size, GFP_NOFS);
error = -ENOMEM;
if (s->base == NULL)
goto cleanup;
@@ -750,7 +751,7 @@
}
} else {
/* Allocate a buffer where we construct the new block. */
- s->base = kzalloc(sb->s_blocksize, GFP_KERNEL);
+ s->base = kzalloc(sb->s_blocksize, GFP_NOFS);
/* assert(header == s->base) */
error = -ENOMEM;
if (s->base == NULL)
@@ -789,8 +790,7 @@
if (error)
goto cleanup_dquot;
lock_buffer(new_bh);
- BHDR(new_bh)->h_refcount = cpu_to_le32(1 +
- le32_to_cpu(BHDR(new_bh)->h_refcount));
+ le32_add_cpu(&BHDR(new_bh)->h_refcount, 1);
ea_bdebug(new_bh, "reusing; refcount now=%d",
le32_to_cpu(BHDR(new_bh)->h_refcount));
unlock_buffer(new_bh);
@@ -808,10 +808,8 @@
get_bh(new_bh);
} else {
/* We need to allocate a new block */
- ext4_fsblk_t goal = le32_to_cpu(
- EXT4_SB(sb)->s_es->s_first_data_block) +
- (ext4_fsblk_t)EXT4_I(inode)->i_block_group *
- EXT4_BLOCKS_PER_GROUP(sb);
+ ext4_fsblk_t goal = ext4_group_first_block_no(sb,
+ EXT4_I(inode)->i_block_group);
ext4_fsblk_t block = ext4_new_block(handle, inode,
goal, &error);
if (error)
@@ -863,7 +861,7 @@
goto cleanup;
bad_block:
- ext4_error(inode->i_sb, __FUNCTION__,
+ ext4_error(inode->i_sb, __func__,
"inode %lu: bad block %llu", inode->i_ino,
EXT4_I(inode)->i_file_acl);
goto cleanup;
@@ -1166,7 +1164,7 @@
if (!bh)
goto cleanup;
if (ext4_xattr_check_block(bh)) {
- ext4_error(inode->i_sb, __FUNCTION__,
+ ext4_error(inode->i_sb, __func__,
"inode %lu: bad block %llu", inode->i_ino,
EXT4_I(inode)->i_file_acl);
error = -EIO;
@@ -1341,14 +1339,14 @@
goto cleanup;
bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
if (!bh) {
- ext4_error(inode->i_sb, __FUNCTION__,
+ ext4_error(inode->i_sb, __func__,
"inode %lu: block %llu read error", inode->i_ino,
EXT4_I(inode)->i_file_acl);
goto cleanup;
}
if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
BHDR(bh)->h_blocks != cpu_to_le32(1)) {
- ext4_error(inode->i_sb, __FUNCTION__,
+ ext4_error(inode->i_sb, __func__,
"inode %lu: bad block %llu", inode->i_ino,
EXT4_I(inode)->i_file_acl);
goto cleanup;
@@ -1475,7 +1473,7 @@
}
bh = sb_bread(inode->i_sb, ce->e_block);
if (!bh) {
- ext4_error(inode->i_sb, __FUNCTION__,
+ ext4_error(inode->i_sb, __func__,
"inode %lu: block %lu read error",
inode->i_ino, (unsigned long) ce->e_block);
} else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index d7f5d6a..5992fe9 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -74,7 +74,6 @@
extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
-extern int ext4_xattr_list(struct inode *, char *, size_t);
extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
@@ -99,12 +98,6 @@
}
static inline int
-ext4_xattr_list(struct inode *inode, void *buffer, size_t size)
-{
- return -EOPNOTSUPP;
-}
-
-static inline int
ext4_xattr_set(struct inode *inode, int name_index, const char *name,
const void *value, size_t size, int flags)
{
diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c
index f17eaf2..ca5f89f 100644
--- a/fs/ext4/xattr_security.c
+++ b/fs/ext4/xattr_security.c
@@ -6,9 +6,9 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
-#include <linux/ext4_jbd2.h>
-#include <linux/ext4_fs.h>
#include <linux/security.h>
+#include "ext4_jbd2.h"
+#include "ext4.h"
#include "xattr.h"
static size_t
diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c
index e0f05ac..fff3338 100644
--- a/fs/ext4/xattr_trusted.c
+++ b/fs/ext4/xattr_trusted.c
@@ -9,8 +9,8 @@
#include <linux/string.h>
#include <linux/capability.h>
#include <linux/fs.h>
-#include <linux/ext4_jbd2.h>
-#include <linux/ext4_fs.h>
+#include "ext4_jbd2.h"
+#include "ext4.h"
#include "xattr.h"
#define XATTR_TRUSTED_PREFIX "trusted."
diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c
index 7ed3d8e..67be723 100644
--- a/fs/ext4/xattr_user.c
+++ b/fs/ext4/xattr_user.c
@@ -8,8 +8,8 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/fs.h>
-#include <linux/ext4_jbd2.h>
-#include <linux/ext4_fs.h>
+#include "ext4_jbd2.h"
+#include "ext4.h"
#include "xattr.h"
#define XATTR_USER_PREFIX "user."
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 639b3b4..fda25479 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -242,7 +242,7 @@
/* prevent the infinite loop of cluster chain */
if (*fclus > limit) {
fat_fs_panic(sb, "%s: detected the cluster chain loop"
- " (i_pos %lld)", __FUNCTION__,
+ " (i_pos %lld)", __func__,
MSDOS_I(inode)->i_pos);
nr = -EIO;
goto out;
@@ -253,7 +253,7 @@
goto out;
else if (nr == FAT_ENT_FREE) {
fat_fs_panic(sb, "%s: invalid cluster chain"
- " (i_pos %lld)", __FUNCTION__,
+ " (i_pos %lld)", __func__,
MSDOS_I(inode)->i_pos);
nr = -EIO;
goto out;
@@ -286,7 +286,7 @@
return ret;
else if (ret == FAT_ENT_EOF) {
fat_fs_panic(sb, "%s: request beyond EOF (i_pos %lld)",
- __FUNCTION__, MSDOS_I(inode)->i_pos);
+ __func__, MSDOS_I(inode)->i_pos);
return -EIO;
}
return dclus;
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c
index 13ab763..302e95c 100644
--- a/fs/fat/fatent.c
+++ b/fs/fat/fatent.c
@@ -546,7 +546,7 @@
goto error;
} else if (cluster == FAT_ENT_FREE) {
fat_fs_panic(sb, "%s: deleting FAT entry beyond EOF",
- __FUNCTION__);
+ __func__);
err = -EIO;
goto error;
}
diff --git a/fs/fat/file.c b/fs/fat/file.c
index d604bb1..27cc116 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -208,7 +208,7 @@
} else if (ret == FAT_ENT_FREE) {
fat_fs_panic(sb,
"%s: invalid cluster chain (i_pos %lld)",
- __FUNCTION__, MSDOS_I(inode)->i_pos);
+ __func__, MSDOS_I(inode)->i_pos);
ret = -EIO;
} else if (ret > 0) {
err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait);
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 5f522a5..4e0a3dd 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -1222,8 +1222,7 @@
brelse(bh);
goto out_invalid;
}
- logical_sector_size =
- le16_to_cpu(get_unaligned((__le16 *)&b->sector_size));
+ logical_sector_size = get_unaligned_le16(&b->sector_size);
if (!is_power_of_2(logical_sector_size)
|| (logical_sector_size < 512)
|| (logical_sector_size > 4096)) {
@@ -1322,8 +1321,7 @@
sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
- sbi->dir_entries =
- le16_to_cpu(get_unaligned((__le16 *)&b->dir_entries));
+ sbi->dir_entries = get_unaligned_le16(&b->dir_entries);
if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
if (!silent)
printk(KERN_ERR "FAT: bogus directroy-entries per block"
@@ -1335,7 +1333,7 @@
rootdir_sectors = sbi->dir_entries
* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
sbi->data_start = sbi->dir_start + rootdir_sectors;
- total_sectors = le16_to_cpu(get_unaligned((__le16 *)&b->sectors));
+ total_sectors = get_unaligned_le16(&b->sectors);
if (total_sectors == 0)
total_sectors = le32_to_cpu(b->total_sect);
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 3f3ac63..bfd7765 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -9,6 +9,7 @@
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/capability.h>
#include <linux/dnotify.h>
#include <linux/smp_lock.h>
diff --git a/fs/file.c b/fs/file.c
index 5110acb..4c6f0ea 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
@@ -149,8 +150,16 @@
nr /= (1024 / sizeof(struct file *));
nr = roundup_pow_of_two(nr + 1);
nr *= (1024 / sizeof(struct file *));
- if (nr > sysctl_nr_open)
- nr = sysctl_nr_open;
+ /*
+ * Note that this can drive nr *below* what we had passed if sysctl_nr_open
+ * had been set lower between the check in expand_files() and here. Deal
+ * with that in caller, it's cheaper that way.
+ *
+ * We make sure that nr remains a multiple of BITS_PER_LONG - otherwise
+ * bitmaps handling below becomes unpleasant, to put it mildly...
+ */
+ if (unlikely(nr > sysctl_nr_open))
+ nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1;
fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL);
if (!fdt)
@@ -199,6 +208,16 @@
if (!new_fdt)
return -ENOMEM;
/*
+ * extremely unlikely race - sysctl_nr_open decreased between the check in
+ * caller and alloc_fdtable(). Cheaper to catch it here...
+ */
+ if (unlikely(new_fdt->max_fds <= nr)) {
+ free_fdarr(new_fdt);
+ free_fdset(new_fdt);
+ kfree(new_fdt);
+ return -EMFILE;
+ }
+ /*
* Check again since another task may have expanded the fd table while
* we dropped the lock
*/
diff --git a/fs/file_table.c b/fs/file_table.c
index 7a0a9b8..8308422 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -8,6 +8,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h
index 2b46064..50ab5ee 100644
--- a/fs/freevxfs/vxfs_extern.h
+++ b/fs/freevxfs/vxfs_extern.h
@@ -50,7 +50,11 @@
/* vxfs_fshead.c */
extern int vxfs_read_fshead(struct super_block *);
+/* vxfs_immed.c */
+extern const struct inode_operations vxfs_immed_symlink_iops;
+
/* vxfs_inode.c */
+extern const struct address_space_operations vxfs_immed_aops;
extern struct kmem_cache *vxfs_inode_cachep;
extern void vxfs_dumpi(struct vxfs_inode_info *, ino_t);
extern struct inode * vxfs_get_fake_inode(struct super_block *,
@@ -69,6 +73,7 @@
extern int vxfs_read_olt(struct super_block *, u_long);
/* vxfs_subr.c */
+extern const struct address_space_operations vxfs_aops;
extern struct page * vxfs_get_page(struct address_space *, u_long);
extern void vxfs_put_page(struct page *);
extern struct buffer_head * vxfs_bread(struct inode *, int);
diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c
index 8a5959a..c36aeaf 100644
--- a/fs/freevxfs/vxfs_immed.c
+++ b/fs/freevxfs/vxfs_immed.c
@@ -35,6 +35,7 @@
#include <linux/namei.h>
#include "vxfs.h"
+#include "vxfs_extern.h"
#include "vxfs_inode.h"
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index ad88d23..9f3f2ce 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -41,11 +41,6 @@
#include "vxfs_extern.h"
-extern const struct address_space_operations vxfs_aops;
-extern const struct address_space_operations vxfs_immed_aops;
-
-extern const struct inode_operations vxfs_immed_symlink_iops;
-
struct kmem_cache *vxfs_inode_cachep;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 0655767..ae45f77 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -25,6 +25,45 @@
#include <linux/buffer_head.h>
#include "internal.h"
+
+/**
+ * writeback_acquire - attempt to get exclusive writeback access to a device
+ * @bdi: the device's backing_dev_info structure
+ *
+ * It is a waste of resources to have more than one pdflush thread blocked on
+ * a single request queue. Exclusion at the request_queue level is obtained
+ * via a flag in the request_queue's backing_dev_info.state.
+ *
+ * Non-request_queue-backed address_spaces will share default_backing_dev_info,
+ * unless they implement their own. Which is somewhat inefficient, as this
+ * may prevent concurrent writeback against multiple devices.
+ */
+static int writeback_acquire(struct backing_dev_info *bdi)
+{
+ return !test_and_set_bit(BDI_pdflush, &bdi->state);
+}
+
+/**
+ * writeback_in_progress - determine whether there is writeback in progress
+ * @bdi: the device's backing_dev_info structure.
+ *
+ * Determine whether there is writeback in progress against a backing device.
+ */
+int writeback_in_progress(struct backing_dev_info *bdi)
+{
+ return test_bit(BDI_pdflush, &bdi->state);
+}
+
+/**
+ * writeback_release - relinquish exclusive writeback access against a device.
+ * @bdi: the device's backing_dev_info structure
+ */
+static void writeback_release(struct backing_dev_info *bdi)
+{
+ BUG_ON(!writeback_in_progress(bdi));
+ clear_bit(BDI_pdflush, &bdi->state);
+}
+
/**
* __mark_inode_dirty - internal function
* @inode: inode to mark
@@ -747,43 +786,4 @@
return err;
}
-
EXPORT_SYMBOL(generic_osync_inode);
-
-/**
- * writeback_acquire - attempt to get exclusive writeback access to a device
- * @bdi: the device's backing_dev_info structure
- *
- * It is a waste of resources to have more than one pdflush thread blocked on
- * a single request queue. Exclusion at the request_queue level is obtained
- * via a flag in the request_queue's backing_dev_info.state.
- *
- * Non-request_queue-backed address_spaces will share default_backing_dev_info,
- * unless they implement their own. Which is somewhat inefficient, as this
- * may prevent concurrent writeback against multiple devices.
- */
-int writeback_acquire(struct backing_dev_info *bdi)
-{
- return !test_and_set_bit(BDI_pdflush, &bdi->state);
-}
-
-/**
- * writeback_in_progress - determine whether there is writeback in progress
- * @bdi: the device's backing_dev_info structure.
- *
- * Determine whether there is writeback in progress against a backing device.
- */
-int writeback_in_progress(struct backing_dev_info *bdi)
-{
- return test_bit(BDI_pdflush, &bdi->state);
-}
-
-/**
- * writeback_release - relinquish exclusive writeback access against a device.
- * @bdi: the device's backing_dev_info structure
- */
-void writeback_release(struct backing_dev_info *bdi)
-{
- BUG_ON(!writeback_in_progress(bdi));
- clear_bit(BDI_pdflush, &bdi->state);
-}
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index 105d4a2..4f3cab3 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -117,7 +117,7 @@
parent = fuse_control_sb->s_root;
inc_nlink(parent->d_inode);
- sprintf(name, "%llu", (unsigned long long) fc->id);
+ sprintf(name, "%u", fc->dev);
parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
&simple_dir_inode_operations,
&simple_dir_operations);
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index af639807..87250b6 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -47,6 +47,14 @@
return req;
}
+struct fuse_req *fuse_request_alloc_nofs(void)
+{
+ struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_NOFS);
+ if (req)
+ fuse_request_init(req);
+ return req;
+}
+
void fuse_request_free(struct fuse_req *req)
{
kmem_cache_free(fuse_req_cachep, req);
@@ -291,6 +299,7 @@
static void wait_answer_interruptible(struct fuse_conn *fc,
struct fuse_req *req)
+ __releases(fc->lock) __acquires(fc->lock)
{
if (signal_pending(current))
return;
@@ -307,8 +316,8 @@
kill_fasync(&fc->fasync, SIGIO, POLL_IN);
}
-/* Called with fc->lock held. Releases, and then reacquires it. */
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
+ __releases(fc->lock) __acquires(fc->lock)
{
if (!fc->no_interrupt) {
/* Any signal may interrupt this */
@@ -430,6 +439,17 @@
}
/*
+ * Called under fc->lock
+ *
+ * fc->connected must have been checked previously
+ */
+void request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req)
+{
+ req->isreply = 1;
+ request_send_nowait_locked(fc, req);
+}
+
+/*
* Lock the request. Up to the next unlock_request() there mustn't be
* anything that could cause a page-fault. If the request was already
* aborted bail out.
@@ -968,6 +988,7 @@
* locked).
*/
static void end_io_requests(struct fuse_conn *fc)
+ __releases(fc->lock) __acquires(fc->lock)
{
while (!list_empty(&fc->io)) {
struct fuse_req *req =
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index c4807b3..2060bf0 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -132,7 +132,7 @@
req->out.args[0].value = outarg;
}
-static u64 fuse_get_attr_version(struct fuse_conn *fc)
+u64 fuse_get_attr_version(struct fuse_conn *fc)
{
u64 curr_version;
@@ -1107,6 +1107,50 @@
}
/*
+ * Prevent concurrent writepages on inode
+ *
+ * This is done by adding a negative bias to the inode write counter
+ * and waiting for all pending writes to finish.
+ */
+void fuse_set_nowrite(struct inode *inode)
+{
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ BUG_ON(!mutex_is_locked(&inode->i_mutex));
+
+ spin_lock(&fc->lock);
+ BUG_ON(fi->writectr < 0);
+ fi->writectr += FUSE_NOWRITE;
+ spin_unlock(&fc->lock);
+ wait_event(fi->page_waitq, fi->writectr == FUSE_NOWRITE);
+}
+
+/*
+ * Allow writepages on inode
+ *
+ * Remove the bias from the writecounter and send any queued
+ * writepages.
+ */
+static void __fuse_release_nowrite(struct inode *inode)
+{
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ BUG_ON(fi->writectr != FUSE_NOWRITE);
+ fi->writectr = 0;
+ fuse_flush_writepages(inode);
+}
+
+void fuse_release_nowrite(struct inode *inode)
+{
+ struct fuse_conn *fc = get_fuse_conn(inode);
+
+ spin_lock(&fc->lock);
+ __fuse_release_nowrite(inode);
+ spin_unlock(&fc->lock);
+}
+
+/*
* Set attributes, and at the same time refresh them.
*
* Truncation is slightly complicated, because the 'truncate' request
@@ -1122,6 +1166,8 @@
struct fuse_req *req;
struct fuse_setattr_in inarg;
struct fuse_attr_out outarg;
+ bool is_truncate = false;
+ loff_t oldsize;
int err;
if (!fuse_allow_task(fc, current))
@@ -1145,12 +1191,16 @@
send_sig(SIGXFSZ, current, 0);
return -EFBIG;
}
+ is_truncate = true;
}
req = fuse_get_req(fc);
if (IS_ERR(req))
return PTR_ERR(req);
+ if (is_truncate)
+ fuse_set_nowrite(inode);
+
memset(&inarg, 0, sizeof(inarg));
memset(&outarg, 0, sizeof(outarg));
iattr_to_fattr(attr, &inarg);
@@ -1181,16 +1231,44 @@
if (err) {
if (err == -EINTR)
fuse_invalidate_attr(inode);
- return err;
+ goto error;
}
if ((inode->i_mode ^ outarg.attr.mode) & S_IFMT) {
make_bad_inode(inode);
- return -EIO;
+ err = -EIO;
+ goto error;
}
- fuse_change_attributes(inode, &outarg.attr, attr_timeout(&outarg), 0);
+ spin_lock(&fc->lock);
+ fuse_change_attributes_common(inode, &outarg.attr,
+ attr_timeout(&outarg));
+ oldsize = inode->i_size;
+ i_size_write(inode, outarg.attr.size);
+
+ if (is_truncate) {
+ /* NOTE: this may release/reacquire fc->lock */
+ __fuse_release_nowrite(inode);
+ }
+ spin_unlock(&fc->lock);
+
+ /*
+ * Only call invalidate_inode_pages2() after removing
+ * FUSE_NOWRITE, otherwise fuse_launder_page() would deadlock.
+ */
+ if (S_ISREG(inode->i_mode) && oldsize != outarg.attr.size) {
+ if (outarg.attr.size < oldsize)
+ fuse_truncate(inode->i_mapping, outarg.attr.size);
+ invalidate_inode_pages2(inode->i_mapping);
+ }
+
return 0;
+
+error:
+ if (is_truncate)
+ fuse_release_nowrite(inode);
+
+ return err;
}
static int fuse_setattr(struct dentry *entry, struct iattr *attr)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 676b0bc..f28cf8b 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -210,6 +210,49 @@
return (u64) v0 + ((u64) v1 << 32);
}
+/*
+ * Check if page is under writeback
+ *
+ * This is currently done by walking the list of writepage requests
+ * for the inode, which can be pretty inefficient.
+ */
+static bool fuse_page_is_writeback(struct inode *inode, pgoff_t index)
+{
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ struct fuse_req *req;
+ bool found = false;
+
+ spin_lock(&fc->lock);
+ list_for_each_entry(req, &fi->writepages, writepages_entry) {
+ pgoff_t curr_index;
+
+ BUG_ON(req->inode != inode);
+ curr_index = req->misc.write.in.offset >> PAGE_CACHE_SHIFT;
+ if (curr_index == index) {
+ found = true;
+ break;
+ }
+ }
+ spin_unlock(&fc->lock);
+
+ return found;
+}
+
+/*
+ * Wait for page writeback to be completed.
+ *
+ * Since fuse doesn't rely on the VM writeback tracking, this has to
+ * use some other means.
+ */
+static int fuse_wait_on_page_writeback(struct inode *inode, pgoff_t index)
+{
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ wait_event(fi->page_waitq, !fuse_page_is_writeback(inode, index));
+ return 0;
+}
+
static int fuse_flush(struct file *file, fl_owner_t id)
{
struct inode *inode = file->f_path.dentry->d_inode;
@@ -245,6 +288,21 @@
return err;
}
+/*
+ * Wait for all pending writepages on the inode to finish.
+ *
+ * This is currently done by blocking further writes with FUSE_NOWRITE
+ * and waiting for all sent writes to complete.
+ *
+ * This must be called under i_mutex, otherwise the FUSE_NOWRITE usage
+ * could conflict with truncation.
+ */
+static void fuse_sync_writes(struct inode *inode)
+{
+ fuse_set_nowrite(inode);
+ fuse_release_nowrite(inode);
+}
+
int fuse_fsync_common(struct file *file, struct dentry *de, int datasync,
int isdir)
{
@@ -261,6 +319,17 @@
if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir))
return 0;
+ /*
+ * Start writeback against all dirty pages of the inode, then
+ * wait for all outstanding writes, before sending the FSYNC
+ * request.
+ */
+ err = write_inode_now(inode, 0);
+ if (err)
+ return err;
+
+ fuse_sync_writes(inode);
+
req = fuse_get_req(fc);
if (IS_ERR(req))
return PTR_ERR(req);
@@ -294,7 +363,7 @@
void fuse_read_fill(struct fuse_req *req, struct file *file,
struct inode *inode, loff_t pos, size_t count, int opcode)
{
- struct fuse_read_in *inarg = &req->misc.read_in;
+ struct fuse_read_in *inarg = &req->misc.read.in;
struct fuse_file *ff = file->private_data;
inarg->fh = ff->fh;
@@ -320,7 +389,7 @@
fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
if (owner != NULL) {
- struct fuse_read_in *inarg = &req->misc.read_in;
+ struct fuse_read_in *inarg = &req->misc.read.in;
inarg->read_flags |= FUSE_READ_LOCKOWNER;
inarg->lock_owner = fuse_lock_owner_id(fc, owner);
@@ -329,31 +398,66 @@
return req->out.args[0].size;
}
+static void fuse_read_update_size(struct inode *inode, loff_t size,
+ u64 attr_ver)
+{
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ spin_lock(&fc->lock);
+ if (attr_ver == fi->attr_version && size < inode->i_size) {
+ fi->attr_version = ++fc->attr_version;
+ i_size_write(inode, size);
+ }
+ spin_unlock(&fc->lock);
+}
+
static int fuse_readpage(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
+ size_t num_read;
+ loff_t pos = page_offset(page);
+ size_t count = PAGE_CACHE_SIZE;
+ u64 attr_ver;
int err;
err = -EIO;
if (is_bad_inode(inode))
goto out;
+ /*
+ * Page writeback can extend beyond the liftime of the
+ * page-cache page, so make sure we read a properly synced
+ * page.
+ */
+ fuse_wait_on_page_writeback(inode, page->index);
+
req = fuse_get_req(fc);
err = PTR_ERR(req);
if (IS_ERR(req))
goto out;
+ attr_ver = fuse_get_attr_version(fc);
+
req->out.page_zeroing = 1;
req->num_pages = 1;
req->pages[0] = page;
- fuse_send_read(req, file, inode, page_offset(page), PAGE_CACHE_SIZE,
- NULL);
+ num_read = fuse_send_read(req, file, inode, pos, count, NULL);
err = req->out.h.error;
fuse_put_request(fc, req);
- if (!err)
+
+ if (!err) {
+ /*
+ * Short read means EOF. If file size is larger, truncate it
+ */
+ if (num_read < count)
+ fuse_read_update_size(inode, pos + num_read, attr_ver);
+
SetPageUptodate(page);
+ }
+
fuse_invalidate_attr(inode); /* atime changed */
out:
unlock_page(page);
@@ -363,8 +467,19 @@
static void fuse_readpages_end(struct fuse_conn *fc, struct fuse_req *req)
{
int i;
+ size_t count = req->misc.read.in.size;
+ size_t num_read = req->out.args[0].size;
+ struct inode *inode = req->pages[0]->mapping->host;
- fuse_invalidate_attr(req->pages[0]->mapping->host); /* atime changed */
+ /*
+ * Short read means EOF. If file size is larger, truncate it
+ */
+ if (!req->out.h.error && num_read < count) {
+ loff_t pos = page_offset(req->pages[0]) + num_read;
+ fuse_read_update_size(inode, pos, req->misc.read.attr_ver);
+ }
+
+ fuse_invalidate_attr(inode); /* atime changed */
for (i = 0; i < req->num_pages; i++) {
struct page *page = req->pages[i];
@@ -387,6 +502,7 @@
size_t count = req->num_pages << PAGE_CACHE_SHIFT;
req->out.page_zeroing = 1;
fuse_read_fill(req, file, inode, pos, count, FUSE_READ);
+ req->misc.read.attr_ver = fuse_get_attr_version(fc);
if (fc->async_read) {
struct fuse_file *ff = file->private_data;
req->ff = fuse_file_get(ff);
@@ -411,6 +527,8 @@
struct inode *inode = data->inode;
struct fuse_conn *fc = get_fuse_conn(inode);
+ fuse_wait_on_page_writeback(inode, page->index);
+
if (req->num_pages &&
(req->num_pages == FUSE_MAX_PAGES_PER_REQ ||
(req->num_pages + 1) * PAGE_CACHE_SIZE > fc->max_read ||
@@ -477,11 +595,10 @@
}
static void fuse_write_fill(struct fuse_req *req, struct file *file,
- struct inode *inode, loff_t pos, size_t count,
- int writepage)
+ struct fuse_file *ff, struct inode *inode,
+ loff_t pos, size_t count, int writepage)
{
struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_file *ff = file->private_data;
struct fuse_write_in *inarg = &req->misc.write.in;
struct fuse_write_out *outarg = &req->misc.write.out;
@@ -490,7 +607,7 @@
inarg->offset = pos;
inarg->size = count;
inarg->write_flags = writepage ? FUSE_WRITE_CACHE : 0;
- inarg->flags = file->f_flags;
+ inarg->flags = file ? file->f_flags : 0;
req->in.h.opcode = FUSE_WRITE;
req->in.h.nodeid = get_node_id(inode);
req->in.argpages = 1;
@@ -511,7 +628,7 @@
fl_owner_t owner)
{
struct fuse_conn *fc = get_fuse_conn(inode);
- fuse_write_fill(req, file, inode, pos, count, 0);
+ fuse_write_fill(req, file, file->private_data, inode, pos, count, 0);
if (owner != NULL) {
struct fuse_write_in *inarg = &req->misc.write.in;
inarg->write_flags |= FUSE_WRITE_LOCKOWNER;
@@ -533,19 +650,36 @@
return 0;
}
+static void fuse_write_update_size(struct inode *inode, loff_t pos)
+{
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ spin_lock(&fc->lock);
+ fi->attr_version = ++fc->attr_version;
+ if (pos > inode->i_size)
+ i_size_write(inode, pos);
+ spin_unlock(&fc->lock);
+}
+
static int fuse_buffered_write(struct file *file, struct inode *inode,
loff_t pos, unsigned count, struct page *page)
{
int err;
size_t nres;
struct fuse_conn *fc = get_fuse_conn(inode);
- struct fuse_inode *fi = get_fuse_inode(inode);
unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
struct fuse_req *req;
if (is_bad_inode(inode))
return -EIO;
+ /*
+ * Make sure writepages on the same page are not mixed up with
+ * plain writes.
+ */
+ fuse_wait_on_page_writeback(inode, page->index);
+
req = fuse_get_req(fc);
if (IS_ERR(req))
return PTR_ERR(req);
@@ -560,12 +694,7 @@
err = -EIO;
if (!err) {
pos += nres;
- spin_lock(&fc->lock);
- fi->attr_version = ++fc->attr_version;
- if (pos > inode->i_size)
- i_size_write(inode, pos);
- spin_unlock(&fc->lock);
-
+ fuse_write_update_size(inode, pos);
if (count == PAGE_CACHE_SIZE)
SetPageUptodate(page);
}
@@ -588,6 +717,198 @@
return res;
}
+static size_t fuse_send_write_pages(struct fuse_req *req, struct file *file,
+ struct inode *inode, loff_t pos,
+ size_t count)
+{
+ size_t res;
+ unsigned offset;
+ unsigned i;
+
+ for (i = 0; i < req->num_pages; i++)
+ fuse_wait_on_page_writeback(inode, req->pages[i]->index);
+
+ res = fuse_send_write(req, file, inode, pos, count, NULL);
+
+ offset = req->page_offset;
+ count = res;
+ for (i = 0; i < req->num_pages; i++) {
+ struct page *page = req->pages[i];
+
+ if (!req->out.h.error && !offset && count >= PAGE_CACHE_SIZE)
+ SetPageUptodate(page);
+
+ if (count > PAGE_CACHE_SIZE - offset)
+ count -= PAGE_CACHE_SIZE - offset;
+ else
+ count = 0;
+ offset = 0;
+
+ unlock_page(page);
+ page_cache_release(page);
+ }
+
+ return res;
+}
+
+static ssize_t fuse_fill_write_pages(struct fuse_req *req,
+ struct address_space *mapping,
+ struct iov_iter *ii, loff_t pos)
+{
+ struct fuse_conn *fc = get_fuse_conn(mapping->host);
+ unsigned offset = pos & (PAGE_CACHE_SIZE - 1);
+ size_t count = 0;
+ int err;
+
+ req->page_offset = offset;
+
+ do {
+ size_t tmp;
+ struct page *page;
+ pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+ size_t bytes = min_t(size_t, PAGE_CACHE_SIZE - offset,
+ iov_iter_count(ii));
+
+ bytes = min_t(size_t, bytes, fc->max_write - count);
+
+ again:
+ err = -EFAULT;
+ if (iov_iter_fault_in_readable(ii, bytes))
+ break;
+
+ err = -ENOMEM;
+ page = __grab_cache_page(mapping, index);
+ if (!page)
+ break;
+
+ pagefault_disable();
+ tmp = iov_iter_copy_from_user_atomic(page, ii, offset, bytes);
+ pagefault_enable();
+ flush_dcache_page(page);
+
+ if (!tmp) {
+ unlock_page(page);
+ page_cache_release(page);
+ bytes = min(bytes, iov_iter_single_seg_count(ii));
+ goto again;
+ }
+
+ err = 0;
+ req->pages[req->num_pages] = page;
+ req->num_pages++;
+
+ iov_iter_advance(ii, tmp);
+ count += tmp;
+ pos += tmp;
+ offset += tmp;
+ if (offset == PAGE_CACHE_SIZE)
+ offset = 0;
+
+ } while (iov_iter_count(ii) && count < fc->max_write &&
+ req->num_pages < FUSE_MAX_PAGES_PER_REQ && offset == 0);
+
+ return count > 0 ? count : err;
+}
+
+static ssize_t fuse_perform_write(struct file *file,
+ struct address_space *mapping,
+ struct iov_iter *ii, loff_t pos)
+{
+ struct inode *inode = mapping->host;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ int err = 0;
+ ssize_t res = 0;
+
+ if (is_bad_inode(inode))
+ return -EIO;
+
+ do {
+ struct fuse_req *req;
+ ssize_t count;
+
+ req = fuse_get_req(fc);
+ if (IS_ERR(req)) {
+ err = PTR_ERR(req);
+ break;
+ }
+
+ count = fuse_fill_write_pages(req, mapping, ii, pos);
+ if (count <= 0) {
+ err = count;
+ } else {
+ size_t num_written;
+
+ num_written = fuse_send_write_pages(req, file, inode,
+ pos, count);
+ err = req->out.h.error;
+ if (!err) {
+ res += num_written;
+ pos += num_written;
+
+ /* break out of the loop on short write */
+ if (num_written != count)
+ err = -EIO;
+ }
+ }
+ fuse_put_request(fc, req);
+ } while (!err && iov_iter_count(ii));
+
+ if (res > 0)
+ fuse_write_update_size(inode, pos);
+
+ fuse_invalidate_attr(inode);
+
+ return res > 0 ? res : err;
+}
+
+static ssize_t fuse_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ size_t count = 0;
+ ssize_t written = 0;
+ struct inode *inode = mapping->host;
+ ssize_t err;
+ struct iov_iter i;
+
+ WARN_ON(iocb->ki_pos != pos);
+
+ err = generic_segment_checks(iov, &nr_segs, &count, VERIFY_READ);
+ if (err)
+ return err;
+
+ mutex_lock(&inode->i_mutex);
+ vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
+
+ /* We can write back this queue in page reclaim */
+ current->backing_dev_info = mapping->backing_dev_info;
+
+ err = generic_write_checks(file, &pos, &count, S_ISBLK(inode->i_mode));
+ if (err)
+ goto out;
+
+ if (count == 0)
+ goto out;
+
+ err = remove_suid(file->f_path.dentry);
+ if (err)
+ goto out;
+
+ file_update_time(file);
+
+ iov_iter_init(&i, iov, nr_segs, count, 0);
+ written = fuse_perform_write(file, mapping, &i, pos);
+ if (written >= 0)
+ iocb->ki_pos = pos + written;
+
+out:
+ current->backing_dev_info = NULL;
+ mutex_unlock(&inode->i_mutex);
+
+ return written ? written : err;
+}
+
static void fuse_release_user_pages(struct fuse_req *req, int write)
{
unsigned i;
@@ -613,7 +934,7 @@
nbytes = min(nbytes, (unsigned) FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
npages = (nbytes + offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
- npages = min(max(npages, 1), FUSE_MAX_PAGES_PER_REQ);
+ npages = clamp(npages, 1, FUSE_MAX_PAGES_PER_REQ);
down_read(¤t->mm->mmap_sem);
npages = get_user_pages(current, current->mm, user_addr, npages, write,
0, req->pages, NULL);
@@ -645,14 +966,15 @@
while (count) {
size_t nres;
- size_t nbytes = min(count, nmax);
- int err = fuse_get_user_pages(req, buf, nbytes, !write);
+ size_t nbytes_limit = min(count, nmax);
+ size_t nbytes;
+ int err = fuse_get_user_pages(req, buf, nbytes_limit, !write);
if (err) {
res = err;
break;
}
nbytes = (req->num_pages << PAGE_SHIFT) - req->page_offset;
- nbytes = min(count, nbytes);
+ nbytes = min(nbytes_limit, nbytes);
if (write)
nres = fuse_send_write(req, file, inode, pos, nbytes,
current->files);
@@ -683,12 +1005,8 @@
}
fuse_put_request(fc, req);
if (res > 0) {
- if (write) {
- spin_lock(&fc->lock);
- if (pos > inode->i_size)
- i_size_write(inode, pos);
- spin_unlock(&fc->lock);
- }
+ if (write)
+ fuse_write_update_size(inode, pos);
*ppos = pos;
}
fuse_invalidate_attr(inode);
@@ -716,21 +1034,225 @@
return res;
}
-static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
+static void fuse_writepage_free(struct fuse_conn *fc, struct fuse_req *req)
{
- if ((vma->vm_flags & VM_SHARED)) {
- if ((vma->vm_flags & VM_WRITE))
- return -ENODEV;
- else
- vma->vm_flags &= ~VM_MAYWRITE;
- }
- return generic_file_mmap(file, vma);
+ __free_page(req->pages[0]);
+ fuse_file_put(req->ff);
+ fuse_put_request(fc, req);
}
-static int fuse_set_page_dirty(struct page *page)
+static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req)
{
- printk("fuse_set_page_dirty: should not happen\n");
- dump_stack();
+ struct inode *inode = req->inode;
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ struct backing_dev_info *bdi = inode->i_mapping->backing_dev_info;
+
+ list_del(&req->writepages_entry);
+ dec_bdi_stat(bdi, BDI_WRITEBACK);
+ dec_zone_page_state(req->pages[0], NR_WRITEBACK_TEMP);
+ bdi_writeout_inc(bdi);
+ wake_up(&fi->page_waitq);
+}
+
+/* Called under fc->lock, may release and reacquire it */
+static void fuse_send_writepage(struct fuse_conn *fc, struct fuse_req *req)
+{
+ struct fuse_inode *fi = get_fuse_inode(req->inode);
+ loff_t size = i_size_read(req->inode);
+ struct fuse_write_in *inarg = &req->misc.write.in;
+
+ if (!fc->connected)
+ goto out_free;
+
+ if (inarg->offset + PAGE_CACHE_SIZE <= size) {
+ inarg->size = PAGE_CACHE_SIZE;
+ } else if (inarg->offset < size) {
+ inarg->size = size & (PAGE_CACHE_SIZE - 1);
+ } else {
+ /* Got truncated off completely */
+ goto out_free;
+ }
+
+ req->in.args[1].size = inarg->size;
+ fi->writectr++;
+ request_send_background_locked(fc, req);
+ return;
+
+ out_free:
+ fuse_writepage_finish(fc, req);
+ spin_unlock(&fc->lock);
+ fuse_writepage_free(fc, req);
+ spin_lock(&fc->lock);
+}
+
+/*
+ * If fi->writectr is positive (no truncate or fsync going on) send
+ * all queued writepage requests.
+ *
+ * Called with fc->lock
+ */
+void fuse_flush_writepages(struct inode *inode)
+{
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ struct fuse_req *req;
+
+ while (fi->writectr >= 0 && !list_empty(&fi->queued_writes)) {
+ req = list_entry(fi->queued_writes.next, struct fuse_req, list);
+ list_del_init(&req->list);
+ fuse_send_writepage(fc, req);
+ }
+}
+
+static void fuse_writepage_end(struct fuse_conn *fc, struct fuse_req *req)
+{
+ struct inode *inode = req->inode;
+ struct fuse_inode *fi = get_fuse_inode(inode);
+
+ mapping_set_error(inode->i_mapping, req->out.h.error);
+ spin_lock(&fc->lock);
+ fi->writectr--;
+ fuse_writepage_finish(fc, req);
+ spin_unlock(&fc->lock);
+ fuse_writepage_free(fc, req);
+}
+
+static int fuse_writepage_locked(struct page *page)
+{
+ struct address_space *mapping = page->mapping;
+ struct inode *inode = mapping->host;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ struct fuse_req *req;
+ struct fuse_file *ff;
+ struct page *tmp_page;
+
+ set_page_writeback(page);
+
+ req = fuse_request_alloc_nofs();
+ if (!req)
+ goto err;
+
+ tmp_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM);
+ if (!tmp_page)
+ goto err_free;
+
+ spin_lock(&fc->lock);
+ BUG_ON(list_empty(&fi->write_files));
+ ff = list_entry(fi->write_files.next, struct fuse_file, write_entry);
+ req->ff = fuse_file_get(ff);
+ spin_unlock(&fc->lock);
+
+ fuse_write_fill(req, NULL, ff, inode, page_offset(page), 0, 1);
+
+ copy_highpage(tmp_page, page);
+ req->num_pages = 1;
+ req->pages[0] = tmp_page;
+ req->page_offset = 0;
+ req->end = fuse_writepage_end;
+ req->inode = inode;
+
+ inc_bdi_stat(mapping->backing_dev_info, BDI_WRITEBACK);
+ inc_zone_page_state(tmp_page, NR_WRITEBACK_TEMP);
+ end_page_writeback(page);
+
+ spin_lock(&fc->lock);
+ list_add(&req->writepages_entry, &fi->writepages);
+ list_add_tail(&req->list, &fi->queued_writes);
+ fuse_flush_writepages(inode);
+ spin_unlock(&fc->lock);
+
+ return 0;
+
+err_free:
+ fuse_request_free(req);
+err:
+ end_page_writeback(page);
+ return -ENOMEM;
+}
+
+static int fuse_writepage(struct page *page, struct writeback_control *wbc)
+{
+ int err;
+
+ err = fuse_writepage_locked(page);
+ unlock_page(page);
+
+ return err;
+}
+
+static int fuse_launder_page(struct page *page)
+{
+ int err = 0;
+ if (clear_page_dirty_for_io(page)) {
+ struct inode *inode = page->mapping->host;
+ err = fuse_writepage_locked(page);
+ if (!err)
+ fuse_wait_on_page_writeback(inode, page->index);
+ }
+ return err;
+}
+
+/*
+ * Write back dirty pages now, because there may not be any suitable
+ * open files later
+ */
+static void fuse_vma_close(struct vm_area_struct *vma)
+{
+ filemap_write_and_wait(vma->vm_file->f_mapping);
+}
+
+/*
+ * Wait for writeback against this page to complete before allowing it
+ * to be marked dirty again, and hence written back again, possibly
+ * before the previous writepage completed.
+ *
+ * Block here, instead of in ->writepage(), so that the userspace fs
+ * can only block processes actually operating on the filesystem.
+ *
+ * Otherwise unprivileged userspace fs would be able to block
+ * unrelated:
+ *
+ * - page migration
+ * - sync(2)
+ * - try_to_free_pages() with order > PAGE_ALLOC_COSTLY_ORDER
+ */
+static int fuse_page_mkwrite(struct vm_area_struct *vma, struct page *page)
+{
+ /*
+ * Don't use page->mapping as it may become NULL from a
+ * concurrent truncate.
+ */
+ struct inode *inode = vma->vm_file->f_mapping->host;
+
+ fuse_wait_on_page_writeback(inode, page->index);
+ return 0;
+}
+
+static struct vm_operations_struct fuse_file_vm_ops = {
+ .close = fuse_vma_close,
+ .fault = filemap_fault,
+ .page_mkwrite = fuse_page_mkwrite,
+};
+
+static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) {
+ struct inode *inode = file->f_dentry->d_inode;
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ struct fuse_file *ff = file->private_data;
+ /*
+ * file may be written through mmap, so chain it onto the
+ * inodes's write_file list
+ */
+ spin_lock(&fc->lock);
+ if (list_empty(&ff->write_entry))
+ list_add(&ff->write_entry, &fi->write_files);
+ spin_unlock(&fc->lock);
+ }
+ file_accessed(file);
+ vma->vm_ops = &fuse_file_vm_ops;
return 0;
}
@@ -909,12 +1431,37 @@
return err ? 0 : outarg.block;
}
+static loff_t fuse_file_llseek(struct file *file, loff_t offset, int origin)
+{
+ loff_t retval;
+ struct inode *inode = file->f_path.dentry->d_inode;
+
+ mutex_lock(&inode->i_mutex);
+ switch (origin) {
+ case SEEK_END:
+ offset += i_size_read(inode);
+ break;
+ case SEEK_CUR:
+ offset += file->f_pos;
+ }
+ retval = -EINVAL;
+ if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ file->f_version = 0;
+ }
+ retval = offset;
+ }
+ mutex_unlock(&inode->i_mutex);
+ return retval;
+}
+
static const struct file_operations fuse_file_operations = {
- .llseek = generic_file_llseek,
+ .llseek = fuse_file_llseek,
.read = do_sync_read,
.aio_read = fuse_file_aio_read,
.write = do_sync_write,
- .aio_write = generic_file_aio_write,
+ .aio_write = fuse_file_aio_write,
.mmap = fuse_file_mmap,
.open = fuse_open,
.flush = fuse_flush,
@@ -926,7 +1473,7 @@
};
static const struct file_operations fuse_direct_io_file_operations = {
- .llseek = generic_file_llseek,
+ .llseek = fuse_file_llseek,
.read = fuse_direct_read,
.write = fuse_direct_write,
.open = fuse_open,
@@ -940,10 +1487,12 @@
static const struct address_space_operations fuse_file_aops = {
.readpage = fuse_readpage,
+ .writepage = fuse_writepage,
+ .launder_page = fuse_launder_page,
.write_begin = fuse_write_begin,
.write_end = fuse_write_end,
.readpages = fuse_readpages,
- .set_page_dirty = fuse_set_page_dirty,
+ .set_page_dirty = __set_page_dirty_nobuffers,
.bmap = fuse_bmap,
};
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 67aaf6e..dadffa2 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -15,6 +15,7 @@
#include <linux/mm.h>
#include <linux/backing-dev.h>
#include <linux/mutex.h>
+#include <linux/rwsem.h>
/** Max number of pages that can be used in a single read request */
#define FUSE_MAX_PAGES_PER_REQ 32
@@ -25,6 +26,9 @@
/** Congestion starts at 75% of maximum */
#define FUSE_CONGESTION_THRESHOLD (FUSE_MAX_BACKGROUND * 75 / 100)
+/** Bias for fi->writectr, meaning new writepages must not be sent */
+#define FUSE_NOWRITE INT_MIN
+
/** It could be as large as PATH_MAX, but would that have any uses? */
#define FUSE_NAME_MAX 1024
@@ -73,6 +77,19 @@
/** Files usable in writepage. Protected by fc->lock */
struct list_head write_files;
+
+ /** Writepages pending on truncate or fsync */
+ struct list_head queued_writes;
+
+ /** Number of sent writes, a negative bias (FUSE_NOWRITE)
+ * means more writes are blocked */
+ int writectr;
+
+ /** Waitq for writepage completion */
+ wait_queue_head_t page_waitq;
+
+ /** List of writepage requestst (pending or sent) */
+ struct list_head writepages;
};
/** FUSE specific file data */
@@ -222,7 +239,10 @@
} release;
struct fuse_init_in init_in;
struct fuse_init_out init_out;
- struct fuse_read_in read_in;
+ struct {
+ struct fuse_read_in in;
+ u64 attr_ver;
+ } read;
struct {
struct fuse_write_in in;
struct fuse_write_out out;
@@ -242,6 +262,12 @@
/** File used in the request (or NULL) */
struct fuse_file *ff;
+ /** Inode used in the request or NULL */
+ struct inode *inode;
+
+ /** Link on fi->writepages */
+ struct list_head writepages_entry;
+
/** Request completion callback */
void (*end)(struct fuse_conn *, struct fuse_req *);
@@ -390,8 +416,8 @@
/** Entry on the fuse_conn_list */
struct list_head entry;
- /** Unique ID */
- u64 id;
+ /** Device ID from super block */
+ dev_t dev;
/** Dentries in the control filesystem */
struct dentry *ctl_dentry[FUSE_CTL_NUM_DENTRIES];
@@ -438,7 +464,7 @@
/**
* Get a filled in inode
*/
-struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
+struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
int generation, struct fuse_attr *attr,
u64 attr_valid, u64 attr_version);
@@ -446,7 +472,7 @@
* Send FORGET command
*/
void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
- unsigned long nodeid, u64 nlookup);
+ u64 nodeid, u64 nlookup);
/**
* Initialize READ or READDIR request
@@ -504,6 +530,11 @@
void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
u64 attr_valid, u64 attr_version);
+void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
+ u64 attr_valid);
+
+void fuse_truncate(struct address_space *mapping, loff_t offset);
+
/**
* Initialize the client device
*/
@@ -522,6 +553,8 @@
*/
struct fuse_req *fuse_request_alloc(void);
+struct fuse_req *fuse_request_alloc_nofs(void);
+
/**
* Free a request
*/
@@ -558,6 +591,8 @@
*/
void request_send_background(struct fuse_conn *fc, struct fuse_req *req);
+void request_send_background_locked(struct fuse_conn *fc, struct fuse_req *req);
+
/* Abort all requests */
void fuse_abort_conn(struct fuse_conn *fc);
@@ -600,3 +635,10 @@
int fuse_update_attributes(struct inode *inode, struct kstat *stat,
struct file *file, bool *refreshed);
+
+void fuse_flush_writepages(struct inode *inode);
+
+void fuse_set_nowrite(struct inode *inode);
+void fuse_release_nowrite(struct inode *inode);
+
+u64 fuse_get_attr_version(struct fuse_conn *fc);
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 4df34da..79b6158 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -59,7 +59,11 @@
fi->nodeid = 0;
fi->nlookup = 0;
fi->attr_version = 0;
+ fi->writectr = 0;
INIT_LIST_HEAD(&fi->write_files);
+ INIT_LIST_HEAD(&fi->queued_writes);
+ INIT_LIST_HEAD(&fi->writepages);
+ init_waitqueue_head(&fi->page_waitq);
fi->forget_req = fuse_request_alloc();
if (!fi->forget_req) {
kmem_cache_free(fuse_inode_cachep, inode);
@@ -73,13 +77,14 @@
{
struct fuse_inode *fi = get_fuse_inode(inode);
BUG_ON(!list_empty(&fi->write_files));
+ BUG_ON(!list_empty(&fi->queued_writes));
if (fi->forget_req)
fuse_request_free(fi->forget_req);
kmem_cache_free(fuse_inode_cachep, inode);
}
void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req,
- unsigned long nodeid, u64 nlookup)
+ u64 nodeid, u64 nlookup)
{
struct fuse_forget_in *inarg = &req->misc.forget_in;
inarg->nlookup = nlookup;
@@ -109,7 +114,7 @@
return 0;
}
-static void fuse_truncate(struct address_space *mapping, loff_t offset)
+void fuse_truncate(struct address_space *mapping, loff_t offset)
{
/* See vmtruncate() */
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
@@ -117,19 +122,12 @@
unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
}
-
-void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
- u64 attr_valid, u64 attr_version)
+void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr,
+ u64 attr_valid)
{
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_inode *fi = get_fuse_inode(inode);
- loff_t oldsize;
- spin_lock(&fc->lock);
- if (attr_version != 0 && fi->attr_version > attr_version) {
- spin_unlock(&fc->lock);
- return;
- }
fi->attr_version = ++fc->attr_version;
fi->i_time = attr_valid;
@@ -159,6 +157,22 @@
fi->orig_i_mode = inode->i_mode;
if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
inode->i_mode &= ~S_ISVTX;
+}
+
+void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr,
+ u64 attr_valid, u64 attr_version)
+{
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ struct fuse_inode *fi = get_fuse_inode(inode);
+ loff_t oldsize;
+
+ spin_lock(&fc->lock);
+ if (attr_version != 0 && fi->attr_version > attr_version) {
+ spin_unlock(&fc->lock);
+ return;
+ }
+
+ fuse_change_attributes_common(inode, attr, attr_valid);
oldsize = inode->i_size;
i_size_write(inode, attr->size);
@@ -193,7 +207,7 @@
static int fuse_inode_eq(struct inode *inode, void *_nodeidp)
{
- unsigned long nodeid = *(unsigned long *) _nodeidp;
+ u64 nodeid = *(u64 *) _nodeidp;
if (get_node_id(inode) == nodeid)
return 1;
else
@@ -202,12 +216,12 @@
static int fuse_inode_set(struct inode *inode, void *_nodeidp)
{
- unsigned long nodeid = *(unsigned long *) _nodeidp;
+ u64 nodeid = *(u64 *) _nodeidp;
get_fuse_inode(inode)->nodeid = nodeid;
return 0;
}
-struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
+struct inode *fuse_iget(struct super_block *sb, u64 nodeid,
int generation, struct fuse_attr *attr,
u64 attr_valid, u64 attr_version)
{
@@ -447,7 +461,7 @@
return 0;
}
-static struct fuse_conn *new_conn(void)
+static struct fuse_conn *new_conn(struct super_block *sb)
{
struct fuse_conn *fc;
int err;
@@ -468,19 +482,41 @@
atomic_set(&fc->num_waiting, 0);
fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE;
fc->bdi.unplug_io_fn = default_unplug_io_fn;
+ /* fuse does it's own writeback accounting */
+ fc->bdi.capabilities = BDI_CAP_NO_ACCT_WB;
+ fc->dev = sb->s_dev;
err = bdi_init(&fc->bdi);
- if (err) {
- kfree(fc);
- fc = NULL;
- goto out;
- }
+ if (err)
+ goto error_kfree;
+ err = bdi_register_dev(&fc->bdi, fc->dev);
+ if (err)
+ goto error_bdi_destroy;
+ /*
+ * For a single fuse filesystem use max 1% of dirty +
+ * writeback threshold.
+ *
+ * This gives about 1M of write buffer for memory maps on a
+ * machine with 1G and 10% dirty_ratio, which should be more
+ * than enough.
+ *
+ * Privileged users can raise it by writing to
+ *
+ * /sys/class/bdi/<bdi>/max_ratio
+ */
+ bdi_set_max_ratio(&fc->bdi, 1);
fc->reqctr = 0;
fc->blocked = 1;
fc->attr_version = 1;
get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key));
}
-out:
return fc;
+
+error_bdi_destroy:
+ bdi_destroy(&fc->bdi);
+error_kfree:
+ mutex_destroy(&fc->inst_mutex);
+ kfree(fc);
+ return NULL;
}
void fuse_conn_put(struct fuse_conn *fc)
@@ -548,6 +584,7 @@
fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages);
fc->minor = arg->minor;
fc->max_write = arg->minor < 5 ? 4096 : arg->max_write;
+ fc->max_write = min_t(unsigned, 4096, fc->max_write);
fc->conn_init = 1;
}
fuse_put_request(fc, req);
@@ -578,12 +615,6 @@
request_send_background(fc, req);
}
-static u64 conn_id(void)
-{
- static u64 ctr = 1;
- return ctr++;
-}
-
static int fuse_fill_super(struct super_block *sb, void *data, int silent)
{
struct fuse_conn *fc;
@@ -621,14 +652,14 @@
if (file->f_op != &fuse_dev_operations)
return -EINVAL;
- fc = new_conn();
+ fc = new_conn(sb);
if (!fc)
return -ENOMEM;
fc->flags = d.flags;
fc->user_id = d.user_id;
fc->group_id = d.group_id;
- fc->max_read = d.max_read;
+ fc->max_read = min_t(unsigned, 4096, d.max_read);
/* Used by get_root_inode() */
sb->s_fs_info = fc;
@@ -659,7 +690,6 @@
if (file->private_data)
goto err_unlock;
- fc->id = conn_id();
err = fuse_ctl_add_conn(fc);
if (err)
goto err_unlock;
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
index 8479da4..a4ff271 100644
--- a/fs/gfs2/locking/dlm/sysfs.c
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -212,7 +212,7 @@
{
gdlm_kset = kset_create_and_add("lock_dlm", NULL, kernel_kobj);
if (!gdlm_kset) {
- printk(KERN_WARNING "%s: can not create kset\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: can not create kset\n", __func__);
return -ENOMEM;
}
return 0;
diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
index 509c5d6..7f48576 100644
--- a/fs/gfs2/util.h
+++ b/fs/gfs2/util.h
@@ -41,7 +41,7 @@
#define gfs2_assert_withdraw(sdp, assertion) \
((likely(assertion)) ? 0 : gfs2_assert_withdraw_i((sdp), #assertion, \
- __FUNCTION__, __FILE__, __LINE__))
+ __func__, __FILE__, __LINE__))
int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
@@ -49,28 +49,28 @@
#define gfs2_assert_warn(sdp, assertion) \
((likely(assertion)) ? 0 : gfs2_assert_warn_i((sdp), #assertion, \
- __FUNCTION__, __FILE__, __LINE__))
+ __func__, __FILE__, __LINE__))
int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide,
const char *function, char *file, unsigned int line);
#define gfs2_consist(sdp) \
-gfs2_consist_i((sdp), 0, __FUNCTION__, __FILE__, __LINE__)
+gfs2_consist_i((sdp), 0, __func__, __FILE__, __LINE__)
int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide,
const char *function, char *file, unsigned int line);
#define gfs2_consist_inode(ip) \
-gfs2_consist_inode_i((ip), 0, __FUNCTION__, __FILE__, __LINE__)
+gfs2_consist_inode_i((ip), 0, __func__, __FILE__, __LINE__)
int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide,
const char *function, char *file, unsigned int line);
#define gfs2_consist_rgrpd(rgd) \
-gfs2_consist_rgrpd_i((rgd), 0, __FUNCTION__, __FILE__, __LINE__)
+gfs2_consist_rgrpd_i((rgd), 0, __func__, __FILE__, __LINE__)
int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
@@ -91,7 +91,7 @@
}
#define gfs2_meta_check(sdp, bh) \
-gfs2_meta_check_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__)
+gfs2_meta_check_i((sdp), (bh), __func__, __FILE__, __LINE__)
int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
@@ -118,7 +118,7 @@
}
#define gfs2_metatype_check(sdp, bh, type) \
-gfs2_metatype_check_i((sdp), (bh), (type), __FUNCTION__, __FILE__, __LINE__)
+gfs2_metatype_check_i((sdp), (bh), (type), __func__, __FILE__, __LINE__)
static inline void gfs2_metatype_set(struct buffer_head *bh, u16 type,
u16 format)
@@ -134,14 +134,14 @@
char *file, unsigned int line);
#define gfs2_io_error(sdp) \
-gfs2_io_error_i((sdp), __FUNCTION__, __FILE__, __LINE__);
+gfs2_io_error_i((sdp), __func__, __FILE__, __LINE__);
int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
const char *function, char *file, unsigned int line);
#define gfs2_io_error_bh(sdp, bh) \
-gfs2_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__);
+gfs2_io_error_bh_i((sdp), (bh), __func__, __FILE__, __LINE__);
extern struct kmem_cache *gfs2_glock_cachep;
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 24cf6fc..f6621a7 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -208,7 +208,9 @@
struct hfs_bnode *node, *next_node;
struct page **pagep;
u32 nidx, idx;
- u16 off, len;
+ unsigned off;
+ u16 off16;
+ u16 len;
u8 *data, byte, m;
int i;
@@ -235,7 +237,8 @@
node = hfs_bnode_find(tree, nidx);
if (IS_ERR(node))
return node;
- len = hfs_brec_lenoff(node, 2, &off);
+ len = hfs_brec_lenoff(node, 2, &off16);
+ off = off16;
off += node->page_offset;
pagep = node->page + (off >> PAGE_CACHE_SHIFT);
@@ -280,7 +283,8 @@
return next_node;
node = next_node;
- len = hfs_brec_lenoff(node, 0, &off);
+ len = hfs_brec_lenoff(node, 0, &off16);
+ off = off16;
off += node->page_offset;
pagep = node->page + (off >> PAGE_CACHE_SHIFT);
data = kmap(*pagep);
diff --git a/fs/hfs/mdb.c b/fs/hfs/mdb.c
index b4651e1..36ca2e1 100644
--- a/fs/hfs/mdb.c
+++ b/fs/hfs/mdb.c
@@ -215,7 +215,7 @@
attrib &= cpu_to_be16(~HFS_SB_ATTRIB_UNMNT);
attrib |= cpu_to_be16(HFS_SB_ATTRIB_INCNSTNT);
mdb->drAtrb = attrib;
- mdb->drWrCnt = cpu_to_be32(be32_to_cpu(mdb->drWrCnt) + 1);
+ be32_add_cpu(&mdb->drWrCnt, 1);
mdb->drLsMod = hfs_mtime();
mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 32de44e..8cf6797 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -297,7 +297,8 @@
return 0;
}
p = match_strdup(&args[0]);
- hsb->nls_disk = load_nls(p);
+ if (p)
+ hsb->nls_disk = load_nls(p);
if (!hsb->nls_disk) {
printk(KERN_ERR "hfs: unable to load codepage \"%s\"\n", p);
kfree(p);
@@ -311,7 +312,8 @@
return 0;
}
p = match_strdup(&args[0]);
- hsb->nls_io = load_nls(p);
+ if (p)
+ hsb->nls_io = load_nls(p);
if (!hsb->nls_io) {
printk(KERN_ERR "hfs: unable to load iocharset \"%s\"\n", p);
kfree(p);
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index bb54336..e49fcee 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -184,7 +184,9 @@
struct hfs_bnode *node, *next_node;
struct page **pagep;
u32 nidx, idx;
- u16 off, len;
+ unsigned off;
+ u16 off16;
+ u16 len;
u8 *data, byte, m;
int i;
@@ -211,7 +213,8 @@
node = hfs_bnode_find(tree, nidx);
if (IS_ERR(node))
return node;
- len = hfs_brec_lenoff(node, 2, &off);
+ len = hfs_brec_lenoff(node, 2, &off16);
+ off = off16;
off += node->page_offset;
pagep = node->page + (off >> PAGE_CACHE_SHIFT);
@@ -256,7 +259,8 @@
return next_node;
node = next_node;
- len = hfs_brec_lenoff(node, 0, &off);
+ len = hfs_brec_lenoff(node, 0, &off16);
+ off = off16;
off += node->page_offset;
pagep = node->page + (off >> PAGE_CACHE_SHIFT);
data = kmap(*pagep);
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index d72d0a8..9e59537 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -311,6 +311,10 @@
int hfsplus_rename_cat(u32, struct inode *, struct qstr *,
struct inode *, struct qstr *);
+/* dir.c */
+extern const struct inode_operations hfsplus_dir_inode_operations;
+extern const struct file_operations hfsplus_dir_operations;
+
/* extents.c */
int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
void hfsplus_ext_write_extent(struct inode *);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 37744cf..d53b2af 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -278,9 +278,6 @@
return 0;
}
-extern const struct inode_operations hfsplus_dir_inode_operations;
-extern struct file_operations hfsplus_dir_operations;
-
static const struct inode_operations hfsplus_file_inode_operations = {
.lookup = hfsplus_file_lookup,
.truncate = hfsplus_file_truncate,
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index dc64fac..9997cbf 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -132,7 +132,8 @@
return 0;
}
p = match_strdup(&args[0]);
- sbi->nls = load_nls(p);
+ if (p)
+ sbi->nls = load_nls(p);
if (!sbi->nls) {
printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p);
kfree(p);
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index b0f9ad3..ce97a54 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -357,7 +357,7 @@
printk(KERN_WARNING "hfs: Filesystem is marked locked, mounting read-only.\n");
sb->s_flags |= MS_RDONLY;
} else if (vhdr->attributes & cpu_to_be32(HFSPLUS_VOL_JOURNALED)) {
- printk(KERN_WARNING "hfs: write access to a jounaled filesystem is not supported, "
+ printk(KERN_WARNING "hfs: write access to a journaled filesystem is not supported, "
"use the force option at your own risk, mounting read-only.\n");
sb->s_flags |= MS_RDONLY;
}
@@ -423,7 +423,7 @@
*/
vhdr->last_mount_vers = cpu_to_be32(HFSP_MOUNT_VERSION);
vhdr->modify_date = hfsp_now2mt();
- vhdr->write_count = cpu_to_be32(be32_to_cpu(vhdr->write_count) + 1);
+ be32_add_cpu(&vhdr->write_count, 1);
vhdr->attributes &= cpu_to_be32(~HFSPLUS_VOL_UNMNT);
vhdr->attributes |= cpu_to_be32(HFSPLUS_VOL_INCNSTNT);
mark_buffer_dirty(HFSPLUS_SB(sb).s_vhbh);
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c
index 72cab78..175d08e 100644
--- a/fs/hfsplus/wrapper.c
+++ b/fs/hfsplus/wrapper.c
@@ -47,7 +47,7 @@
return 0;
wd->ablk_start = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
- extent = be32_to_cpu(get_unaligned((__be32 *)(bufptr + HFSP_WRAPOFF_EMBEDEXT)));
+ extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT);
wd->embed_start = (extent >> 16) & 0xFFFF;
wd->embed_count = extent & 0xFFFF;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 9783723..aeabf80 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -45,7 +45,7 @@
static struct backing_dev_info hugetlbfs_backing_dev_info = {
.ra_pages = 0, /* No readahead */
- .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
int sysctl_hugetlb_shm_group;
diff --git a/fs/inode.c b/fs/inode.c
index 27ee1af..bf64781 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -495,8 +495,7 @@
struct inode * inode = NULL;
repeat:
- hlist_for_each (node, head) {
- inode = hlist_entry(node, struct inode, i_hash);
+ hlist_for_each_entry(inode, node, head, i_hash) {
if (inode->i_sb != sb)
continue;
if (!test(inode, data))
@@ -520,8 +519,7 @@
struct inode * inode = NULL;
repeat:
- hlist_for_each (node, head) {
- inode = hlist_entry(node, struct inode, i_hash);
+ hlist_for_each_entry(inode, node, head, i_hash) {
if (inode->i_ino != ino)
continue;
if (inode->i_sb != sb)
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index 7b94a1e..6676c06 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -598,7 +598,7 @@
}
ih = inotify_init(&inotify_user_ops);
- if (unlikely(IS_ERR(ih))) {
+ if (IS_ERR(ih)) {
ret = PTR_ERR(ih);
goto out_free_dev;
}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index f32fbde..7db32b3 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -28,8 +28,8 @@
*
* Returns 0 on success, -errno on error.
*/
-long vfs_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
+static long vfs_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
{
int error = -ENOTTY;
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 1ba407c..2f0dc5a 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -145,6 +145,14 @@
}
de = tmpde;
}
+ /* Basic sanity check, whether name doesn't exceed dir entry */
+ if (de_len < de->name_len[0] +
+ sizeof(struct iso_directory_record)) {
+ printk(KERN_NOTICE "iso9660: Corrupted directory entry"
+ " in block %lu of inode %lu\n", block,
+ inode->i_ino);
+ return -EIO;
+ }
if (first_de) {
isofs_normalize_block_and_offset(de,
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
index d1bdf8ad..ccbf72f 100644
--- a/fs/isofs/isofs.h
+++ b/fs/isofs/isofs.h
@@ -78,29 +78,29 @@
}
static inline unsigned int isonum_721(char *p)
{
- return le16_to_cpu(get_unaligned((__le16 *)p));
+ return get_unaligned_le16(p);
}
static inline unsigned int isonum_722(char *p)
{
- return be16_to_cpu(get_unaligned((__le16 *)p));
+ return get_unaligned_be16(p);
}
static inline unsigned int isonum_723(char *p)
{
/* Ignore bigendian datum due to broken mastering programs */
- return le16_to_cpu(get_unaligned((__le16 *)p));
+ return get_unaligned_le16(p);
}
static inline unsigned int isonum_731(char *p)
{
- return le32_to_cpu(get_unaligned((__le32 *)p));
+ return get_unaligned_le32(p);
}
static inline unsigned int isonum_732(char *p)
{
- return be32_to_cpu(get_unaligned((__le32 *)p));
+ return get_unaligned_be32(p);
}
static inline unsigned int isonum_733(char *p)
{
/* Ignore bigendian datum due to broken mastering programs */
- return le32_to_cpu(get_unaligned((__le32 *)p));
+ return get_unaligned_le32(p);
}
extern int iso_date(char *, int);
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index 344b247..8299889 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -111,6 +111,13 @@
dlen = de->name_len[0];
dpnt = de->name;
+ /* Basic sanity check, whether name doesn't exceed dir entry */
+ if (de_len < dlen + sizeof(struct iso_directory_record)) {
+ printk(KERN_NOTICE "iso9660: Corrupted directory entry"
+ " in block %lu of inode %lu\n", block,
+ dir->i_ino);
+ return 0;
+ }
if (sbi->s_rock &&
((i = get_rock_ridge_filename(de, tmpname, dir)))) {
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index a817308..e013978 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -520,22 +520,6 @@
jbd_debug (3, "JBD: commit phase 2\n");
/*
- * First, drop modified flag: all accesses to the buffers
- * will be tracked for a new trasaction only -bzzz
- */
- spin_lock(&journal->j_list_lock);
- if (commit_transaction->t_buffers) {
- new_jh = jh = commit_transaction->t_buffers->b_tnext;
- do {
- J_ASSERT_JH(new_jh, new_jh->b_modified == 1 ||
- new_jh->b_modified == 0);
- new_jh->b_modified = 0;
- new_jh = new_jh->b_tnext;
- } while (new_jh != jh);
- }
- spin_unlock(&journal->j_list_lock);
-
- /*
* Now start flushing things to disk, in the order they appear
* on the transaction lists. Data blocks go first.
*/
@@ -584,6 +568,9 @@
stats.u.run.rs_blocks = commit_transaction->t_outstanding_credits;
stats.u.run.rs_blocks_logged = 0;
+ J_ASSERT(commit_transaction->t_nr_buffers <=
+ commit_transaction->t_outstanding_credits);
+
descriptor = NULL;
bufs = 0;
while (commit_transaction->t_buffers) {
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 954cff0..53632e3 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -534,7 +534,7 @@
if (!tid_geq(journal->j_commit_request, tid)) {
printk(KERN_EMERG
"%s: error: j_commit_request=%d, tid=%d\n",
- __FUNCTION__, journal->j_commit_request, tid);
+ __func__, journal->j_commit_request, tid);
}
spin_unlock(&journal->j_state_lock);
#endif
@@ -599,7 +599,7 @@
printk(KERN_ALERT "%s: journal block not found "
"at offset %lu on %s\n",
- __FUNCTION__,
+ __func__,
blocknr,
bdevname(journal->j_dev, b));
err = -EIO;
@@ -904,19 +904,10 @@
snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
journal->j_proc_entry = proc_mkdir(name, proc_jbd2_stats);
if (journal->j_proc_entry) {
- struct proc_dir_entry *p;
- p = create_proc_entry("history", S_IRUGO,
- journal->j_proc_entry);
- if (p) {
- p->proc_fops = &jbd2_seq_history_fops;
- p->data = journal;
- p = create_proc_entry("info", S_IRUGO,
- journal->j_proc_entry);
- if (p) {
- p->proc_fops = &jbd2_seq_info_fops;
- p->data = journal;
- }
- }
+ proc_create_data("history", S_IRUGO, journal->j_proc_entry,
+ &jbd2_seq_history_fops, journal);
+ proc_create_data("info", S_IRUGO, journal->j_proc_entry,
+ &jbd2_seq_info_fops, journal);
}
}
@@ -1006,13 +997,14 @@
*/
/**
- * journal_t * jbd2_journal_init_dev() - creates an initialises a journal structure
+ * journal_t * jbd2_journal_init_dev() - creates and initialises a journal structure
* @bdev: Block device on which to create the journal
* @fs_dev: Device which hold journalled filesystem for this journal.
* @start: Block nr Start of journal.
* @len: Length of the journal in blocks.
* @blocksize: blocksize of journalling device
- * @returns: a newly created journal_t *
+ *
+ * Returns: a newly created journal_t *
*
* jbd2_journal_init_dev creates a journal which maps a fixed contiguous
* range of blocks on an arbitrary block device.
@@ -1036,7 +1028,7 @@
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
if (!journal->j_wbuf) {
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
- __FUNCTION__);
+ __func__);
kfree(journal);
journal = NULL;
goto out;
@@ -1092,7 +1084,7 @@
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
if (!journal->j_wbuf) {
printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
- __FUNCTION__);
+ __func__);
kfree(journal);
return NULL;
}
@@ -1101,7 +1093,7 @@
/* If that failed, give up */
if (err) {
printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
- __FUNCTION__);
+ __func__);
kfree(journal);
return NULL;
}
@@ -1187,7 +1179,7 @@
*/
printk(KERN_EMERG
"%s: creation of journal on external device!\n",
- __FUNCTION__);
+ __func__);
BUG();
}
@@ -1985,9 +1977,10 @@
static void jbd2_journal_destroy_jbd2_journal_head_cache(void)
{
- J_ASSERT(jbd2_journal_head_cache != NULL);
- kmem_cache_destroy(jbd2_journal_head_cache);
- jbd2_journal_head_cache = NULL;
+ if (jbd2_journal_head_cache) {
+ kmem_cache_destroy(jbd2_journal_head_cache);
+ jbd2_journal_head_cache = NULL;
+ }
}
/*
@@ -2006,7 +1999,7 @@
jbd_debug(1, "out of memory for journal_head\n");
if (time_after(jiffies, last_warning + 5*HZ)) {
printk(KERN_NOTICE "ENOMEM in %s, retrying.\n",
- __FUNCTION__);
+ __func__);
last_warning = jiffies;
}
while (!ret) {
@@ -2143,13 +2136,13 @@
if (jh->b_frozen_data) {
printk(KERN_WARNING "%s: freeing "
"b_frozen_data\n",
- __FUNCTION__);
+ __func__);
jbd2_free(jh->b_frozen_data, bh->b_size);
}
if (jh->b_committed_data) {
printk(KERN_WARNING "%s: freeing "
"b_committed_data\n",
- __FUNCTION__);
+ __func__);
jbd2_free(jh->b_committed_data, bh->b_size);
}
bh->b_private = NULL;
@@ -2314,10 +2307,12 @@
BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024);
ret = journal_init_caches();
- if (ret != 0)
+ if (ret == 0) {
+ jbd2_create_debugfs_entry();
+ jbd2_create_jbd_stats_proc_entry();
+ } else {
jbd2_journal_destroy_caches();
- jbd2_create_debugfs_entry();
- jbd2_create_jbd_stats_proc_entry();
+ }
return ret;
}
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
index 2e1453a..257ff26 100644
--- a/fs/jbd2/revoke.c
+++ b/fs/jbd2/revoke.c
@@ -139,7 +139,7 @@
oom:
if (!journal_oom_retry)
return -ENOMEM;
- jbd_debug(1, "ENOMEM in %s, retrying\n", __FUNCTION__);
+ jbd_debug(1, "ENOMEM in %s, retrying\n", __func__);
yield();
goto repeat;
}
@@ -167,138 +167,121 @@
return NULL;
}
+void jbd2_journal_destroy_revoke_caches(void)
+{
+ if (jbd2_revoke_record_cache) {
+ kmem_cache_destroy(jbd2_revoke_record_cache);
+ jbd2_revoke_record_cache = NULL;
+ }
+ if (jbd2_revoke_table_cache) {
+ kmem_cache_destroy(jbd2_revoke_table_cache);
+ jbd2_revoke_table_cache = NULL;
+ }
+}
+
int __init jbd2_journal_init_revoke_caches(void)
{
+ J_ASSERT(!jbd2_revoke_record_cache);
+ J_ASSERT(!jbd2_revoke_table_cache);
+
jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record",
sizeof(struct jbd2_revoke_record_s),
0,
SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY,
NULL);
if (!jbd2_revoke_record_cache)
- return -ENOMEM;
+ goto record_cache_failure;
jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table",
sizeof(struct jbd2_revoke_table_s),
0, SLAB_TEMPORARY, NULL);
- if (!jbd2_revoke_table_cache) {
- kmem_cache_destroy(jbd2_revoke_record_cache);
- jbd2_revoke_record_cache = NULL;
- return -ENOMEM;
- }
+ if (!jbd2_revoke_table_cache)
+ goto table_cache_failure;
return 0;
+table_cache_failure:
+ jbd2_journal_destroy_revoke_caches();
+record_cache_failure:
+ return -ENOMEM;
}
-void jbd2_journal_destroy_revoke_caches(void)
+static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size)
{
- kmem_cache_destroy(jbd2_revoke_record_cache);
- jbd2_revoke_record_cache = NULL;
- kmem_cache_destroy(jbd2_revoke_table_cache);
- jbd2_revoke_table_cache = NULL;
-}
+ int shift = 0;
+ int tmp = hash_size;
+ struct jbd2_revoke_table_s *table;
-/* Initialise the revoke table for a given journal to a given size. */
+ table = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
+ if (!table)
+ goto out;
-int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
-{
- int shift, tmp;
-
- J_ASSERT (journal->j_revoke_table[0] == NULL);
-
- shift = 0;
- tmp = hash_size;
while((tmp >>= 1UL) != 0UL)
shift++;
- journal->j_revoke_table[0] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
- if (!journal->j_revoke_table[0])
- return -ENOMEM;
- journal->j_revoke = journal->j_revoke_table[0];
-
- /* Check that the hash_size is a power of two */
- J_ASSERT(is_power_of_2(hash_size));
-
- journal->j_revoke->hash_size = hash_size;
-
- journal->j_revoke->hash_shift = shift;
-
- journal->j_revoke->hash_table =
+ table->hash_size = hash_size;
+ table->hash_shift = shift;
+ table->hash_table =
kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
- if (!journal->j_revoke->hash_table) {
- kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
- journal->j_revoke = NULL;
- return -ENOMEM;
+ if (!table->hash_table) {
+ kmem_cache_free(jbd2_revoke_table_cache, table);
+ table = NULL;
+ goto out;
}
for (tmp = 0; tmp < hash_size; tmp++)
- INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
+ INIT_LIST_HEAD(&table->hash_table[tmp]);
- journal->j_revoke_table[1] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
- if (!journal->j_revoke_table[1]) {
- kfree(journal->j_revoke_table[0]->hash_table);
- kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
- return -ENOMEM;
+out:
+ return table;
+}
+
+static void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table)
+{
+ int i;
+ struct list_head *hash_list;
+
+ for (i = 0; i < table->hash_size; i++) {
+ hash_list = &table->hash_table[i];
+ J_ASSERT(list_empty(hash_list));
}
+ kfree(table->hash_table);
+ kmem_cache_free(jbd2_revoke_table_cache, table);
+}
+
+/* Initialise the revoke table for a given journal to a given size. */
+int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
+{
+ J_ASSERT(journal->j_revoke_table[0] == NULL);
+ J_ASSERT(is_power_of_2(hash_size));
+
+ journal->j_revoke_table[0] = jbd2_journal_init_revoke_table(hash_size);
+ if (!journal->j_revoke_table[0])
+ goto fail0;
+
+ journal->j_revoke_table[1] = jbd2_journal_init_revoke_table(hash_size);
+ if (!journal->j_revoke_table[1])
+ goto fail1;
+
journal->j_revoke = journal->j_revoke_table[1];
- /* Check that the hash_size is a power of two */
- J_ASSERT(is_power_of_2(hash_size));
-
- journal->j_revoke->hash_size = hash_size;
-
- journal->j_revoke->hash_shift = shift;
-
- journal->j_revoke->hash_table =
- kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
- if (!journal->j_revoke->hash_table) {
- kfree(journal->j_revoke_table[0]->hash_table);
- kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
- kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[1]);
- journal->j_revoke = NULL;
- return -ENOMEM;
- }
-
- for (tmp = 0; tmp < hash_size; tmp++)
- INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
-
spin_lock_init(&journal->j_revoke_lock);
return 0;
+
+fail1:
+ jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
+fail0:
+ return -ENOMEM;
}
-/* Destoy a journal's revoke table. The table must already be empty! */
-
+/* Destroy a journal's revoke table. The table must already be empty! */
void jbd2_journal_destroy_revoke(journal_t *journal)
{
- struct jbd2_revoke_table_s *table;
- struct list_head *hash_list;
- int i;
-
- table = journal->j_revoke_table[0];
- if (!table)
- return;
-
- for (i=0; i<table->hash_size; i++) {
- hash_list = &table->hash_table[i];
- J_ASSERT (list_empty(hash_list));
- }
-
- kfree(table->hash_table);
- kmem_cache_free(jbd2_revoke_table_cache, table);
journal->j_revoke = NULL;
-
- table = journal->j_revoke_table[1];
- if (!table)
- return;
-
- for (i=0; i<table->hash_size; i++) {
- hash_list = &table->hash_table[i];
- J_ASSERT (list_empty(hash_list));
- }
-
- kfree(table->hash_table);
- kmem_cache_free(jbd2_revoke_table_cache, table);
- journal->j_revoke = NULL;
+ if (journal->j_revoke_table[0])
+ jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]);
+ if (journal->j_revoke_table[1])
+ jbd2_journal_destroy_revoke_table(journal->j_revoke_table[1]);
}
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
index b9b0b6f..d6e006e 100644
--- a/fs/jbd2/transaction.c
+++ b/fs/jbd2/transaction.c
@@ -618,6 +618,12 @@
goto done;
/*
+ * this is the first time this transaction is touching this buffer,
+ * reset the modified flag
+ */
+ jh->b_modified = 0;
+
+ /*
* If there is already a copy-out version of this buffer, then we don't
* need to make another one
*/
@@ -690,7 +696,7 @@
if (!frozen_buffer) {
printk(KERN_EMERG
"%s: OOM for frozen_buffer\n",
- __FUNCTION__);
+ __func__);
JBUFFER_TRACE(jh, "oom!");
error = -ENOMEM;
jbd_lock_bh_state(bh);
@@ -829,9 +835,16 @@
if (jh->b_transaction == NULL) {
jh->b_transaction = transaction;
+
+ /* first access by this transaction */
+ jh->b_modified = 0;
+
JBUFFER_TRACE(jh, "file as BJ_Reserved");
__jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
} else if (jh->b_transaction == journal->j_committing_transaction) {
+ /* first access by this transaction */
+ jh->b_modified = 0;
+
JBUFFER_TRACE(jh, "set next transaction");
jh->b_next_transaction = transaction;
}
@@ -901,7 +914,7 @@
committed_data = jbd2_alloc(jh2bh(jh)->b_size, GFP_NOFS);
if (!committed_data) {
printk(KERN_EMERG "%s: No memory for committed data\n",
- __FUNCTION__);
+ __func__);
err = -ENOMEM;
goto out;
}
@@ -1230,6 +1243,7 @@
struct journal_head *jh;
int drop_reserve = 0;
int err = 0;
+ int was_modified = 0;
BUFFER_TRACE(bh, "entry");
@@ -1248,6 +1262,9 @@
goto not_jbd;
}
+ /* keep track of wether or not this transaction modified us */
+ was_modified = jh->b_modified;
+
/*
* The buffer's going from the transaction, we must drop
* all references -bzzz
@@ -1265,7 +1282,12 @@
JBUFFER_TRACE(jh, "belongs to current transaction: unfile");
- drop_reserve = 1;
+ /*
+ * we only want to drop a reference if this transaction
+ * modified the buffer
+ */
+ if (was_modified)
+ drop_reserve = 1;
/*
* We are no longer going to journal this buffer.
@@ -1305,7 +1327,13 @@
if (jh->b_next_transaction) {
J_ASSERT(jh->b_next_transaction == transaction);
jh->b_next_transaction = NULL;
- drop_reserve = 1;
+
+ /*
+ * only drop a reference if this transaction modified
+ * the buffer
+ */
+ if (was_modified)
+ drop_reserve = 1;
}
}
@@ -1434,7 +1462,8 @@
return err;
}
-/**int jbd2_journal_force_commit() - force any uncommitted transactions
+/**
+ * int jbd2_journal_force_commit() - force any uncommitted transactions
* @journal: journal to force
*
* For synchronous operations: force any uncommitted transactions
@@ -2077,7 +2106,7 @@
jh->b_transaction = jh->b_next_transaction;
jh->b_next_transaction = NULL;
__jbd2_journal_file_buffer(jh, jh->b_transaction,
- was_dirty ? BJ_Metadata : BJ_Reserved);
+ jh->b_modified ? BJ_Metadata : BJ_Reserved);
J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
if (was_dirty)
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index d58f845..c5e1450 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -46,7 +46,7 @@
static void jffs2_build_inode_pass1(struct jffs2_sb_info *c,
- struct jffs2_inode_cache *ic)
+ struct jffs2_inode_cache *ic)
{
struct jffs2_full_dirent *fd;
@@ -68,11 +68,17 @@
continue;
}
- if (child_ic->nlink++ && fd->type == DT_DIR) {
- JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
- fd->name, fd->ino, ic->ino);
- /* TODO: What do we do about it? */
- }
+ if (fd->type == DT_DIR) {
+ if (child_ic->pino_nlink) {
+ JFFS2_ERROR("child dir \"%s\" (ino #%u) of dir ino #%u appears to be a hard link\n",
+ fd->name, fd->ino, ic->ino);
+ /* TODO: What do we do about it? */
+ } else {
+ child_ic->pino_nlink = ic->ino;
+ }
+ } else
+ child_ic->pino_nlink++;
+
dbg_fsbuild("increased nlink for child \"%s\" (ino #%u)\n", fd->name, fd->ino);
/* Can't free scan_dents so far. We might need them in pass 2 */
}
@@ -125,7 +131,7 @@
dbg_fsbuild("pass 2 starting\n");
for_each_inode(i, c, ic) {
- if (ic->nlink)
+ if (ic->pino_nlink)
continue;
jffs2_build_remove_unlinked_inode(c, ic, &dead_fds);
@@ -232,16 +238,19 @@
/* Reduce nlink of the child. If it's now zero, stick it on the
dead_fds list to be cleaned up later. Else just free the fd */
- child_ic->nlink--;
+ if (fd->type == DT_DIR)
+ child_ic->pino_nlink = 0;
+ else
+ child_ic->pino_nlink--;
- if (!child_ic->nlink) {
- dbg_fsbuild("inode #%u (\"%s\") has now got zero nlink, adding to dead_fds list.\n",
+ if (!child_ic->pino_nlink) {
+ dbg_fsbuild("inode #%u (\"%s\") now has no links; adding to dead_fds list.\n",
fd->ino, fd->name);
fd->next = *dead_fds;
*dead_fds = fd;
} else {
dbg_fsbuild("inode #%u (\"%s\") has now got nlink %d. Ignoring.\n",
- fd->ino, fd->name, child_ic->nlink);
+ fd->ino, fd->name, child_ic->pino_nlink);
jffs2_free_full_dirent(fd);
}
}
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h
index 9645275..a113ecc 100644
--- a/fs/jffs2/debug.h
+++ b/fs/jffs2/debug.h
@@ -82,28 +82,28 @@
do { \
printk(JFFS2_ERR_MSG_PREFIX \
" (%d) %s: " fmt, task_pid_nr(current), \
- __FUNCTION__ , ##__VA_ARGS__); \
+ __func__ , ##__VA_ARGS__); \
} while(0)
#define JFFS2_WARNING(fmt, ...) \
do { \
printk(JFFS2_WARN_MSG_PREFIX \
" (%d) %s: " fmt, task_pid_nr(current), \
- __FUNCTION__ , ##__VA_ARGS__); \
+ __func__ , ##__VA_ARGS__); \
} while(0)
#define JFFS2_NOTICE(fmt, ...) \
do { \
printk(JFFS2_NOTICE_MSG_PREFIX \
" (%d) %s: " fmt, task_pid_nr(current), \
- __FUNCTION__ , ##__VA_ARGS__); \
+ __func__ , ##__VA_ARGS__); \
} while(0)
#define JFFS2_DEBUG(fmt, ...) \
do { \
printk(JFFS2_DBG_MSG_PREFIX \
" (%d) %s: " fmt, task_pid_nr(current), \
- __FUNCTION__ , ##__VA_ARGS__); \
+ __func__ , ##__VA_ARGS__); \
} while(0)
/*
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index c63e7a9..c0c141f 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -208,6 +208,13 @@
f = JFFS2_INODE_INFO(inode);
dir_f = JFFS2_INODE_INFO(dir_i);
+ /* jffs2_do_create() will want to lock it, _after_ reserving
+ space and taking c-alloc_sem. If we keep it locked here,
+ lockdep gets unhappy (although it's a false positive;
+ nothing else will be looking at this inode yet so there's
+ no chance of AB-BA deadlock involving its f->sem). */
+ mutex_unlock(&f->sem);
+
ret = jffs2_do_create(c, dir_f, f, ri,
dentry->d_name.name, dentry->d_name.len);
if (ret)
@@ -219,7 +226,8 @@
d_instantiate(dentry, inode);
D1(printk(KERN_DEBUG "jffs2_create: Created ino #%lu with mode %o, nlink %d(%d). nrpages %ld\n",
- inode->i_ino, inode->i_mode, inode->i_nlink, f->inocache->nlink, inode->i_mapping->nrpages));
+ inode->i_ino, inode->i_mode, inode->i_nlink,
+ f->inocache->pino_nlink, inode->i_mapping->nrpages));
return 0;
fail:
@@ -243,7 +251,7 @@
ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
dentry->d_name.len, dead_f, now);
if (dead_f->inocache)
- dentry->d_inode->i_nlink = dead_f->inocache->nlink;
+ dentry->d_inode->i_nlink = dead_f->inocache->pino_nlink;
if (!ret)
dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
return ret;
@@ -276,7 +284,7 @@
if (!ret) {
mutex_lock(&f->sem);
- old_dentry->d_inode->i_nlink = ++f->inocache->nlink;
+ old_dentry->d_inode->i_nlink = ++f->inocache->pino_nlink;
mutex_unlock(&f->sem);
d_instantiate(dentry, old_dentry->d_inode);
dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
@@ -493,11 +501,14 @@
inode->i_op = &jffs2_dir_inode_operations;
inode->i_fop = &jffs2_dir_operations;
- /* Directories get nlink 2 at start */
- inode->i_nlink = 2;
f = JFFS2_INODE_INFO(inode);
+ /* Directories get nlink 2 at start */
+ inode->i_nlink = 2;
+ /* but ic->pino_nlink is the parent ino# */
+ f->inocache->pino_nlink = dir_i->i_ino;
+
ri->data_crc = cpu_to_je32(0);
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
@@ -594,17 +605,25 @@
static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
{
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dir_i->i_sb);
+ struct jffs2_inode_info *dir_f = JFFS2_INODE_INFO(dir_i);
struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
struct jffs2_full_dirent *fd;
int ret;
+ uint32_t now = get_seconds();
for (fd = f->dents ; fd; fd = fd->next) {
if (fd->ino)
return -ENOTEMPTY;
}
- ret = jffs2_unlink(dir_i, dentry);
- if (!ret)
+
+ ret = jffs2_do_unlink(c, dir_f, dentry->d_name.name,
+ dentry->d_name.len, f, now);
+ if (!ret) {
+ dir_i->i_mtime = dir_i->i_ctime = ITIME(now);
+ clear_nlink(dentry->d_inode);
drop_nlink(dir_i);
+ }
return ret;
}
@@ -817,7 +836,10 @@
inode which didn't exist. */
if (victim_f->inocache) {
mutex_lock(&victim_f->sem);
- victim_f->inocache->nlink--;
+ if (S_ISDIR(new_dentry->d_inode->i_mode))
+ victim_f->inocache->pino_nlink = 0;
+ else
+ victim_f->inocache->pino_nlink--;
mutex_unlock(&victim_f->sem);
}
}
@@ -838,8 +860,8 @@
struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
mutex_lock(&f->sem);
inc_nlink(old_dentry->d_inode);
- if (f->inocache)
- f->inocache->nlink++;
+ if (f->inocache && !S_ISDIR(old_dentry->d_inode->i_mode))
+ f->inocache->pino_nlink++;
mutex_unlock(&f->sem);
printk(KERN_NOTICE "jffs2_rename(): Link succeeded, unlink failed (err %d). You now have a hard link\n", ret);
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 25a640e..dddb2a6 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -294,7 +294,7 @@
break;
#endif
default:
- if (ic->nodes == (void *)ic && ic->nlink == 0)
+ if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
jffs2_del_ino_cache(c, ic);
}
}
@@ -332,7 +332,8 @@
if (c->mtd->point) {
unsigned long *wordebuf;
- ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size, &retlen, (unsigned char **)&ebuf);
+ ret = c->mtd->point(c->mtd, jeb->offset, c->sector_size,
+ &retlen, &ebuf, NULL);
if (ret) {
D1(printk(KERN_DEBUG "MTD point failed %d\n", ret));
goto do_flash_read;
@@ -340,7 +341,7 @@
if (retlen < c->sector_size) {
/* Don't muck about if it won't let us point to the whole erase sector */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen));
- c->mtd->unpoint(c->mtd, ebuf, jeb->offset, retlen);
+ c->mtd->unpoint(c->mtd, jeb->offset, retlen);
goto do_flash_read;
}
wordebuf = ebuf-sizeof(*wordebuf);
@@ -349,7 +350,7 @@
if (*++wordebuf != ~0)
break;
} while(--retlen);
- c->mtd->unpoint(c->mtd, ebuf, jeb->offset, c->sector_size);
+ c->mtd->unpoint(c->mtd, jeb->offset, c->sector_size);
if (retlen) {
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08tx\n",
*wordebuf, jeb->offset + c->sector_size-retlen*sizeof(*wordebuf));
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 3eb1c84..086c438 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -273,7 +273,7 @@
inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime));
inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime));
- inode->i_nlink = f->inocache->nlink;
+ inode->i_nlink = f->inocache->pino_nlink;
inode->i_blocks = (inode->i_size + 511) >> 9;
@@ -286,13 +286,12 @@
case S_IFDIR:
{
struct jffs2_full_dirent *fd;
+ inode->i_nlink = 2; /* parent and '.' */
for (fd=f->dents; fd; fd = fd->next) {
if (fd->type == DT_DIR && fd->ino)
inc_nlink(inode);
}
- /* and '..' */
- inc_nlink(inode);
/* Root dir gets i_nlink 3 for some reason */
if (inode->i_ino == 1)
inc_nlink(inode);
@@ -586,11 +585,12 @@
}
struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
- int inum, int nlink)
+ int inum, int unlinked)
{
struct inode *inode;
struct jffs2_inode_cache *ic;
- if (!nlink) {
+
+ if (unlinked) {
/* The inode has zero nlink but its nodes weren't yet marked
obsolete. This has to be because we're still waiting for
the final (close() and) iput() to happen.
@@ -638,8 +638,8 @@
return ERR_CAST(inode);
}
if (is_bad_inode(inode)) {
- printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. nlink %d\n",
- inum, nlink);
+ printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u. unlinked %d\n",
+ inum, unlinked);
/* NB. This will happen again. We need to do something appropriate here. */
iput(inode);
return ERR_PTR(-EIO);
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index bad0056..090c556 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -161,8 +161,8 @@
continue;
}
- if (!ic->nlink) {
- D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n",
+ if (!ic->pino_nlink) {
+ D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink/pino zero\n",
ic->ino));
spin_unlock(&c->inocache_lock);
jffs2_xattr_delete_inode(c, ic);
@@ -398,10 +398,10 @@
it's vaguely possible. */
inum = ic->ino;
- nlink = ic->nlink;
+ nlink = ic->pino_nlink;
spin_unlock(&c->inocache_lock);
- f = jffs2_gc_fetch_inode(c, inum, nlink);
+ f = jffs2_gc_fetch_inode(c, inum, !nlink);
if (IS_ERR(f)) {
ret = PTR_ERR(f);
goto release_sem;
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index 8219df6..1750445 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -177,7 +177,10 @@
#ifdef CONFIG_JFFS2_FS_XATTR
struct jffs2_xattr_ref *xref;
#endif
- int nlink;
+ uint32_t pino_nlink; /* Directories store parent inode
+ here; other inodes store nlink.
+ Zero always means that it's
+ completely unlinked. */
};
/* Inode states for 'state' above. We need the 'GC' state to prevent
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 9df8f3e..a9bf960 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -709,7 +709,7 @@
break;
#endif
default:
- if (ic->nodes == (void *)ic && ic->nlink == 0)
+ if (ic->nodes == (void *)ic && ic->pino_nlink == 0)
jffs2_del_ino_cache(c, ic);
break;
}
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 1b10d25..2cc866c 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -187,7 +187,7 @@
void jffs2_gc_release_inode(struct jffs2_sb_info *c,
struct jffs2_inode_info *f);
struct jffs2_inode_info *jffs2_gc_fetch_inode(struct jffs2_sb_info *c,
- int inum, int nlink);
+ int inum, int unlinked);
unsigned char *jffs2_gc_fetch_page(struct jffs2_sb_info *c,
struct jffs2_inode_info *f,
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index 4cb4d76..6ca08ad 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -63,10 +63,11 @@
/* TODO: instead, incapsulate point() stuff to jffs2_flash_read(),
* adding and jffs2_flash_read_end() interface. */
if (c->mtd->point) {
- err = c->mtd->point(c->mtd, ofs, len, &retlen, &buffer);
+ err = c->mtd->point(c->mtd, ofs, len, &retlen,
+ (void **)&buffer, NULL);
if (!err && retlen < len) {
JFFS2_WARNING("MTD point returned len too short: %zu instead of %u.\n", retlen, tn->csize);
- c->mtd->unpoint(c->mtd, buffer, ofs, retlen);
+ c->mtd->unpoint(c->mtd, ofs, retlen);
} else if (err)
JFFS2_WARNING("MTD point failed: error code %d.\n", err);
else
@@ -100,7 +101,7 @@
kfree(buffer);
#ifndef __ECOS
else
- c->mtd->unpoint(c->mtd, buffer, ofs, len);
+ c->mtd->unpoint(c->mtd, ofs, len);
#endif
if (crc != tn->data_crc) {
@@ -136,7 +137,7 @@
kfree(buffer);
#ifndef __ECOS
else
- c->mtd->unpoint(c->mtd, buffer, ofs, len);
+ c->mtd->unpoint(c->mtd, ofs, len);
#endif
return err;
}
@@ -1123,7 +1124,8 @@
size_t retlen;
int ret;
- dbg_readinode("ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink);
+ dbg_readinode("ino #%u pino/nlink is %d\n", f->inocache->ino,
+ f->inocache->pino_nlink);
memset(&rii, 0, sizeof(rii));
@@ -1358,7 +1360,7 @@
}
dbg_readinode("creating inocache for root inode\n");
memset(f->inocache, 0, sizeof(struct jffs2_inode_cache));
- f->inocache->ino = f->inocache->nlink = 1;
+ f->inocache->ino = f->inocache->pino_nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->state = INO_STATE_READING;
jffs2_add_ino_cache(c, f->inocache);
@@ -1401,7 +1403,7 @@
jffs2_clear_acl(f);
jffs2_xattr_delete_inode(c, f->inocache);
mutex_lock(&f->sem);
- deleted = f->inocache && !f->inocache->nlink;
+ deleted = f->inocache && !f->inocache->pino_nlink;
if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index 272872d..1d437de 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -97,11 +97,12 @@
size_t pointlen;
if (c->mtd->point) {
- ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf);
+ ret = c->mtd->point(c->mtd, 0, c->mtd->size, &pointlen,
+ (void **)&flashbuf, NULL);
if (!ret && pointlen < c->mtd->size) {
/* Don't muck about if it won't let us point to the whole flash */
D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
- c->mtd->unpoint(c->mtd, flashbuf, 0, pointlen);
+ c->mtd->unpoint(c->mtd, 0, pointlen);
flashbuf = NULL;
}
if (ret)
@@ -267,7 +268,7 @@
kfree(flashbuf);
#ifndef __ECOS
else
- c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size);
+ c->mtd->unpoint(c->mtd, 0, c->mtd->size);
#endif
if (s)
kfree(s);
@@ -940,7 +941,7 @@
ic->nodes = (void *)ic;
jffs2_add_ino_cache(c, ic);
if (ino == 1)
- ic->nlink = 1;
+ ic->pino_nlink = 1;
return ic;
}
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index f3353df..7da69ea 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -31,11 +31,12 @@
static struct inode *jffs2_alloc_inode(struct super_block *sb)
{
- struct jffs2_inode_info *ei;
- ei = (struct jffs2_inode_info *)kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
- if (!ei)
+ struct jffs2_inode_info *f;
+
+ f = kmem_cache_alloc(jffs2_inode_cachep, GFP_KERNEL);
+ if (!f)
return NULL;
- return &ei->vfs_inode;
+ return &f->vfs_inode;
}
static void jffs2_destroy_inode(struct inode *inode)
@@ -45,10 +46,10 @@
static void jffs2_i_init_once(struct kmem_cache *cachep, void *foo)
{
- struct jffs2_inode_info *ei = (struct jffs2_inode_info *) foo;
+ struct jffs2_inode_info *f = foo;
- mutex_init(&ei->sem);
- inode_init_once(&ei->vfs_inode);
+ mutex_init(&f->sem);
+ inode_init_once(&f->vfs_inode);
}
static int jffs2_sync_fs(struct super_block *sb, int wait)
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index 8de52b6..0e78b00 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -494,7 +494,7 @@
/* If it's an in-core inode, then we have to adjust any
full_dirent or full_dnode structure to point to the
new version instead of the old */
- f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink);
+ f = jffs2_gc_fetch_inode(c, ic->ino, !ic->pino_nlink);
if (IS_ERR(f)) {
/* Should never happen; it _must_ be present */
JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n",
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 665fce9..ca29440 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -19,7 +19,8 @@
#include "compr.h"
-int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t mode, struct jffs2_raw_inode *ri)
+int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
+ uint32_t mode, struct jffs2_raw_inode *ri)
{
struct jffs2_inode_cache *ic;
@@ -31,7 +32,7 @@
memset(ic, 0, sizeof(*ic));
f->inocache = ic;
- f->inocache->nlink = 1;
+ f->inocache->pino_nlink = 1; /* Will be overwritten shortly for directories */
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
f->inocache->state = INO_STATE_PRESENT;
@@ -438,10 +439,10 @@
ret = jffs2_reserve_space(c, sizeof(*ri), &alloclen, ALLOC_NORMAL,
JFFS2_SUMMARY_INODE_SIZE);
D1(printk(KERN_DEBUG "jffs2_do_create(): reserved 0x%x bytes\n", alloclen));
- if (ret) {
- mutex_unlock(&f->sem);
+ if (ret)
return ret;
- }
+
+ mutex_lock(&f->sem);
ri->data_crc = cpu_to_je32(0);
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
@@ -635,9 +636,9 @@
jffs2_mark_node_obsolete(c, fd->raw);
jffs2_free_full_dirent(fd);
}
- }
-
- dead_f->inocache->nlink--;
+ dead_f->inocache->pino_nlink = 0;
+ } else
+ dead_f->inocache->pino_nlink--;
/* NB: Caller must set inode nlink if appropriate */
mutex_unlock(&dead_f->sem);
}
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c
index e486659..082e844 100644
--- a/fs/jffs2/xattr.c
+++ b/fs/jffs2/xattr.c
@@ -82,7 +82,7 @@
static void unload_xattr_datum(struct jffs2_sb_info *c, struct jffs2_xattr_datum *xd)
{
/* must be called under down_write(xattr_sem) */
- D1(dbg_xattr("%s: xid=%u, version=%u\n", __FUNCTION__, xd->xid, xd->version));
+ D1(dbg_xattr("%s: xid=%u, version=%u\n", __func__, xd->xid, xd->version));
if (xd->xname) {
c->xdatum_mem_usage -= (xd->name_len + 1 + xd->value_len);
kfree(xd->xname);
@@ -592,7 +592,7 @@
When an inode with XATTR is removed, those XATTRs must be removed. */
struct jffs2_xattr_ref *ref, *_ref;
- if (!ic || ic->nlink > 0)
+ if (!ic || ic->pino_nlink > 0)
return;
down_write(&c->xattr_sem);
@@ -829,7 +829,7 @@
ref->xd and ref->ic are not valid yet. */
xd = jffs2_find_xattr_datum(c, ref->xid);
ic = jffs2_get_ino_cache(c, ref->ino);
- if (!xd || !ic || !ic->nlink) {
+ if (!xd || !ic || !ic->pino_nlink) {
dbg_xattr("xref(ino=%u, xid=%u, xseqno=%u) is orphan.\n",
ref->ino, ref->xid, ref->xseqno);
ref->xseqno |= XREF_DELETE_MARKER;
@@ -1252,7 +1252,7 @@
rc = jffs2_reserve_space_gc(c, totlen, &length, JFFS2_SUMMARY_XREF_SIZE);
if (rc) {
JFFS2_WARNING("%s: jffs2_reserve_space_gc() = %d, request = %u\n",
- __FUNCTION__, rc, totlen);
+ __func__, rc, totlen);
rc = rc ? rc : -EBADFD;
goto out;
}
diff --git a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c
index 887f575..bf6ab19 100644
--- a/fs/jfs/jfs_debug.c
+++ b/fs/jfs/jfs_debug.c
@@ -89,7 +89,7 @@
{
int i;
- if (!(base = proc_mkdir("jfs", proc_root_fs)))
+ if (!(base = proc_mkdir("fs/jfs", NULL)))
return;
base->owner = THIS_MODULE;
@@ -109,7 +109,7 @@
if (base) {
for (i = 0; i < NPROCENT; i++)
remove_proc_entry(Entries[i].name, base);
- remove_proc_entry("jfs", proc_root_fs);
+ remove_proc_entry("fs/jfs", NULL);
}
}
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 40b16f2..5df517b 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -573,7 +573,7 @@
/* Ensure the resulting lock will get added to granted list */
fl->fl_flags |= FL_SLEEP;
if (do_vfs_lock(fl) < 0)
- printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__);
up_read(&host->h_rwsem);
fl->fl_flags = fl_flags;
status = 0;
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 4d81553..81aca85 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -752,7 +752,7 @@
return;
default:
printk(KERN_WARNING "lockd: unexpected error %d in %s!\n",
- -error, __FUNCTION__);
+ -error, __func__);
nlmsvc_insert_block(block, 10 * HZ);
nlmsvc_release_block(block);
return;
diff --git a/fs/locks.c b/fs/locks.c
index 44d9a6a..663c069 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -116,6 +116,7 @@
#include <linux/capability.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 2d4358c..05ff4f1 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -609,7 +609,7 @@
if (corrupt < 0) {
fat_fs_panic(new_dir->i_sb,
"%s: Filesystem corrupted (i_pos %lld)",
- __FUNCTION__, sinfo.i_pos);
+ __func__, sinfo.i_pos);
}
goto out;
}
diff --git a/fs/namei.c b/fs/namei.c
index e179f71..32fd965 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -30,6 +30,7 @@
#include <linux/capability.h>
#include <linux/file.h>
#include <linux/fcntl.h>
+#include <linux/device_cgroup.h>
#include <asm/namei.h>
#include <asm/uaccess.h>
@@ -281,6 +282,10 @@
if (retval)
return retval;
+ retval = devcgroup_inode_permission(inode, mask);
+ if (retval)
+ return retval;
+
return security_inode_permission(inode, mask, nd);
}
@@ -2028,6 +2033,10 @@
if (!dir->i_op || !dir->i_op->mknod)
return -EPERM;
+ error = devcgroup_inode_mknod(mode, dev);
+ if (error)
+ return error;
+
error = security_inode_mknod(dir, dentry, mode, dev);
if (error)
return error;
diff --git a/fs/namespace.c b/fs/namespace.c
index fe37680..4fc302c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1176,17 +1176,6 @@
#endif
}
-static int lives_below_in_same_fs(struct dentry *d, struct dentry *dentry)
-{
- while (1) {
- if (d == dentry)
- return 1;
- if (d == NULL || d == d->d_parent)
- return 0;
- d = d->d_parent;
- }
-}
-
struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
int flag)
{
@@ -1203,7 +1192,7 @@
p = mnt;
list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) {
- if (!lives_below_in_same_fs(r->mnt_mountpoint, dentry))
+ if (!is_subdir(r->mnt_mountpoint, dentry))
continue;
for (s = r; s; s = next_mnt(s, r)) {
@@ -2340,10 +2329,10 @@
err = sysfs_init();
if (err)
printk(KERN_WARNING "%s: sysfs_init error: %d\n",
- __FUNCTION__, err);
+ __func__, err);
fs_kobj = kobject_create_and_add("fs", NULL);
if (!fs_kobj)
- printk(KERN_WARNING "%s: kobj create error\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: kobj create error\n", __func__);
init_rootfs();
init_mount_tree();
}
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index df6d60b..97645f1 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -102,48 +102,47 @@
}
static inline char *
- ncp_reply_data(struct ncp_server *server, int offset)
+ncp_reply_data(struct ncp_server *server, int offset)
{
return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
}
-static inline __u8 BVAL(void* data)
+static inline u8 BVAL(void *data)
{
- return get_unaligned((__u8*)data);
+ return *(u8 *)data;
}
-static __u8
- ncp_reply_byte(struct ncp_server *server, int offset)
+static u8 ncp_reply_byte(struct ncp_server *server, int offset)
{
- return get_unaligned((__u8 *) ncp_reply_data(server, offset));
+ return *(u8 *)ncp_reply_data(server, offset);
}
-static inline __u16 WVAL_LH(void* data)
+static inline u16 WVAL_LH(void *data)
{
- return le16_to_cpu(get_unaligned((__le16*)data));
+ return get_unaligned_le16(data);
}
-static __u16
- ncp_reply_le16(struct ncp_server *server, int offset)
+static u16
+ncp_reply_le16(struct ncp_server *server, int offset)
{
- return le16_to_cpu(get_unaligned((__le16 *) ncp_reply_data(server, offset)));
+ return get_unaligned_le16(ncp_reply_data(server, offset));
}
-static __u16
- ncp_reply_be16(struct ncp_server *server, int offset)
+static u16
+ncp_reply_be16(struct ncp_server *server, int offset)
{
- return be16_to_cpu(get_unaligned((__be16 *) ncp_reply_data(server, offset)));
+ return get_unaligned_be16(ncp_reply_data(server, offset));
}
-static inline __u32 DVAL_LH(void* data)
+static inline u32 DVAL_LH(void *data)
{
- return le32_to_cpu(get_unaligned((__le32*)data));
+ return get_unaligned_le32(data);
}
static __le32
- ncp_reply_dword(struct ncp_server *server, int offset)
+ncp_reply_dword(struct ncp_server *server, int offset)
{
- return get_unaligned((__le32 *) ncp_reply_data(server, offset));
+ return get_unaligned((__le32 *)ncp_reply_data(server, offset));
}
static inline __u32 ncp_reply_dword_lh(struct ncp_server* server, int offset) {
@@ -1006,8 +1005,8 @@
result = ncp_request2(server, 72, bounce, bufsize);
ncp_unlock_server(server);
if (!result) {
- int len = be16_to_cpu(get_unaligned((__be16*)((char*)bounce +
- sizeof(struct ncp_reply_header))));
+ int len = get_unaligned_be16((char *)bounce +
+ sizeof(struct ncp_reply_header));
result = -EIO;
if (len <= to_read) {
char* source;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index f2f3b28..89ac5bb 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1321,6 +1321,7 @@
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
static int nfs_volume_list_open(struct inode *inode, struct file *file);
@@ -1341,6 +1342,7 @@
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
/*
@@ -1500,33 +1502,29 @@
{
struct proc_dir_entry *p;
- proc_fs_nfs = proc_mkdir("nfsfs", proc_root_fs);
+ proc_fs_nfs = proc_mkdir("fs/nfsfs", NULL);
if (!proc_fs_nfs)
goto error_0;
proc_fs_nfs->owner = THIS_MODULE;
/* a file of servers with which we're dealing */
- p = create_proc_entry("servers", S_IFREG|S_IRUGO, proc_fs_nfs);
+ p = proc_create("servers", S_IFREG|S_IRUGO,
+ proc_fs_nfs, &nfs_server_list_fops);
if (!p)
goto error_1;
- p->proc_fops = &nfs_server_list_fops;
- p->owner = THIS_MODULE;
-
/* a file of volumes that we have mounted */
- p = create_proc_entry("volumes", S_IFREG|S_IRUGO, proc_fs_nfs);
+ p = proc_create("volumes", S_IFREG|S_IRUGO,
+ proc_fs_nfs, &nfs_volume_list_fops);
if (!p)
goto error_2;
-
- p->proc_fops = &nfs_volume_list_fops;
- p->owner = THIS_MODULE;
return 0;
error_2:
remove_proc_entry("servers", proc_fs_nfs);
error_1:
- remove_proc_entry("nfsfs", proc_root_fs);
+ remove_proc_entry("fs/nfsfs", NULL);
error_0:
return -ENOMEM;
}
@@ -1538,7 +1536,7 @@
{
remove_proc_entry("volumes", proc_fs_nfs);
remove_proc_entry("servers", proc_fs_nfs);
- remove_proc_entry("nfsfs", proc_root_fs);
+ remove_proc_entry("fs/nfsfs", NULL);
}
#endif /* CONFIG_PROC_FS */
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index fa220dc..7226a50 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1575,6 +1575,11 @@
return nfs_compare_mount_options(sb, server, mntflags);
}
+static int nfs_bdi_register(struct nfs_server *server)
+{
+ return bdi_register_dev(&server->backing_dev_info, server->s_dev);
+}
+
static int nfs_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
{
@@ -1617,6 +1622,10 @@
if (s->s_fs_info != server) {
nfs_free_server(server);
server = NULL;
+ } else {
+ error = nfs_bdi_register(server);
+ if (error)
+ goto error_splat_super;
}
if (!s->s_root) {
@@ -1664,6 +1673,7 @@
{
struct nfs_server *server = NFS_SB(s);
+ bdi_unregister(&server->backing_dev_info);
kill_anon_super(s);
nfs_free_server(server);
}
@@ -1708,6 +1718,10 @@
if (s->s_fs_info != server) {
nfs_free_server(server);
server = NULL;
+ } else {
+ error = nfs_bdi_register(server);
+ if (error)
+ goto error_splat_super;
}
if (!s->s_root) {
@@ -1984,6 +1998,10 @@
if (s->s_fs_info != server) {
nfs_free_server(server);
server = NULL;
+ } else {
+ error = nfs_bdi_register(server);
+ if (error)
+ goto error_splat_super;
}
if (!s->s_root) {
@@ -2070,6 +2088,10 @@
if (s->s_fs_info != server) {
nfs_free_server(server);
server = NULL;
+ } else {
+ error = nfs_bdi_register(server);
+ if (error)
+ goto error_splat_super;
}
if (!s->s_root) {
@@ -2149,6 +2171,10 @@
if (s->s_fs_info != server) {
nfs_free_server(server);
server = NULL;
+ } else {
+ error = nfs_bdi_register(server);
+ if (error)
+ goto error_splat_super;
}
if (!s->s_root) {
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 562abf3..0b3ffa9 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -104,7 +104,7 @@
} while (0)
#define RESERVE_SPACE(nbytes) do { \
p = xdr_reserve_space(xdr, nbytes); \
- if (!p) dprintk("NFSD: RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __FUNCTION__); \
+ if (!p) dprintk("NFSD: RESERVE_SPACE(%d) failed in function %s\n", (int) (nbytes), __func__); \
BUG_ON(!p); \
} while (0)
@@ -134,7 +134,7 @@
p = xdr_inline_decode(xdr, nbytes); \
if (!p) { \
dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \
- __FUNCTION__, __LINE__); \
+ __func__, __LINE__); \
return -EIO; \
} \
} while (0)
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 42f3820..5ac00c4 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -169,6 +169,7 @@
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
/*----------------------------------------------------------------------------*/
@@ -801,10 +802,9 @@
entry = proc_mkdir("fs/nfs", NULL);
if (!entry)
return -ENOMEM;
- entry = create_proc_entry("fs/nfs/exports", 0, NULL);
+ entry = proc_create("exports", 0, entry, &exports_operations);
if (!entry)
return -ENOMEM;
- entry->proc_fops = &exports_operations;
return 0;
}
#else /* CONFIG_PROC_FS */
diff --git a/fs/ntfs/debug.h b/fs/ntfs/debug.h
index 8ac37c3..5e6724c 100644
--- a/fs/ntfs/debug.h
+++ b/fs/ntfs/debug.h
@@ -45,7 +45,7 @@
extern void __ntfs_debug (const char *file, int line, const char *function,
const char *format, ...) __attribute__ ((format (printf, 4, 5)));
#define ntfs_debug(f, a...) \
- __ntfs_debug(__FILE__, __LINE__, __FUNCTION__, f, ##a)
+ __ntfs_debug(__FILE__, __LINE__, __func__, f, ##a)
extern void ntfs_debug_dump_runlist(const runlist_element *rl);
@@ -58,10 +58,10 @@
extern void __ntfs_warning(const char *function, const struct super_block *sb,
const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
-#define ntfs_warning(sb, f, a...) __ntfs_warning(__FUNCTION__, sb, f, ##a)
+#define ntfs_warning(sb, f, a...) __ntfs_warning(__func__, sb, f, ##a)
extern void __ntfs_error(const char *function, const struct super_block *sb,
const char *fmt, ...) __attribute__ ((format (printf, 3, 4)));
-#define ntfs_error(sb, f, a...) __ntfs_error(__FUNCTION__, sb, f, ##a)
+#define ntfs_error(sb, f, a...) __ntfs_error(__func__, sb, f, ##a)
#endif /* _LINUX_NTFS_DEBUG_H */
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index 2ad5c8b..790defb 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -1191,7 +1191,7 @@
if (size) {
page = ntfs_map_page(mftbmp_mapping,
ofs >> PAGE_CACHE_SHIFT);
- if (unlikely(IS_ERR(page))) {
+ if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to read mft "
"bitmap, aborting.");
return PTR_ERR(page);
@@ -2118,7 +2118,7 @@
}
/* Read, map, and pin the page containing the mft record. */
page = ntfs_map_page(mft_vi->i_mapping, index);
- if (unlikely(IS_ERR(page))) {
+ if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to map page containing mft record "
"to format 0x%llx.", (long long)mft_no);
return PTR_ERR(page);
@@ -2519,7 +2519,7 @@
ofs = (bit << vol->mft_record_size_bits) & ~PAGE_CACHE_MASK;
/* Read, map, and pin the page containing the mft record. */
page = ntfs_map_page(vol->mft_ino->i_mapping, index);
- if (unlikely(IS_ERR(page))) {
+ if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to map page containing allocated "
"mft record 0x%llx.", (long long)bit);
err = PTR_ERR(page);
diff --git a/fs/ocfs2/cluster/sys.c b/fs/ocfs2/cluster/sys.c
index 98429fd..bc702da 100644
--- a/fs/ocfs2/cluster/sys.c
+++ b/fs/ocfs2/cluster/sys.c
@@ -65,7 +65,7 @@
{
int ret;
- o2cb_kset = kset_create_and_add("o2cb", NULL, NULL);
+ o2cb_kset = kset_create_and_add("o2cb", NULL, fs_kobj);
if (!o2cb_kset)
return -ENOMEM;
diff --git a/fs/ocfs2/dlm/dlmdebug.c b/fs/ocfs2/dlm/dlmdebug.c
index 5f6d8587..1b81dcb 100644
--- a/fs/ocfs2/dlm/dlmdebug.c
+++ b/fs/ocfs2/dlm/dlmdebug.c
@@ -44,7 +44,8 @@
#define MLOG_MASK_PREFIX ML_DLM
#include "cluster/masklog.h"
-int stringify_lockname(const char *lockname, int locklen, char *buf, int len);
+static int stringify_lockname(const char *lockname, int locklen, char *buf,
+ int len);
void dlm_print_one_lock_resource(struct dlm_lock_resource *res)
{
@@ -251,7 +252,8 @@
*
* For more on lockname formats, please refer to dlmglue.c and ocfs2_lockid.h.
*/
-int stringify_lockname(const char *lockname, int locklen, char *buf, int len)
+static int stringify_lockname(const char *lockname, int locklen, char *buf,
+ int len)
{
int out = 0;
__be64 inode_blkno_be;
@@ -368,7 +370,7 @@
kfree(dc);
}
-void dlm_debug_put(struct dlm_debug_ctxt *dc)
+static void dlm_debug_put(struct dlm_debug_ctxt *dc)
{
if (dc)
kref_put(&dc->debug_refcnt, dlm_debug_free);
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index 61a000f..e48aba6 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -327,7 +327,7 @@
static struct backing_dev_info dlmfs_backing_dev_info = {
.ra_pages = 0, /* No readahead */
- .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
static struct inode *dlmfs_get_root_inode(struct super_block *sb)
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 9154c82d3..57e0d30 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1048,6 +1048,10 @@
mlog_entry("(0x%p, '%.*s')\n", dentry,
dentry->d_name.len, dentry->d_name.name);
+ /* ensuring we don't even attempt to truncate a symlink */
+ if (S_ISLNK(inode->i_mode))
+ attr->ia_valid &= ~ATTR_SIZE;
+
if (attr->ia_valid & ATTR_MODE)
mlog(0, "mode change: %d\n", attr->ia_mode);
if (attr->ia_valid & ATTR_UID)
diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c
index ce0dc14..be774bd 100644
--- a/fs/ocfs2/localalloc.c
+++ b/fs/ocfs2/localalloc.c
@@ -260,7 +260,7 @@
bh = osb->local_alloc_bh;
alloc = (struct ocfs2_dinode *) bh->b_data;
- alloc_copy = kmalloc(bh->b_size, GFP_KERNEL);
+ alloc_copy = kmalloc(bh->b_size, GFP_NOFS);
if (!alloc_copy) {
status = -ENOMEM;
goto out_commit;
@@ -931,7 +931,7 @@
* local alloc shutdown won't try to double free main bitmap
* bits. Make a copy so the sync function knows which bits to
* free. */
- alloc_copy = kmalloc(osb->local_alloc_bh->b_size, GFP_KERNEL);
+ alloc_copy = kmalloc(osb->local_alloc_bh->b_size, GFP_NOFS);
if (!alloc_copy) {
status = -ENOMEM;
mlog_errno(status);
diff --git a/fs/ocfs2/stack_o2cb.c b/fs/ocfs2/stack_o2cb.c
index ac1d74c..bbd1667 100644
--- a/fs/ocfs2/stack_o2cb.c
+++ b/fs/ocfs2/stack_o2cb.c
@@ -385,7 +385,7 @@
return 0;
}
-struct ocfs2_stack_operations o2cb_stack_ops = {
+static struct ocfs2_stack_operations o2cb_stack_ops = {
.connect = o2cb_cluster_connect,
.disconnect = o2cb_cluster_disconnect,
.hangup = o2cb_cluster_hangup,
diff --git a/fs/ocfs2/stack_user.c b/fs/ocfs2/stack_user.c
index 7428663..b503772 100644
--- a/fs/ocfs2/stack_user.c
+++ b/fs/ocfs2/stack_user.c
@@ -635,7 +635,7 @@
.owner = THIS_MODULE,
};
-struct miscdevice ocfs2_control_device = {
+static struct miscdevice ocfs2_control_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "ocfs2_control",
.fops = &ocfs2_control_fops,
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index 7134007..ba9dbb5 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -167,9 +167,11 @@
.readlink = page_readlink,
.follow_link = ocfs2_follow_link,
.getattr = ocfs2_getattr,
+ .setattr = ocfs2_setattr,
};
const struct inode_operations ocfs2_fast_symlink_inode_operations = {
.readlink = ocfs2_readlink,
.follow_link = ocfs2_follow_link,
.getattr = ocfs2_getattr,
+ .setattr = ocfs2_setattr,
};
diff --git a/fs/open.c b/fs/open.c
index 7af1f05..a145008 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -7,6 +7,7 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/quotaops.h>
#include <linux/fsnotify.h>
#include <linux/module.h>
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
index e7dd1d4..0fdda2e 100644
--- a/fs/partitions/ldm.c
+++ b/fs/partitions/ldm.c
@@ -41,12 +41,12 @@
#ifndef CONFIG_LDM_DEBUG
#define ldm_debug(...) do {} while (0)
#else
-#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __FUNCTION__, f, ##a)
+#define ldm_debug(f, a...) _ldm_printk (KERN_DEBUG, __func__, f, ##a)
#endif
-#define ldm_crit(f, a...) _ldm_printk (KERN_CRIT, __FUNCTION__, f, ##a)
-#define ldm_error(f, a...) _ldm_printk (KERN_ERR, __FUNCTION__, f, ##a)
-#define ldm_info(f, a...) _ldm_printk (KERN_INFO, __FUNCTION__, f, ##a)
+#define ldm_crit(f, a...) _ldm_printk (KERN_CRIT, __func__, f, ##a)
+#define ldm_error(f, a...) _ldm_printk (KERN_ERR, __func__, f, ##a)
+#define ldm_info(f, a...) _ldm_printk (KERN_INFO, __func__, f, ##a)
__attribute__ ((format (printf, 3, 4)))
static void _ldm_printk (const char *level, const char *function,
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 07d6c48..dca997a 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -73,6 +73,7 @@
#include <linux/signal.h>
#include <linux/highmem.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/times.h>
#include <linux/cpuset.h>
#include <linux/rcupdate.h>
@@ -425,12 +426,13 @@
cutime = cstime = utime = stime = cputime_zero;
cgtime = gtime = cputime_zero;
- rcu_read_lock();
if (lock_task_sighand(task, &flags)) {
struct signal_struct *sig = task->signal;
if (sig->tty) {
- tty_pgrp = pid_nr_ns(sig->tty->pgrp, ns);
+ struct pid *pgrp = tty_get_pgrp(sig->tty);
+ tty_pgrp = pid_nr_ns(pgrp, ns);
+ put_pid(pgrp);
tty_nr = new_encode_dev(tty_devnum(sig->tty));
}
@@ -469,7 +471,6 @@
unlock_task_sighand(task, &flags);
}
- rcu_read_unlock();
if (!whole || num_threads < 2)
wchan = get_wchan(task);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index c5e412a..808cbdc 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -56,6 +56,7 @@
#include <linux/init.h>
#include <linux/capability.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/namei.h>
@@ -195,12 +196,32 @@
return result;
}
-#define MAY_PTRACE(task) \
- (task == current || \
- (task->parent == current && \
- (task->ptrace & PT_PTRACED) && \
- (task_is_stopped_or_traced(task)) && \
- security_ptrace(current,task) == 0))
+/*
+ * Return zero if current may access user memory in @task, -error if not.
+ */
+static int check_mem_permission(struct task_struct *task)
+{
+ /*
+ * A task can always look at itself, in case it chooses
+ * to use system calls instead of load instructions.
+ */
+ if (task == current)
+ return 0;
+
+ /*
+ * If current is actively ptrace'ing, and would also be
+ * permitted to freshly attach with ptrace now, permit it.
+ */
+ if (task->parent == current && (task->ptrace & PT_PTRACED) &&
+ task_is_stopped_or_traced(task) &&
+ ptrace_may_attach(task))
+ return 0;
+
+ /*
+ * Noone else is allowed.
+ */
+ return -EPERM;
+}
struct mm_struct *mm_for_maps(struct task_struct *task)
{
@@ -722,7 +743,7 @@
if (!task)
goto out_no_task;
- if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+ if (check_mem_permission(task))
goto out;
ret = -ENOMEM;
@@ -748,7 +769,7 @@
this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
retval = access_process_vm(task, src, page, this_len, 0);
- if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) {
+ if (!retval || check_mem_permission(task)) {
if (!ret)
ret = -EIO;
break;
@@ -792,7 +813,7 @@
if (!task)
goto out_no_task;
- if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+ if (check_mem_permission(task))
goto out;
copied = -ENOMEM;
@@ -1181,6 +1202,81 @@
#endif
+/*
+ * We added or removed a vma mapping the executable. The vmas are only mapped
+ * during exec and are not mapped with the mmap system call.
+ * Callers must hold down_write() on the mm's mmap_sem for these
+ */
+void added_exe_file_vma(struct mm_struct *mm)
+{
+ mm->num_exe_file_vmas++;
+}
+
+void removed_exe_file_vma(struct mm_struct *mm)
+{
+ mm->num_exe_file_vmas--;
+ if ((mm->num_exe_file_vmas == 0) && mm->exe_file){
+ fput(mm->exe_file);
+ mm->exe_file = NULL;
+ }
+
+}
+
+void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
+{
+ if (new_exe_file)
+ get_file(new_exe_file);
+ if (mm->exe_file)
+ fput(mm->exe_file);
+ mm->exe_file = new_exe_file;
+ mm->num_exe_file_vmas = 0;
+}
+
+struct file *get_mm_exe_file(struct mm_struct *mm)
+{
+ struct file *exe_file;
+
+ /* We need mmap_sem to protect against races with removal of
+ * VM_EXECUTABLE vmas */
+ down_read(&mm->mmap_sem);
+ exe_file = mm->exe_file;
+ if (exe_file)
+ get_file(exe_file);
+ up_read(&mm->mmap_sem);
+ return exe_file;
+}
+
+void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm)
+{
+ /* It's safe to write the exe_file pointer without exe_file_lock because
+ * this is called during fork when the task is not yet in /proc */
+ newmm->exe_file = get_mm_exe_file(oldmm);
+}
+
+static int proc_exe_link(struct inode *inode, struct path *exe_path)
+{
+ struct task_struct *task;
+ struct mm_struct *mm;
+ struct file *exe_file;
+
+ task = get_proc_task(inode);
+ if (!task)
+ return -ENOENT;
+ mm = get_task_mm(task);
+ put_task_struct(task);
+ if (!mm)
+ return -ENOENT;
+ exe_file = get_mm_exe_file(mm);
+ mmput(mm);
+ if (exe_file) {
+ *exe_path = exe_file->f_path;
+ path_get(&exe_file->f_path);
+ fput(exe_file);
+ return 0;
+ } else
+ return -ENOENT;
+}
+
static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index a36ad3c..9d53b39 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -69,12 +69,7 @@
count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
start = NULL;
- if (dp->get_info) {
- /* Handle old net routines */
- n = dp->get_info(page, &start, *ppos, count);
- if (n < count)
- eof = 1;
- } else if (dp->read_proc) {
+ if (dp->read_proc) {
/*
* How to be a proc read function
* ------------------------------
@@ -277,8 +272,11 @@
int len;
int rtn = 0;
+ de = *ret;
+ if (!de)
+ de = &proc_root;
+
spin_lock(&proc_subdir_lock);
- de = &proc_root;
while (1) {
next = strchr(cp, '/');
if (!next)
@@ -385,20 +383,18 @@
lock_kernel();
spin_lock(&proc_subdir_lock);
- if (de) {
- for (de = de->subdir; de ; de = de->next) {
- if (de->namelen != dentry->d_name.len)
- continue;
- if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
- unsigned int ino;
+ for (de = de->subdir; de ; de = de->next) {
+ if (de->namelen != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
+ unsigned int ino;
- ino = de->low_ino;
- de_get(de);
- spin_unlock(&proc_subdir_lock);
- error = -EINVAL;
- inode = proc_get_inode(dir->i_sb, ino, de);
- goto out_unlock;
- }
+ ino = de->low_ino;
+ de_get(de);
+ spin_unlock(&proc_subdir_lock);
+ error = -EINVAL;
+ inode = proc_get_inode(dir->i_sb, ino, de);
+ goto out_unlock;
}
}
spin_unlock(&proc_subdir_lock);
@@ -410,7 +406,8 @@
d_add(dentry, inode);
return NULL;
}
- de_put(de);
+ if (de)
+ de_put(de);
return ERR_PTR(error);
}
@@ -440,10 +437,6 @@
lock_kernel();
ino = inode->i_ino;
- if (!de) {
- ret = -EINVAL;
- goto out;
- }
i = filp->f_pos;
switch (i) {
case 0:
@@ -582,7 +575,7 @@
/* make sure name is valid */
if (!name || !strlen(name)) goto out;
- if (!(*parent) && xlate_proc_name(name, parent, &fn) != 0)
+ if (xlate_proc_name(name, parent, &fn) != 0)
goto out;
/* At this point there must not be any '/' characters beyond *fn */
@@ -682,9 +675,10 @@
return ent;
}
-struct proc_dir_entry *proc_create(const char *name, mode_t mode,
- struct proc_dir_entry *parent,
- const struct file_operations *proc_fops)
+struct proc_dir_entry *proc_create_data(const char *name, mode_t mode,
+ struct proc_dir_entry *parent,
+ const struct file_operations *proc_fops,
+ void *data)
{
struct proc_dir_entry *pde;
nlink_t nlink;
@@ -705,6 +699,7 @@
if (!pde)
goto out;
pde->proc_fops = proc_fops;
+ pde->data = data;
if (proc_register(parent, pde) < 0)
goto out_free;
return pde;
@@ -734,55 +729,58 @@
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
{
struct proc_dir_entry **p;
- struct proc_dir_entry *de;
+ struct proc_dir_entry *de = NULL;
const char *fn = name;
int len;
- if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
- goto out;
+ if (xlate_proc_name(name, &parent, &fn) != 0)
+ return;
len = strlen(fn);
spin_lock(&proc_subdir_lock);
for (p = &parent->subdir; *p; p=&(*p)->next ) {
- if (!proc_match(len, fn, *p))
- continue;
- de = *p;
- *p = de->next;
- de->next = NULL;
-
- spin_lock(&de->pde_unload_lock);
- /*
- * Stop accepting new callers into module. If you're
- * dynamically allocating ->proc_fops, save a pointer somewhere.
- */
- de->proc_fops = NULL;
- /* Wait until all existing callers into module are done. */
- if (de->pde_users > 0) {
- DECLARE_COMPLETION_ONSTACK(c);
-
- if (!de->pde_unload_completion)
- de->pde_unload_completion = &c;
-
- spin_unlock(&de->pde_unload_lock);
- spin_unlock(&proc_subdir_lock);
-
- wait_for_completion(de->pde_unload_completion);
-
- spin_lock(&proc_subdir_lock);
- goto continue_removing;
+ if (proc_match(len, fn, *p)) {
+ de = *p;
+ *p = de->next;
+ de->next = NULL;
+ break;
}
- spin_unlock(&de->pde_unload_lock);
-
-continue_removing:
- if (S_ISDIR(de->mode))
- parent->nlink--;
- de->nlink = 0;
- WARN_ON(de->subdir);
- if (atomic_dec_and_test(&de->count))
- free_proc_entry(de);
- break;
}
spin_unlock(&proc_subdir_lock);
-out:
- return;
+ if (!de)
+ return;
+
+ spin_lock(&de->pde_unload_lock);
+ /*
+ * Stop accepting new callers into module. If you're
+ * dynamically allocating ->proc_fops, save a pointer somewhere.
+ */
+ de->proc_fops = NULL;
+ /* Wait until all existing callers into module are done. */
+ if (de->pde_users > 0) {
+ DECLARE_COMPLETION_ONSTACK(c);
+
+ if (!de->pde_unload_completion)
+ de->pde_unload_completion = &c;
+
+ spin_unlock(&de->pde_unload_lock);
+
+ wait_for_completion(de->pde_unload_completion);
+
+ goto continue_removing;
+ }
+ spin_unlock(&de->pde_unload_lock);
+
+continue_removing:
+ if (S_ISDIR(de->mode))
+ parent->nlink--;
+ de->nlink = 0;
+ if (de->subdir) {
+ printk(KERN_WARNING "%s: removing non-empty directory "
+ "'%s/%s', leaking at least '%s'\n", __func__,
+ de->parent->name, de->name, de->subdir->name);
+ WARN_ON(1);
+ }
+ if (atomic_dec_and_test(&de->count))
+ free_proc_entry(de);
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 82b3a1b..6f4e8dc 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -25,8 +25,7 @@
struct proc_dir_entry *de_get(struct proc_dir_entry *de)
{
- if (de)
- atomic_inc(&de->count);
+ atomic_inc(&de->count);
return de;
}
@@ -35,18 +34,16 @@
*/
void de_put(struct proc_dir_entry *de)
{
- if (de) {
- lock_kernel();
- if (!atomic_read(&de->count)) {
- printk("de_put: entry %s already free!\n", de->name);
- unlock_kernel();
- return;
- }
-
- if (atomic_dec_and_test(&de->count))
- free_proc_entry(de);
+ lock_kernel();
+ if (!atomic_read(&de->count)) {
+ printk("de_put: entry %s already free!\n", de->name);
unlock_kernel();
+ return;
}
+
+ if (atomic_dec_and_test(&de->count))
+ free_proc_entry(de);
+ unlock_kernel();
}
/*
@@ -392,7 +389,7 @@
{
struct inode * inode;
- if (de != NULL && !try_module_get(de->owner))
+ if (!try_module_get(de->owner))
goto out_mod;
inode = iget_locked(sb, ino);
@@ -402,30 +399,29 @@
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
PROC_I(inode)->fd = 0;
PROC_I(inode)->pde = de;
- if (de) {
- if (de->mode) {
- inode->i_mode = de->mode;
- inode->i_uid = de->uid;
- inode->i_gid = de->gid;
- }
- if (de->size)
- inode->i_size = de->size;
- if (de->nlink)
- inode->i_nlink = de->nlink;
- if (de->proc_iops)
- inode->i_op = de->proc_iops;
- if (de->proc_fops) {
- if (S_ISREG(inode->i_mode)) {
+
+ if (de->mode) {
+ inode->i_mode = de->mode;
+ inode->i_uid = de->uid;
+ inode->i_gid = de->gid;
+ }
+ if (de->size)
+ inode->i_size = de->size;
+ if (de->nlink)
+ inode->i_nlink = de->nlink;
+ if (de->proc_iops)
+ inode->i_op = de->proc_iops;
+ if (de->proc_fops) {
+ if (S_ISREG(inode->i_mode)) {
#ifdef CONFIG_COMPAT
- if (!de->proc_fops->compat_ioctl)
- inode->i_fop =
- &proc_reg_file_ops_no_compat;
- else
+ if (!de->proc_fops->compat_ioctl)
+ inode->i_fop =
+ &proc_reg_file_ops_no_compat;
+ else
#endif
- inode->i_fop = &proc_reg_file_ops;
- } else {
- inode->i_fop = de->proc_fops;
- }
+ inode->i_fop = &proc_reg_file_ops;
+ } else {
+ inode->i_fop = de->proc_fops;
}
}
unlock_new_inode(inode);
@@ -433,8 +429,7 @@
return inode;
out_ino:
- if (de != NULL)
- module_put(de->owner);
+ module_put(de->owner);
out_mod:
return NULL;
}
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index bc72f5c..28cbca8 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -11,6 +11,7 @@
#include <linux/proc_fs.h>
+extern struct proc_dir_entry proc_root;
#ifdef CONFIG_PROC_SYSCTL
extern int proc_sys_init(void);
#else
@@ -46,9 +47,6 @@
extern int maps_protect;
-extern void create_seq_entry(char *name, mode_t mode,
- const struct file_operations *f);
-extern int proc_exe_link(struct inode *, struct path *);
extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task);
extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
index 941e951..79ecd28 100644
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -137,7 +137,7 @@
static int __init proc_nommu_init(void)
{
- create_seq_entry("maps", S_IRUGO, &proc_nommu_vma_list_operations);
+ proc_create("maps", S_IRUGO, NULL, &proc_nommu_vma_list_operations);
return 0;
}
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 441a32f..74a323d 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -179,6 +179,7 @@
"PageTables: %8lu kB\n"
"NFS_Unstable: %8lu kB\n"
"Bounce: %8lu kB\n"
+ "WritebackTmp: %8lu kB\n"
"CommitLimit: %8lu kB\n"
"Committed_AS: %8lu kB\n"
"VmallocTotal: %8lu kB\n"
@@ -210,6 +211,7 @@
K(global_page_state(NR_PAGETABLE)),
K(global_page_state(NR_UNSTABLE_NFS)),
K(global_page_state(NR_BOUNCE)),
+ K(global_page_state(NR_WRITEBACK_TEMP)),
K(allowed),
K(committed),
(unsigned long)VMALLOC_TOTAL >> 10,
@@ -826,14 +828,6 @@
struct proc_dir_entry *proc_root_kcore;
-void create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
-{
- struct proc_dir_entry *entry;
- entry = create_proc_entry(name, mode, NULL);
- if (entry)
- entry->proc_fops = f;
-}
-
void __init proc_misc_init(void)
{
static struct {
@@ -862,66 +856,52 @@
/* And now for trickier ones */
#ifdef CONFIG_PRINTK
- {
- struct proc_dir_entry *entry;
- entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
- if (entry)
- entry->proc_fops = &proc_kmsg_operations;
- }
+ proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations);
#endif
- create_seq_entry("locks", 0, &proc_locks_operations);
- create_seq_entry("devices", 0, &proc_devinfo_operations);
- create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
+ proc_create("locks", 0, NULL, &proc_locks_operations);
+ proc_create("devices", 0, NULL, &proc_devinfo_operations);
+ proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
#ifdef CONFIG_BLOCK
- create_seq_entry("partitions", 0, &proc_partitions_operations);
+ proc_create("partitions", 0, NULL, &proc_partitions_operations);
#endif
- create_seq_entry("stat", 0, &proc_stat_operations);
- create_seq_entry("interrupts", 0, &proc_interrupts_operations);
+ proc_create("stat", 0, NULL, &proc_stat_operations);
+ proc_create("interrupts", 0, NULL, &proc_interrupts_operations);
#ifdef CONFIG_SLABINFO
- create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
+ proc_create("slabinfo",S_IWUSR|S_IRUGO,NULL,&proc_slabinfo_operations);
#ifdef CONFIG_DEBUG_SLAB_LEAK
- create_seq_entry("slab_allocators", 0 ,&proc_slabstats_operations);
+ proc_create("slab_allocators", 0, NULL, &proc_slabstats_operations);
#endif
#endif
#ifdef CONFIG_MMU
proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations);
#endif
- create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
- create_seq_entry("pagetypeinfo", S_IRUGO, &pagetypeinfo_file_ops);
- create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
- create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations);
+ proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
+ proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
+ proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations);
+ proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
#ifdef CONFIG_BLOCK
- create_seq_entry("diskstats", 0, &proc_diskstats_operations);
+ proc_create("diskstats", 0, NULL, &proc_diskstats_operations);
#endif
#ifdef CONFIG_MODULES
- create_seq_entry("modules", 0, &proc_modules_operations);
+ proc_create("modules", 0, NULL, &proc_modules_operations);
#endif
#ifdef CONFIG_SCHEDSTATS
- create_seq_entry("schedstat", 0, &proc_schedstat_operations);
+ proc_create("schedstat", 0, NULL, &proc_schedstat_operations);
#endif
#ifdef CONFIG_PROC_KCORE
- proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
- if (proc_root_kcore) {
- proc_root_kcore->proc_fops = &proc_kcore_operations;
+ proc_root_kcore = proc_create("kcore", S_IRUSR, NULL, &proc_kcore_operations);
+ if (proc_root_kcore)
proc_root_kcore->size =
(size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
- }
#endif
#ifdef CONFIG_PROC_PAGE_MONITOR
- create_seq_entry("kpagecount", S_IRUSR, &proc_kpagecount_operations);
- create_seq_entry("kpageflags", S_IRUSR, &proc_kpageflags_operations);
+ proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations);
+ proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations);
#endif
#ifdef CONFIG_PROC_VMCORE
- proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL);
- if (proc_vmcore)
- proc_vmcore->proc_fops = &proc_vmcore_operations;
+ proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations);
#endif
#ifdef CONFIG_MAGIC_SYSRQ
- {
- struct proc_dir_entry *entry;
- entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL);
- if (entry)
- entry->proc_fops = &proc_sysrq_trigger_operations;
- }
+ proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations);
#endif
}
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 614c34b..5acc001 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -165,8 +165,8 @@
return err;
}
-static ssize_t proc_sys_read(struct file *filp, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
+ size_t count, loff_t *ppos, int write)
{
struct dentry *dentry = filp->f_dentry;
struct ctl_table_header *head;
@@ -190,12 +190,12 @@
* and won't be until we finish.
*/
error = -EPERM;
- if (sysctl_perm(table, MAY_READ))
+ if (sysctl_perm(head->root, table, write ? MAY_WRITE : MAY_READ))
goto out;
/* careful: calling conventions are nasty here */
res = count;
- error = table->proc_handler(table, 0, filp, buf, &res, ppos);
+ error = table->proc_handler(table, write, filp, buf, &res, ppos);
if (!error)
error = res;
out:
@@ -204,44 +204,16 @@
return error;
}
+static ssize_t proc_sys_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0);
+}
+
static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
- struct dentry *dentry = filp->f_dentry;
- struct ctl_table_header *head;
- struct ctl_table *table;
- ssize_t error;
- size_t res;
-
- table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
- /* Has the sysctl entry disappeared on us? */
- error = -ENOENT;
- if (!table)
- goto out;
-
- /* Has the sysctl entry been replaced by a directory? */
- error = -EISDIR;
- if (!table->proc_handler)
- goto out;
-
- /*
- * At this point we know that the sysctl was not unregistered
- * and won't be until we finish.
- */
- error = -EPERM;
- if (sysctl_perm(table, MAY_WRITE))
- goto out;
-
- /* careful: calling conventions are nasty here */
- res = count;
- error = table->proc_handler(table, 1, filp, (char __user *)buf,
- &res, ppos);
- if (!error)
- error = res;
-out:
- sysctl_head_finish(head);
-
- return error;
+ return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1);
}
@@ -416,7 +388,7 @@
goto out;
/* Use the permissions on the sysctl table entry */
- error = sysctl_perm(table, mask);
+ error = sysctl_perm(head->root, table, mask);
out:
sysctl_head_finish(head);
return error;
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index 49816e0..21f490f 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -5,7 +5,7 @@
*/
#include <asm/uaccess.h>
-
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/time.h>
@@ -136,39 +136,54 @@
.release = seq_release,
};
-/*
- * This is the handler for /proc/tty/ldiscs
- */
-static int tty_ldiscs_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
{
- int i;
- int len = 0;
- off_t begin = 0;
+ return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
+{
+ int i = *(loff_t *)v;
struct tty_ldisc *ld;
- for (i=0; i < NR_LDISCS; i++) {
- ld = tty_ldisc_get(i);
- if (ld == NULL)
- continue;
- len += sprintf(page+len, "%-10s %2d\n",
- ld->name ? ld->name : "???", i);
- tty_ldisc_put(i);
- if (len+begin > off+count)
- break;
- if (len+begin < off) {
- begin += len;
- len = 0;
- }
- }
- if (i >= NR_LDISCS)
- *eof = 1;
- if (off >= len+begin)
+ ld = tty_ldisc_get(i);
+ if (ld == NULL)
return 0;
- *start = page + (off-begin);
- return ((count < begin+len-off) ? count : begin+len-off);
+ seq_printf(m, "%-10s %2d\n", ld->name ? ld->name : "???", i);
+ tty_ldisc_put(i);
+ return 0;
}
+static const struct seq_operations tty_ldiscs_seq_ops = {
+ .start = tty_ldiscs_seq_start,
+ .next = tty_ldiscs_seq_next,
+ .stop = tty_ldiscs_seq_stop,
+ .show = tty_ldiscs_seq_show,
+};
+
+static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &tty_ldiscs_seq_ops);
+}
+
+static const struct file_operations tty_ldiscs_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_tty_ldiscs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
/*
* This function is called by tty_register_driver() to handle
* registering the driver's /proc handler into /proc/tty/driver/<foo>
@@ -177,16 +192,14 @@
{
struct proc_dir_entry *ent;
- if ((!driver->read_proc && !driver->write_proc) ||
- !driver->driver_name ||
+ if (!driver->ops->read_proc || !driver->driver_name ||
driver->proc_entry)
return;
ent = create_proc_entry(driver->driver_name, 0, proc_tty_driver);
if (!ent)
return;
- ent->read_proc = driver->read_proc;
- ent->write_proc = driver->write_proc;
+ ent->read_proc = driver->ops->read_proc;
ent->owner = driver->owner;
ent->data = driver;
@@ -214,7 +227,6 @@
*/
void __init proc_tty_init(void)
{
- struct proc_dir_entry *entry;
if (!proc_mkdir("tty", NULL))
return;
proc_tty_ldisc = proc_mkdir("tty/ldisc", NULL);
@@ -224,10 +236,7 @@
* password lengths and inter-keystroke timings during password
* entry.
*/
- proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR | S_IXUSR, NULL);
-
- create_proc_read_entry("tty/ldiscs", 0, NULL, tty_ldiscs_read_proc, NULL);
- entry = create_proc_entry("tty/drivers", 0, NULL);
- if (entry)
- entry->proc_fops = &proc_tty_drivers_operations;
+ proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
+ proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops);
+ proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations);
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index ef0fb57..9511753 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -22,8 +22,6 @@
#include "internal.h"
-struct proc_dir_entry *proc_bus, *proc_root_fs, *proc_root_driver;
-
static int proc_test_super(struct super_block *sb, void *data)
{
return sb->s_fs_info == data;
@@ -126,8 +124,8 @@
#ifdef CONFIG_SYSVIPC
proc_mkdir("sysvipc", NULL);
#endif
- proc_root_fs = proc_mkdir("fs", NULL);
- proc_root_driver = proc_mkdir("driver", NULL);
+ proc_mkdir("fs", NULL);
+ proc_mkdir("driver", NULL);
proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
/* just give it a mountpoint */
@@ -137,7 +135,7 @@
#ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init();
#endif
- proc_bus = proc_mkdir("bus", NULL);
+ proc_mkdir("bus", NULL);
proc_sys_init();
}
@@ -232,9 +230,5 @@
EXPORT_SYMBOL(proc_symlink);
EXPORT_SYMBOL(proc_mkdir);
EXPORT_SYMBOL(create_proc_entry);
-EXPORT_SYMBOL(proc_create);
+EXPORT_SYMBOL(proc_create_data);
EXPORT_SYMBOL(remove_proc_entry);
-EXPORT_SYMBOL(proc_root);
-EXPORT_SYMBOL(proc_root_fs);
-EXPORT_SYMBOL(proc_bus);
-EXPORT_SYMBOL(proc_root_driver);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7415eeb..e2b8e76 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -75,40 +75,6 @@
return mm->total_vm;
}
-int proc_exe_link(struct inode *inode, struct path *path)
-{
- struct vm_area_struct * vma;
- int result = -ENOENT;
- struct task_struct *task = get_proc_task(inode);
- struct mm_struct * mm = NULL;
-
- if (task) {
- mm = get_task_mm(task);
- put_task_struct(task);
- }
- if (!mm)
- goto out;
- down_read(&mm->mmap_sem);
-
- vma = mm->mmap;
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
- break;
- vma = vma->vm_next;
- }
-
- if (vma) {
- *path = vma->vm_file->f_path;
- path_get(&vma->vm_file->f_path);
- result = 0;
- }
-
- up_read(&mm->mmap_sem);
- mmput(mm);
-out:
- return result;
-}
-
static void pad_len_spaces(struct seq_file *m, int len)
{
len = 25 + sizeof(void*) * 6 - len;
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 8011528..4b733f1 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -103,40 +103,6 @@
return size;
}
-int proc_exe_link(struct inode *inode, struct path *path)
-{
- struct vm_list_struct *vml;
- struct vm_area_struct *vma;
- struct task_struct *task = get_proc_task(inode);
- struct mm_struct *mm = get_task_mm(task);
- int result = -ENOENT;
-
- if (!mm)
- goto out;
- down_read(&mm->mmap_sem);
-
- vml = mm->context.vmlist;
- vma = NULL;
- while (vml) {
- if ((vml->vma->vm_flags & VM_EXECUTABLE) && vml->vma->vm_file) {
- vma = vml->vma;
- break;
- }
- vml = vml->next;
- }
-
- if (vma) {
- *path = vma->vm_file->f_path;
- path_get(&vma->vm_file->f_path);
- result = 0;
- }
-
- up_read(&mm->mmap_sem);
- mmput(mm);
-out:
- return result;
-}
-
/*
* display mapping lines for a particular process's /proc/pid/maps
*/
diff --git a/fs/quota_v2.c b/fs/quota_v2.c
index 23b647f..234ada9 100644
--- a/fs/quota_v2.c
+++ b/fs/quota_v2.c
@@ -306,7 +306,7 @@
printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
goto out_buf;
}
- dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
+ le16_add_cpu(&dh->dqdh_entries, 1);
memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
/* Find free structure in block */
for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
@@ -448,7 +448,7 @@
goto out_buf;
}
dh = (struct v2_disk_dqdbheader *)buf;
- dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
+ le16_add_cpu(&dh->dqdh_entries, -1);
if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
(ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
index b41a514..9590b90 100644
--- a/fs/ramfs/file-mmu.c
+++ b/fs/ramfs/file-mmu.c
@@ -26,6 +26,9 @@
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/ramfs.h>
+
+#include "internal.h"
const struct address_space_operations ramfs_aops = {
.readpage = simple_readpage,
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index 8428d5b..b131234 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -44,7 +44,7 @@
static struct backing_dev_info ramfs_backing_dev_info = {
.ra_pages = 0, /* No readahead */
- .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK |
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK |
BDI_CAP_MAP_DIRECT | BDI_CAP_MAP_COPY |
BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP,
};
diff --git a/fs/ramfs/internal.h b/fs/ramfs/internal.h
index af7cc07..6b33063 100644
--- a/fs/ramfs/internal.h
+++ b/fs/ramfs/internal.h
@@ -11,5 +11,4 @@
extern const struct address_space_operations ramfs_aops;
-extern const struct file_operations ramfs_file_operations;
extern const struct inode_operations ramfs_file_inode_operations;
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index da86042..e396b2f 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -2574,11 +2574,9 @@
result = 0;
- if (journal->j_dev_file != NULL) {
- result = filp_close(journal->j_dev_file, NULL);
- journal->j_dev_file = NULL;
- journal->j_dev_bd = NULL;
- } else if (journal->j_dev_bd != NULL) {
+ if (journal->j_dev_bd != NULL) {
+ if (journal->j_dev_bd->bd_dev != super->s_dev)
+ bd_release(journal->j_dev_bd);
result = blkdev_put(journal->j_dev_bd);
journal->j_dev_bd = NULL;
}
@@ -2603,7 +2601,6 @@
result = 0;
journal->j_dev_bd = NULL;
- journal->j_dev_file = NULL;
jdev = SB_ONDISK_JOURNAL_DEVICE(super) ?
new_decode_dev(SB_ONDISK_JOURNAL_DEVICE(super)) : super->s_dev;
@@ -2620,35 +2617,34 @@
"cannot init journal device '%s': %i",
__bdevname(jdev, b), result);
return result;
- } else if (jdev != super->s_dev)
+ } else if (jdev != super->s_dev) {
+ result = bd_claim(journal->j_dev_bd, journal);
+ if (result) {
+ blkdev_put(journal->j_dev_bd);
+ return result;
+ }
+
set_blocksize(journal->j_dev_bd, super->s_blocksize);
+ }
+
return 0;
}
- journal->j_dev_file = filp_open(jdev_name, 0, 0);
- if (!IS_ERR(journal->j_dev_file)) {
- struct inode *jdev_inode = journal->j_dev_file->f_mapping->host;
- if (!S_ISBLK(jdev_inode->i_mode)) {
- reiserfs_warning(super, "journal_init_dev: '%s' is "
- "not a block device", jdev_name);
- result = -ENOTBLK;
- release_journal_dev(super, journal);
- } else {
- /* ok */
- journal->j_dev_bd = I_BDEV(jdev_inode);
- set_blocksize(journal->j_dev_bd, super->s_blocksize);
- reiserfs_info(super,
- "journal_init_dev: journal device: %s\n",
- bdevname(journal->j_dev_bd, b));
- }
- } else {
- result = PTR_ERR(journal->j_dev_file);
- journal->j_dev_file = NULL;
+ journal->j_dev_bd = open_bdev_excl(jdev_name, 0, journal);
+ if (IS_ERR(journal->j_dev_bd)) {
+ result = PTR_ERR(journal->j_dev_bd);
+ journal->j_dev_bd = NULL;
reiserfs_warning(super,
"journal_init_dev: Cannot open '%s': %i",
jdev_name, result);
+ return result;
}
- return result;
+
+ set_blocksize(journal->j_dev_bd, super->s_blocksize);
+ reiserfs_info(super,
+ "journal_init_dev: journal device: %s\n",
+ bdevname(journal->j_dev_bd, b));
+ return 0;
}
/**
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index 8f86c52..b9dbeec 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -467,6 +467,7 @@
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
static struct proc_dir_entry *proc_info_root = NULL;
@@ -475,12 +476,8 @@
static void add_file(struct super_block *sb, char *name,
int (*func) (struct seq_file *, struct super_block *))
{
- struct proc_dir_entry *de;
- de = create_proc_entry(name, 0, REISERFS_SB(sb)->procdir);
- if (de) {
- de->data = func;
- de->proc_fops = &r_file_operations;
- }
+ proc_create_data(name, 0, REISERFS_SB(sb)->procdir,
+ &r_file_operations, func);
}
int reiserfs_proc_info_init(struct super_block *sb)
diff --git a/fs/select.c b/fs/select.c
index 00f58c5..8dda969 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -21,6 +21,7 @@
#include <linux/poll.h>
#include <linux/personality.h> /* for STICKY_TIMEOUTS */
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/fs.h>
#include <linux/rcupdate.h>
@@ -298,7 +299,7 @@
#define MAX_SELECT_SECONDS \
((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1)
-static int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
fd_set __user *exp, s64 *timeout)
{
fd_set_bits fds;
@@ -425,7 +426,7 @@
return ret;
}
-#ifdef TIF_RESTORE_SIGMASK
+#ifdef HAVE_SET_RESTORE_SIGMASK
asmlinkage long sys_pselect7(int n, fd_set __user *inp, fd_set __user *outp,
fd_set __user *exp, struct timespec __user *tsp,
const sigset_t __user *sigmask, size_t sigsetsize)
@@ -498,7 +499,7 @@
if (sigmask) {
memcpy(¤t->saved_sigmask, &sigsaved,
sizeof(sigsaved));
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
}
} else if (sigmask)
sigprocmask(SIG_SETMASK, &sigsaved, NULL);
@@ -528,7 +529,7 @@
return sys_pselect7(n, inp, outp, exp, tsp, up, sigsetsize);
}
-#endif /* TIF_RESTORE_SIGMASK */
+#endif /* HAVE_SET_RESTORE_SIGMASK */
struct poll_list {
struct poll_list *next;
@@ -759,7 +760,7 @@
return ret;
}
-#ifdef TIF_RESTORE_SIGMASK
+#ifdef HAVE_SET_RESTORE_SIGMASK
asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds,
struct timespec __user *tsp, const sigset_t __user *sigmask,
size_t sigsetsize)
@@ -805,7 +806,7 @@
if (sigmask) {
memcpy(¤t->saved_sigmask, &sigsaved,
sizeof(sigsaved));
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
}
ret = -ERESTARTNOHAND;
} else if (sigmask)
@@ -839,4 +840,4 @@
return ret;
}
-#endif /* TIF_RESTORE_SIGMASK */
+#endif /* HAVE_SET_RESTORE_SIGMASK */
diff --git a/fs/signalfd.c b/fs/signalfd.c
index 8ead0db..6197256 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -207,11 +207,8 @@
asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask)
{
- int error;
sigset_t sigmask;
struct signalfd_ctx *ctx;
- struct file *file;
- struct inode *inode;
if (sizemask != sizeof(sigset_t) ||
copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
@@ -230,12 +227,11 @@
* When we call this, the initialization must be complete, since
* anon_inode_getfd() will install the fd.
*/
- error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]",
- &signalfd_fops, ctx);
- if (error)
- goto err_fdalloc;
+ ufd = anon_inode_getfd("[signalfd]", &signalfd_fops, ctx);
+ if (ufd < 0)
+ kfree(ctx);
} else {
- file = fget(ufd);
+ struct file *file = fget(ufd);
if (!file)
return -EBADF;
ctx = file->private_data;
@@ -252,9 +248,4 @@
}
return ufd;
-
-err_fdalloc:
- kfree(ctx);
- return error;
}
-
diff --git a/fs/smbfs/smb_debug.h b/fs/smbfs/smb_debug.h
index 734972b..fc4b1a5 100644
--- a/fs/smbfs/smb_debug.h
+++ b/fs/smbfs/smb_debug.h
@@ -11,14 +11,14 @@
* these are normally enabled.
*/
#ifdef SMBFS_PARANOIA
-# define PARANOIA(f, a...) printk(KERN_NOTICE "%s: " f, __FUNCTION__ , ## a)
+# define PARANOIA(f, a...) printk(KERN_NOTICE "%s: " f, __func__ , ## a)
#else
# define PARANOIA(f, a...) do { ; } while(0)
#endif
/* lots of debug messages */
#ifdef SMBFS_DEBUG_VERBOSE
-# define VERBOSE(f, a...) printk(KERN_DEBUG "%s: " f, __FUNCTION__ , ## a)
+# define VERBOSE(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
#else
# define VERBOSE(f, a...) do { ; } while(0)
#endif
@@ -28,7 +28,7 @@
* too common name.
*/
#ifdef SMBFS_DEBUG
-#define DEBUG1(f, a...) printk(KERN_DEBUG "%s: " f, __FUNCTION__ , ## a)
+#define DEBUG1(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a)
#else
#define DEBUG1(f, a...) do { ; } while(0)
#endif
diff --git a/fs/splice.c b/fs/splice.c
index eeb1a86..633f58e 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -1075,7 +1075,7 @@
ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
if (ret > 0)
- *ppos += ret;
+ *ppos = sd.pos;
return ret;
}
diff --git a/fs/super.c b/fs/super.c
index a5a4aca..453877c 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -117,7 +117,7 @@
* Drop a superblock's refcount. Returns non-zero if the superblock was
* destroyed. The caller must hold sb_lock.
*/
-int __put_super(struct super_block *sb)
+static int __put_super(struct super_block *sb)
{
int ret = 0;
diff --git a/fs/sync.c b/fs/sync.c
index 7cd005ea..228e17b 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -64,7 +64,7 @@
/* sync the superblock to buffers */
sb = inode->i_sb;
lock_super(sb);
- if (sb->s_op->write_super)
+ if (sb->s_dirt && sb->s_op->write_super)
sb->s_op->write_super(sb);
unlock_super(sb);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index dbdfabb..e7735f6 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -135,7 +135,7 @@
goto out;
}
pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
- __FUNCTION__, count, *ppos, buffer->page);
+ __func__, count, *ppos, buffer->page);
retval = simple_read_from_buffer(buf, count, ppos, buffer->page,
buffer->count);
out:
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index d9262f7..eb53c63 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -30,7 +30,7 @@
static struct backing_dev_info sysfs_backing_dev_info = {
.ra_pages = 0, /* No readahead */
- .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
static const struct inode_operations sysfs_inode_operations ={
@@ -59,6 +59,8 @@
if (error)
return error;
+ iattr->ia_valid &= ~ATTR_SIZE; /* ignore size changes */
+
error = inode_setattr(inode, iattr);
if (error)
return error;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 7416826..14f0023 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -61,7 +61,7 @@
/* instantiate and link root dentry */
root = d_alloc_root(inode);
if (!root) {
- pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
+ pr_debug("%s: could not get root dentry!\n",__func__);
iput(inode);
return -ENOMEM;
}
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h
index 42d51d1..38ebe3f 100644
--- a/fs/sysv/sysv.h
+++ b/fs/sysv/sysv.h
@@ -217,9 +217,9 @@
if (sbi->s_bytesex == BYTESEX_PDP)
*(__u32*)n = PDP_swab(PDP_swab(*(__u32*)n)+d);
else if (sbi->s_bytesex == BYTESEX_LE)
- *(__le32*)n = cpu_to_le32(le32_to_cpu(*(__le32*)n)+d);
+ le32_add_cpu((__le32 *)n, d);
else
- *(__be32*)n = cpu_to_be32(be32_to_cpu(*(__be32*)n)+d);
+ be32_add_cpu((__be32 *)n, d);
return *n;
}
@@ -242,9 +242,9 @@
static inline __fs16 fs16_add(struct sysv_sb_info *sbi, __fs16 *n, int d)
{
if (sbi->s_bytesex != BYTESEX_BE)
- *(__le16*)n = cpu_to_le16(le16_to_cpu(*(__le16 *)n)+d);
+ le16_add_cpu((__le16 *)n, d);
else
- *(__be16*)n = cpu_to_be16(be16_to_cpu(*(__be16 *)n)+d);
+ be16_add_cpu((__be16 *)n, d);
return *n;
}
diff --git a/fs/timerfd.c b/fs/timerfd.c
index 10c80b5..d87d354 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -20,6 +20,7 @@
#include <linux/hrtimer.h>
#include <linux/anon_inodes.h>
#include <linux/timerfd.h>
+#include <linux/syscalls.h>
struct timerfd_ctx {
struct hrtimer tmr;
@@ -180,10 +181,8 @@
asmlinkage long sys_timerfd_create(int clockid, int flags)
{
- int error, ufd;
+ int ufd;
struct timerfd_ctx *ctx;
- struct file *file;
- struct inode *inode;
if (flags)
return -EINVAL;
@@ -199,12 +198,9 @@
ctx->clockid = clockid;
hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
- error = anon_inode_getfd(&ufd, &inode, &file, "[timerfd]",
- &timerfd_fops, ctx);
- if (error) {
+ ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx);
+ if (ufd < 0)
kfree(ctx);
- return error;
- }
return ufd;
}
diff --git a/fs/udf/super.c b/fs/udf/super.c
index b564fc1..9fb18a3 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -240,7 +240,7 @@
sbi->s_partmaps = kcalloc(count, sizeof(struct udf_part_map),
GFP_KERNEL);
if (!sbi->s_partmaps) {
- udf_error(sb, __FUNCTION__,
+ udf_error(sb, __func__,
"Unable to allocate space for %d partition maps",
count);
sbi->s_partitions = 0;
@@ -1086,7 +1086,7 @@
bitmap = vmalloc(size); /* TODO: get rid of vmalloc */
if (bitmap == NULL) {
- udf_error(sb, __FUNCTION__,
+ udf_error(sb, __func__,
"Unable to allocate space for bitmap "
"and %d buffer_head pointers", nr_groups);
return NULL;
diff --git a/fs/utimes.c b/fs/utimes.c
index a2bef77..af059d5 100644
--- a/fs/utimes.c
+++ b/fs/utimes.c
@@ -40,9 +40,14 @@
#endif
+static bool nsec_special(long nsec)
+{
+ return nsec == UTIME_OMIT || nsec == UTIME_NOW;
+}
+
static bool nsec_valid(long nsec)
{
- if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
+ if (nsec_special(nsec))
return true;
return nsec >= 0 && nsec <= 999999999;
@@ -119,7 +124,15 @@
newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
newattrs.ia_valid |= ATTR_MTIME_SET;
}
- } else {
+ }
+
+ /*
+ * If times is NULL or both times are either UTIME_OMIT or
+ * UTIME_NOW, then need to check permissions, because
+ * inode_change_ok() won't do it.
+ */
+ if (!times || (nsec_special(times[0].tv_nsec) &&
+ nsec_special(times[1].tv_nsec))) {
error = -EACCES;
if (IS_IMMUTABLE(inode))
goto mnt_drop_write_and_out;
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 5b66162..a352272 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -986,7 +986,7 @@
if (corrupt < 0) {
fat_fs_panic(new_dir->i_sb,
"%s: Filesystem corrupted (i_pos %lld)",
- __FUNCTION__, sinfo.i_pos);
+ __func__, sinfo.i_pos);
}
goto out;
}
diff --git a/fs/xattr.c b/fs/xattr.c
index 89a942f..4706a8b 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -67,7 +67,7 @@
}
int
-vfs_setxattr(struct dentry *dentry, char *name, void *value,
+vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags)
{
struct inode *inode = dentry->d_inode;
@@ -131,7 +131,7 @@
EXPORT_SYMBOL_GPL(xattr_getsecurity);
ssize_t
-vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
+vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -187,7 +187,7 @@
EXPORT_SYMBOL_GPL(vfs_listxattr);
int
-vfs_removexattr(struct dentry *dentry, char *name)
+vfs_removexattr(struct dentry *dentry, const char *name)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -218,7 +218,7 @@
* Extended attribute SET operations
*/
static long
-setxattr(struct dentry *d, char __user *name, void __user *value,
+setxattr(struct dentry *d, const char __user *name, const void __user *value,
size_t size, int flags)
{
int error;
@@ -252,8 +252,8 @@
}
asmlinkage long
-sys_setxattr(char __user *path, char __user *name, void __user *value,
- size_t size, int flags)
+sys_setxattr(const char __user *path, const char __user *name,
+ const void __user *value, size_t size, int flags)
{
struct nameidata nd;
int error;
@@ -271,8 +271,8 @@
}
asmlinkage long
-sys_lsetxattr(char __user *path, char __user *name, void __user *value,
- size_t size, int flags)
+sys_lsetxattr(const char __user *path, const char __user *name,
+ const void __user *value, size_t size, int flags)
{
struct nameidata nd;
int error;
@@ -290,7 +290,7 @@
}
asmlinkage long
-sys_fsetxattr(int fd, char __user *name, void __user *value,
+sys_fsetxattr(int fd, const char __user *name, const void __user *value,
size_t size, int flags)
{
struct file *f;
@@ -315,7 +315,8 @@
* Extended attribute GET operations
*/
static ssize_t
-getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
+getxattr(struct dentry *d, const char __user *name, void __user *value,
+ size_t size)
{
ssize_t error;
void *kvalue = NULL;
@@ -349,8 +350,8 @@
}
asmlinkage ssize_t
-sys_getxattr(char __user *path, char __user *name, void __user *value,
- size_t size)
+sys_getxattr(const char __user *path, const char __user *name,
+ void __user *value, size_t size)
{
struct nameidata nd;
ssize_t error;
@@ -364,7 +365,7 @@
}
asmlinkage ssize_t
-sys_lgetxattr(char __user *path, char __user *name, void __user *value,
+sys_lgetxattr(const char __user *path, const char __user *name, void __user *value,
size_t size)
{
struct nameidata nd;
@@ -379,7 +380,7 @@
}
asmlinkage ssize_t
-sys_fgetxattr(int fd, char __user *name, void __user *value, size_t size)
+sys_fgetxattr(int fd, const char __user *name, void __user *value, size_t size)
{
struct file *f;
ssize_t error = -EBADF;
@@ -424,7 +425,7 @@
}
asmlinkage ssize_t
-sys_listxattr(char __user *path, char __user *list, size_t size)
+sys_listxattr(const char __user *path, char __user *list, size_t size)
{
struct nameidata nd;
ssize_t error;
@@ -438,7 +439,7 @@
}
asmlinkage ssize_t
-sys_llistxattr(char __user *path, char __user *list, size_t size)
+sys_llistxattr(const char __user *path, char __user *list, size_t size)
{
struct nameidata nd;
ssize_t error;
@@ -470,7 +471,7 @@
* Extended attribute REMOVE operations
*/
static long
-removexattr(struct dentry *d, char __user *name)
+removexattr(struct dentry *d, const char __user *name)
{
int error;
char kname[XATTR_NAME_MAX + 1];
@@ -485,7 +486,7 @@
}
asmlinkage long
-sys_removexattr(char __user *path, char __user *name)
+sys_removexattr(const char __user *path, const char __user *name)
{
struct nameidata nd;
int error;
@@ -503,7 +504,7 @@
}
asmlinkage long
-sys_lremovexattr(char __user *path, char __user *name)
+sys_lremovexattr(const char __user *path, const char __user *name)
{
struct nameidata nd;
int error;
@@ -521,7 +522,7 @@
}
asmlinkage long
-sys_fremovexattr(int fd, char __user *name)
+sys_fremovexattr(int fd, const char __user *name)
{
struct file *f;
struct dentry *dentry;
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index 524021f..3f53dd1 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -64,3 +64,16 @@
See the xfs man page in section 5 for additional information.
If unsure, say N.
+
+config XFS_DEBUG
+ bool "XFS Debugging support (EXPERIMENTAL)"
+ depends on XFS_FS && EXPERIMENTAL
+ help
+ Say Y here to get an XFS build with many debugging features,
+ including ASSERT checks, function wrappers around macros,
+ and extra sanity-checking functions in various code paths.
+
+ Note that the resulting code will be HUGE and SLOW, and probably
+ not useful unless you are debugging a particular problem.
+
+ Say N unless you are an XFS developer, or you play one on TV.
diff --git a/fs/xfs/linux-2.6/mrlock.h b/fs/xfs/linux-2.6/mrlock.h
index c110bb0..ff6a198 100644
--- a/fs/xfs/linux-2.6/mrlock.h
+++ b/fs/xfs/linux-2.6/mrlock.h
@@ -20,29 +20,24 @@
#include <linux/rwsem.h>
-enum { MR_NONE, MR_ACCESS, MR_UPDATE };
-
typedef struct {
struct rw_semaphore mr_lock;
+#ifdef DEBUG
int mr_writer;
+#endif
} mrlock_t;
+#ifdef DEBUG
#define mrinit(mrp, name) \
do { (mrp)->mr_writer = 0; init_rwsem(&(mrp)->mr_lock); } while (0)
+#else
+#define mrinit(mrp, name) \
+ do { init_rwsem(&(mrp)->mr_lock); } while (0)
+#endif
+
#define mrlock_init(mrp, t,n,s) mrinit(mrp, n)
#define mrfree(mrp) do { } while (0)
-static inline void mraccess(mrlock_t *mrp)
-{
- down_read(&mrp->mr_lock);
-}
-
-static inline void mrupdate(mrlock_t *mrp)
-{
- down_write(&mrp->mr_lock);
- mrp->mr_writer = 1;
-}
-
static inline void mraccess_nested(mrlock_t *mrp, int subclass)
{
down_read_nested(&mrp->mr_lock, subclass);
@@ -51,10 +46,11 @@
static inline void mrupdate_nested(mrlock_t *mrp, int subclass)
{
down_write_nested(&mrp->mr_lock, subclass);
+#ifdef DEBUG
mrp->mr_writer = 1;
+#endif
}
-
static inline int mrtryaccess(mrlock_t *mrp)
{
return down_read_trylock(&mrp->mr_lock);
@@ -64,39 +60,31 @@
{
if (!down_write_trylock(&mrp->mr_lock))
return 0;
+#ifdef DEBUG
mrp->mr_writer = 1;
+#endif
return 1;
}
-static inline void mrunlock(mrlock_t *mrp)
+static inline void mrunlock_excl(mrlock_t *mrp)
{
- if (mrp->mr_writer) {
- mrp->mr_writer = 0;
- up_write(&mrp->mr_lock);
- } else {
- up_read(&mrp->mr_lock);
- }
+#ifdef DEBUG
+ mrp->mr_writer = 0;
+#endif
+ up_write(&mrp->mr_lock);
+}
+
+static inline void mrunlock_shared(mrlock_t *mrp)
+{
+ up_read(&mrp->mr_lock);
}
static inline void mrdemote(mrlock_t *mrp)
{
+#ifdef DEBUG
mrp->mr_writer = 0;
+#endif
downgrade_write(&mrp->mr_lock);
}
-#ifdef DEBUG
-/*
- * Debug-only routine, without some platform-specific asm code, we can
- * now only answer requests regarding whether we hold the lock for write
- * (reader state is outside our visibility, we only track writer state).
- * Note: means !ismrlocked would give false positives, so don't do that.
- */
-static inline int ismrlocked(mrlock_t *mrp, int type)
-{
- if (mrp && type == MR_UPDATE)
- return mrp->mr_writer;
- return 1;
-}
-#endif
-
#endif /* __XFS_SUPPORT_MRLOCK_H__ */
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 52f6846..5105015 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -886,7 +886,7 @@
xfs_buf_lock_value(
xfs_buf_t *bp)
{
- return atomic_read(&bp->b_sema.count);
+ return bp->b_sema.count;
}
#endif
diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index 265f016..c672b32 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -133,7 +133,7 @@
if (!ip)
return ERR_PTR(-EIO);
- if (!ip->i_d.di_mode || ip->i_d.di_gen != generation) {
+ if (ip->i_d.di_gen != generation) {
xfs_iput_new(ip, XFS_ILOCK_SHARED);
return ERR_PTR(-ENOENT);
}
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 0590524..65e78c1 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -43,9 +43,6 @@
#include <linux/smp_lock.h>
static struct vm_operations_struct xfs_file_vm_ops;
-#ifdef CONFIG_XFS_DMAPI
-static struct vm_operations_struct xfs_dmapi_file_vm_ops;
-#endif
STATIC_INLINE ssize_t
__xfs_file_read(
@@ -202,22 +199,6 @@
(xfs_off_t)0, (xfs_off_t)-1);
}
-#ifdef CONFIG_XFS_DMAPI
-STATIC int
-xfs_vm_fault(
- struct vm_area_struct *vma,
- struct vm_fault *vmf)
-{
- struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
- bhv_vnode_t *vp = vn_from_inode(inode);
-
- ASSERT_ALWAYS(vp->v_vfsp->vfs_flag & VFS_DMI);
- if (XFS_SEND_MMAP(XFS_VFSTOM(vp->v_vfsp), vma, 0))
- return VM_FAULT_SIGBUS;
- return filemap_fault(vma, vmf);
-}
-#endif /* CONFIG_XFS_DMAPI */
-
/*
* Unfortunately we can't just use the clean and simple readdir implementation
* below, because nfs might call back into ->lookup from the filldir callback
@@ -386,11 +367,6 @@
vma->vm_ops = &xfs_file_vm_ops;
vma->vm_flags |= VM_CAN_NONLINEAR;
-#ifdef CONFIG_XFS_DMAPI
- if (XFS_M(filp->f_path.dentry->d_inode->i_sb)->m_flags & XFS_MOUNT_DMAPI)
- vma->vm_ops = &xfs_dmapi_file_vm_ops;
-#endif /* CONFIG_XFS_DMAPI */
-
file_accessed(filp);
return 0;
}
@@ -437,47 +413,6 @@
return error;
}
-#ifdef CONFIG_XFS_DMAPI
-#ifdef HAVE_VMOP_MPROTECT
-STATIC int
-xfs_vm_mprotect(
- struct vm_area_struct *vma,
- unsigned int newflags)
-{
- struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
- struct xfs_mount *mp = XFS_M(inode->i_sb);
- int error = 0;
-
- if (mp->m_flags & XFS_MOUNT_DMAPI) {
- if ((vma->vm_flags & VM_MAYSHARE) &&
- (newflags & VM_WRITE) && !(vma->vm_flags & VM_WRITE))
- error = XFS_SEND_MMAP(mp, vma, VM_WRITE);
- }
- 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
- * we have to trigger a DMAPI READ event before the file is marked as busy
- * otherwise the invisible I/O will not be able to write to the file to bring
- * it back online.
- */
-STATIC int
-xfs_file_open_exec(
- struct inode *inode)
-{
- struct xfs_mount *mp = XFS_M(inode->i_sb);
- struct xfs_inode *ip = XFS_I(inode);
-
- if (unlikely(mp->m_flags & XFS_MOUNT_DMAPI) &&
- DM_EVENT_ENABLED(ip, DM_EVENT_READ))
- return -XFS_SEND_DATA(mp, DM_EVENT_READ, ip, 0, 0, 0, NULL);
- return 0;
-}
-#endif /* HAVE_FOP_OPEN_EXEC */
-
/*
* mmap()d file has taken write protection fault and is being made
* writable. We can set the page state up correctly for a writable
@@ -546,13 +481,3 @@
.fault = filemap_fault,
.page_mkwrite = xfs_vm_page_mkwrite,
};
-
-#ifdef CONFIG_XFS_DMAPI
-static struct vm_operations_struct xfs_dmapi_file_vm_ops = {
- .fault = xfs_vm_fault,
- .page_mkwrite = xfs_vm_page_mkwrite,
-#ifdef HAVE_VMOP_MPROTECT
- .mprotect = xfs_vm_mprotect,
-#endif
-};
-#endif /* CONFIG_XFS_DMAPI */
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 4ddb86b..a42ba9d 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -238,7 +238,7 @@
return error;
if (ip == NULL)
return XFS_ERROR(EIO);
- if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) {
+ if (ip->i_d.di_gen != igen) {
xfs_iput_new(ip, XFS_ILOCK_SHARED);
return XFS_ERROR(ENOENT);
}
@@ -505,14 +505,14 @@
{
char *kbuf;
int error = EFAULT;
-
+
if (*len > XATTR_SIZE_MAX)
return EINVAL;
kbuf = kmalloc(*len, GFP_KERNEL);
if (!kbuf)
return ENOMEM;
- error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags, NULL);
+ error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags);
if (error)
goto out_kfree;
@@ -546,7 +546,7 @@
if (copy_from_user(kbuf, ubuf, len))
goto out_kfree;
-
+
error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
out_kfree:
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index a1237da..2bf287e 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -511,7 +511,8 @@
xfs_dentry_to_name(&nname, ndentry);
error = xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode),
- XFS_I(ndir), &nname);
+ XFS_I(ndir), &nname, new_inode ?
+ XFS_I(new_inode) : NULL);
if (likely(!error)) {
if (new_inode)
xfs_validate_fields(new_inode);
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index e514332..4edc469 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -75,6 +75,7 @@
#include <linux/delay.h>
#include <linux/log2.h>
#include <linux/spinlock.h>
+#include <linux/random.h>
#include <asm/page.h>
#include <asm/div64.h>
@@ -99,7 +100,6 @@
/*
* Feature macros (disable/enable)
*/
-#define HAVE_SPLICE /* a splice(2) exists in 2.6, but not in 2.4 */
#ifdef CONFIG_SMP
#define HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */
#else
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index 1ebd800..5e3b575 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -394,7 +394,7 @@
int error = 0;
xfs_bmbt_irec_t imap;
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0);
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
zero_offset = XFS_B_FSB_OFFSET(mp, isize);
if (zero_offset == 0) {
@@ -425,14 +425,14 @@
* out sync. We need to drop the ilock while we do this so we
* don't deadlock when the buffer cache calls back to us.
*/
- xfs_iunlock(ip, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
zero_len = mp->m_sb.sb_blocksize - zero_offset;
if (isize + zero_len > offset)
zero_len = offset - isize;
error = xfs_iozero(ip, isize, zero_len);
- xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
ASSERT(error >= 0);
return error;
}
@@ -465,8 +465,7 @@
int error = 0;
xfs_bmbt_irec_t imap;
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
- ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
ASSERT(offset > isize);
/*
@@ -475,8 +474,7 @@
*/
error = xfs_zero_last_block(ip, offset, isize);
if (error) {
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
- ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
return error;
}
@@ -507,8 +505,7 @@
error = xfs_bmapi(NULL, ip, start_zero_fsb, zero_count_fsb,
0, NULL, 0, &imap, &nimaps, NULL, NULL);
if (error) {
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
- ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
return error;
}
ASSERT(nimaps > 0);
@@ -532,7 +529,7 @@
* Drop the inode lock while we're doing the I/O.
* We'll still have the iolock to protect us.
*/
- xfs_iunlock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+ xfs_iunlock(ip, XFS_ILOCK_EXCL);
zero_off = XFS_FSB_TO_B(mp, start_zero_fsb);
zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount);
@@ -548,13 +545,13 @@
start_zero_fsb = imap.br_startoff + imap.br_blockcount;
ASSERT(start_zero_fsb <= (end_zero_fsb + 1));
- xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
}
return 0;
out_lock:
- xfs_ilock(ip, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
+ xfs_ilock(ip, XFS_ILOCK_EXCL);
ASSERT(error >= 0);
return error;
}
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h
index e1d498b..e6be37d 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.h
+++ b/fs/xfs/linux-2.6/xfs_lrw.h
@@ -50,7 +50,6 @@
#define XFS_INVAL_CACHED 18
#define XFS_DIORD_ENTER 19
#define XFS_DIOWR_ENTER 20
-#define XFS_SENDFILE_ENTER 21
#define XFS_WRITEPAGE_ENTER 22
#define XFS_RELEASEPAGE_ENTER 23
#define XFS_INVALIDPAGE_ENTER 24
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 865eb70..742b2c7 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -1181,7 +1181,7 @@
statp->f_fsid.val[0] = (u32)id;
statp->f_fsid.val[1] = (u32)(id >> 32);
- xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT);
+ xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT);
spin_lock(&mp->m_sb_lock);
statp->f_bsize = sbp->sb_blocksize;
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index 8b4d63c..9d73cb5 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -25,12 +25,6 @@
typedef struct inode bhv_vnode_t;
-#define VN_ISLNK(vp) S_ISLNK((vp)->i_mode)
-#define VN_ISREG(vp) S_ISREG((vp)->i_mode)
-#define VN_ISDIR(vp) S_ISDIR((vp)->i_mode)
-#define VN_ISCHR(vp) S_ISCHR((vp)->i_mode)
-#define VN_ISBLK(vp) S_ISBLK((vp)->i_mode)
-
/*
* Vnode to Linux inode mapping.
*/
@@ -151,24 +145,6 @@
XFS_AT_TYPE|XFS_AT_BLKSIZE|XFS_AT_NBLOCKS|XFS_AT_VCODE|\
XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|XFS_AT_GENCOUNT)
-/*
- * Modes.
- */
-#define VSUID S_ISUID /* set user id on execution */
-#define VSGID S_ISGID /* set group id on execution */
-#define VSVTX S_ISVTX /* save swapped text even after use */
-#define VREAD S_IRUSR /* read, write, execute permissions */
-#define VWRITE S_IWUSR
-#define VEXEC S_IXUSR
-
-#define MODEMASK S_IALLUGO /* mode bits plus permission bits */
-
-/*
- * Check whether mandatory file locking is enabled.
- */
-#define MANDLOCK(vp, mode) \
- (VN_ISREG(vp) && ((mode) & (VSGID|(VEXEC>>3))) == VSGID)
-
extern void vn_init(void);
extern int vn_revalidate(bhv_vnode_t *);
diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c
index 631ebb3..85df328 100644
--- a/fs/xfs/quota/xfs_dquot.c
+++ b/fs/xfs/quota/xfs_dquot.c
@@ -933,7 +933,7 @@
type == XFS_DQ_PROJ ||
type == XFS_DQ_GROUP);
if (ip) {
- ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (type == XFS_DQ_USER)
ASSERT(ip->i_udquot == NULL);
else
@@ -1088,7 +1088,7 @@
xfs_qm_mplist_unlock(mp);
XFS_DQ_HASH_UNLOCK(h);
dqret:
- ASSERT((ip == NULL) || XFS_ISLOCKED_INODE_EXCL(ip));
+ ASSERT((ip == NULL) || xfs_isilocked(ip, XFS_ILOCK_EXCL));
xfs_dqtrace_entry(dqp, "DQGET DONE");
*O_dqpp = dqp;
return (0);
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 40ea564..d31cce1 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -670,7 +670,7 @@
xfs_dquot_t *dqp;
int error;
- ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
error = 0;
/*
* See if we already have it in the inode itself. IO_idqpp is
@@ -874,7 +874,7 @@
return 0;
ASSERT((flags & XFS_QMOPT_ILOCKED) == 0 ||
- XFS_ISLOCKED_INODE_EXCL(ip));
+ xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (! (flags & XFS_QMOPT_ILOCKED))
xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -888,7 +888,8 @@
goto done;
nquotas++;
}
- ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
if (XFS_IS_OQUOTA_ON(mp)) {
error = XFS_IS_GQUOTA_ON(mp) ?
xfs_qm_dqattach_one(ip, ip->i_d.di_gid, XFS_DQ_GROUP,
@@ -913,7 +914,7 @@
* This WON'T, in general, result in a thrash.
*/
if (nquotas == 2) {
- ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(ip->i_udquot);
ASSERT(ip->i_gdquot);
@@ -956,7 +957,7 @@
#ifdef QUOTADEBUG
else
- ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
#endif
return error;
}
@@ -1291,7 +1292,7 @@
xfs_mount_t *mp;
xfs_dquot_t *udqp, *gdqp;
- ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
mp = ip->i_mount;
udqp = NULL;
gdqp = NULL;
@@ -1392,7 +1393,7 @@
* Keep an extra reference to this quota inode. This inode is
* locked exclusively and joined to the transaction already.
*/
- ASSERT(XFS_ISLOCKED_INODE_EXCL(*ip));
+ ASSERT(xfs_isilocked(*ip, XFS_ILOCK_EXCL));
VN_HOLD(XFS_ITOV((*ip)));
/*
@@ -1737,12 +1738,6 @@
return error;
}
- if (ip->i_d.di_mode == 0) {
- xfs_iput_new(ip, XFS_ILOCK_EXCL);
- *res = BULKSTAT_RV_NOTHING;
- return XFS_ERROR(ENOENT);
- }
-
/*
* Obtain the locked dquots. In case of an error (eg. allocation
* fails for ENOSPC), we return the negative of the error number
@@ -2563,7 +2558,7 @@
uint bfield = XFS_IS_REALTIME_INODE(ip) ?
XFS_TRANS_DQ_RTBCOUNT : XFS_TRANS_DQ_BCOUNT;
- ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
/* old dquot */
@@ -2607,7 +2602,7 @@
uint delblks, blkflags, prjflags = 0;
xfs_dquot_t *unresudq, *unresgdq, *delblksudq, *delblksgdq;
- ASSERT(XFS_ISLOCKED_INODE(ip));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
mp = ip->i_mount;
ASSERT(XFS_IS_QUOTA_RUNNING(mp));
@@ -2717,7 +2712,7 @@
if (!XFS_IS_QUOTA_ON(tp->t_mountp))
return;
- ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(XFS_IS_QUOTA_RUNNING(tp->t_mountp));
if (udqp) {
diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c
index 8342823..768a3b2 100644
--- a/fs/xfs/quota/xfs_qm_syscalls.c
+++ b/fs/xfs/quota/xfs_qm_syscalls.c
@@ -1366,12 +1366,6 @@
return (error);
}
- if (ip->i_d.di_mode == 0) {
- xfs_iput_new(ip, lock_flags);
- *res = BULKSTAT_RV_NOTHING;
- return XFS_ERROR(ENOENT);
- }
-
/*
* This inode can have blocks after eof which can get released
* when we send it to inactive. Since we don't check the dquot
diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h
index a8b85e2..5e4a40b 100644
--- a/fs/xfs/quota/xfs_quota_priv.h
+++ b/fs/xfs/quota/xfs_quota_priv.h
@@ -27,11 +27,6 @@
/* Number of dquots that fit in to a dquot block */
#define XFS_QM_DQPERBLK(mp) ((mp)->m_quotainfo->qi_dqperchunk)
-#define XFS_ISLOCKED_INODE(ip) (ismrlocked(&(ip)->i_lock, \
- MR_UPDATE | MR_ACCESS) != 0)
-#define XFS_ISLOCKED_INODE_EXCL(ip) (ismrlocked(&(ip)->i_lock, \
- MR_UPDATE) != 0)
-
#define XFS_DQ_IS_ADDEDTO_TRX(t, d) ((d)->q_transp == (t))
#define XFS_QI_MPLRECLAIMS(mp) ((mp)->m_quotainfo->qi_dqreclaims)
diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c
index f441f83..9961138 100644
--- a/fs/xfs/quota/xfs_trans_dquot.c
+++ b/fs/xfs/quota/xfs_trans_dquot.c
@@ -834,7 +834,7 @@
ASSERT(ip->i_ino != mp->m_sb.sb_uquotino);
ASSERT(ip->i_ino != mp->m_sb.sb_gquotino);
- ASSERT(XFS_ISLOCKED_INODE_EXCL(ip));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(XFS_IS_QUOTA_RUNNING(ip->i_mount));
ASSERT((flags & ~(XFS_QMOPT_FORCE_RES | XFS_QMOPT_ENOSPC)) ==
XFS_TRANS_DQ_RES_RTBLKS ||
diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h
index 855da04..75845f9 100644
--- a/fs/xfs/support/debug.h
+++ b/fs/xfs/support/debug.h
@@ -49,8 +49,6 @@
#else /* DEBUG */
-#include <linux/random.h>
-
#define ASSERT(expr) \
(unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__))
diff --git a/fs/xfs/xfs.h b/fs/xfs/xfs.h
index 765aaf6..540e4c9 100644
--- a/fs/xfs/xfs.h
+++ b/fs/xfs/xfs.h
@@ -22,7 +22,7 @@
#define STATIC
#define DEBUG 1
#define XFS_BUF_LOCK_TRACKING 1
-#define QUOTADEBUG 1
+/* #define QUOTADEBUG 1 */
#endif
#ifdef CONFIG_XFS_TRACE
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 8e130b9..ebee3a4 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -72,7 +72,7 @@
{
int error;
- if (!VN_ISDIR(vp))
+ if (!S_ISDIR(vp->i_mode))
return 0;
xfs_acl_get_attr(vp, NULL, _ACL_TYPE_DEFAULT, ATTR_KERNOVAL, &error);
return (error == 0);
@@ -238,15 +238,8 @@
error = EINVAL;
goto out;
}
- if (kind == _ACL_TYPE_ACCESS) {
- bhv_vattr_t va;
-
- va.va_mask = XFS_AT_MODE;
- error = xfs_getattr(xfs_vtoi(vp), &va, 0);
- if (error)
- goto out;
- xfs_acl_sync_mode(va.va_mode, xfs_acl);
- }
+ if (kind == _ACL_TYPE_ACCESS)
+ xfs_acl_sync_mode(xfs_vtoi(vp)->i_d.di_mode, xfs_acl);
error = -posix_acl_xfs_to_xattr(xfs_acl, ext_acl, size);
}
out:
@@ -341,14 +334,15 @@
{
xfs_acl_t *acl;
int rval;
+ struct xfs_name acl_name = {SGI_ACL_FILE, SGI_ACL_FILE_SIZE};
if (!(_ACL_ALLOC(acl)))
return -1;
/* If the file has no ACL return -1. */
rval = sizeof(xfs_acl_t);
- if (xfs_attr_fetch(ip, SGI_ACL_FILE, SGI_ACL_FILE_SIZE,
- (char *)acl, &rval, ATTR_ROOT | ATTR_KERNACCESS, cr)) {
+ if (xfs_attr_fetch(ip, &acl_name, (char *)acl, &rval,
+ ATTR_ROOT | ATTR_KERNACCESS)) {
_ACL_FREE(acl);
return -1;
}
@@ -373,23 +367,15 @@
bhv_vnode_t *vp,
int kind)
{
- xfs_inode_t *ip = xfs_vtoi(vp);
- bhv_vattr_t va;
- int error;
-
if (vp->i_flags & (S_IMMUTABLE|S_APPEND))
return EPERM;
- if (kind == _ACL_TYPE_DEFAULT && !VN_ISDIR(vp))
+ if (kind == _ACL_TYPE_DEFAULT && !S_ISDIR(vp->i_mode))
return ENOTDIR;
if (vp->i_sb->s_flags & MS_RDONLY)
return EROFS;
- va.va_mask = XFS_AT_UID;
- error = xfs_getattr(ip, &va, 0);
- if (error)
- return error;
- if (va.va_uid != current->fsuid && !capable(CAP_FOWNER))
+ if (xfs_vtoi(vp)->i_d.di_uid != current->fsuid && !capable(CAP_FOWNER))
return EPERM;
- return error;
+ return 0;
}
/*
@@ -594,7 +580,7 @@
*error = xfs_attr_get(xfs_vtoi(vp),
kind == _ACL_TYPE_ACCESS ?
SGI_ACL_FILE : SGI_ACL_DEFAULT,
- (char *)aclp, &len, flags, sys_cred);
+ (char *)aclp, &len, flags);
if (*error || (flags & ATTR_KERNOVAL))
return;
xfs_acl_get_endian(aclp);
@@ -643,7 +629,6 @@
xfs_acl_t *access_acl,
xfs_acl_t *default_acl)
{
- bhv_vattr_t va;
int error = 0;
if (access_acl) {
@@ -652,16 +637,10 @@
* be obtained for some reason, invalidate the access ACL.
*/
xfs_acl_get_attr(vp, access_acl, _ACL_TYPE_ACCESS, 0, &error);
- if (!error) {
- /* Got the ACL, need the mode... */
- va.va_mask = XFS_AT_MODE;
- error = xfs_getattr(xfs_vtoi(vp), &va, 0);
- }
-
if (error)
access_acl->acl_cnt = XFS_ACL_NOT_PRESENT;
else /* We have a good ACL and the file mode, synchronize. */
- xfs_acl_sync_mode(va.va_mode, access_acl);
+ xfs_acl_sync_mode(xfs_vtoi(vp)->i_d.di_mode, access_acl);
}
if (default_acl) {
@@ -719,7 +698,7 @@
* If the new file is a directory, its default ACL is a copy of
* the containing directory's default ACL.
*/
- if (VN_ISDIR(vp))
+ if (S_ISDIR(vp->i_mode))
xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error);
if (!error && !basicperms)
xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error);
@@ -744,7 +723,7 @@
bhv_vattr_t va;
xfs_acl_entry_t *ap;
xfs_acl_entry_t *gap = NULL;
- int i, error, nomask = 1;
+ int i, nomask = 1;
*basicperms = 1;
@@ -756,11 +735,7 @@
* mode. The m:: bits take precedence over the g:: bits.
*/
va.va_mask = XFS_AT_MODE;
- error = xfs_getattr(xfs_vtoi(vp), &va, 0);
- if (error)
- return error;
-
- va.va_mask = XFS_AT_MODE;
+ va.va_mode = xfs_vtoi(vp)->i_d.di_mode;
va.va_mode &= ~(S_IRWXU|S_IRWXG|S_IRWXO);
ap = acl->acl_entry;
for (i = 0; i < acl->acl_cnt; ++i) {
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 36d781e..df151a8 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -101,14 +101,28 @@
ktrace_t *xfs_attr_trace_buf;
#endif
+STATIC int
+xfs_attr_name_to_xname(
+ struct xfs_name *xname,
+ const char *aname)
+{
+ if (!aname)
+ return EINVAL;
+ xname->name = aname;
+ xname->len = strlen(aname);
+ if (xname->len >= MAXNAMELEN)
+ return EFAULT; /* match IRIX behaviour */
+
+ return 0;
+}
/*========================================================================
* Overall external interface routines.
*========================================================================*/
int
-xfs_attr_fetch(xfs_inode_t *ip, const char *name, int namelen,
- char *value, int *valuelenp, int flags, struct cred *cred)
+xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name,
+ char *value, int *valuelenp, int flags)
{
xfs_da_args_t args;
int error;
@@ -122,8 +136,8 @@
* Fill in the arg structure for this request.
*/
memset((char *)&args, 0, sizeof(args));
- args.name = name;
- args.namelen = namelen;
+ args.name = name->name;
+ args.namelen = name->len;
args.value = value;
args.valuelen = *valuelenp;
args.flags = flags;
@@ -162,31 +176,29 @@
const char *name,
char *value,
int *valuelenp,
- int flags,
- cred_t *cred)
+ int flags)
{
- int error, namelen;
+ int error;
+ struct xfs_name xname;
XFS_STATS_INC(xs_attr_get);
- if (!name)
- return(EINVAL);
- namelen = strlen(name);
- if (namelen >= MAXNAMELEN)
- return(EFAULT); /* match IRIX behaviour */
-
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return(EIO);
+ error = xfs_attr_name_to_xname(&xname, name);
+ if (error)
+ return error;
+
xfs_ilock(ip, XFS_ILOCK_SHARED);
- error = xfs_attr_fetch(ip, name, namelen, value, valuelenp, flags, cred);
+ error = xfs_attr_fetch(ip, &xname, value, valuelenp, flags);
xfs_iunlock(ip, XFS_ILOCK_SHARED);
return(error);
}
-int
-xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
- char *value, int valuelen, int flags)
+STATIC int
+xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name,
+ char *value, int valuelen, int flags)
{
xfs_da_args_t args;
xfs_fsblock_t firstblock;
@@ -209,7 +221,7 @@
*/
if (XFS_IFORK_Q(dp) == 0) {
int sf_size = sizeof(xfs_attr_sf_hdr_t) +
- XFS_ATTR_SF_ENTSIZE_BYNAME(namelen, valuelen);
+ XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd)))
return(error);
@@ -219,8 +231,8 @@
* Fill in the arg structure for this request.
*/
memset((char *)&args, 0, sizeof(args));
- args.name = name;
- args.namelen = namelen;
+ args.name = name->name;
+ args.namelen = name->len;
args.value = value;
args.valuelen = valuelen;
args.flags = flags;
@@ -236,7 +248,7 @@
* Determine space new attribute will use, and if it would be
* "local" or "remote" (note: local != inline).
*/
- size = xfs_attr_leaf_newentsize(namelen, valuelen,
+ size = xfs_attr_leaf_newentsize(name->len, valuelen,
mp->m_sb.sb_blocksize, &local);
nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
@@ -429,26 +441,27 @@
int valuelen,
int flags)
{
- int namelen;
-
- namelen = strlen(name);
- if (namelen >= MAXNAMELEN)
- return EFAULT; /* match IRIX behaviour */
+ int error;
+ struct xfs_name xname;
XFS_STATS_INC(xs_attr_set);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return (EIO);
- return xfs_attr_set_int(dp, name, namelen, value, valuelen, flags);
+ error = xfs_attr_name_to_xname(&xname, name);
+ if (error)
+ return error;
+
+ return xfs_attr_set_int(dp, &xname, value, valuelen, flags);
}
/*
* Generic handler routine to remove a name from an attribute list.
* Transitions attribute list from Btree to shortform as necessary.
*/
-int
-xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags)
+STATIC int
+xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
{
xfs_da_args_t args;
xfs_fsblock_t firstblock;
@@ -460,8 +473,8 @@
* Fill in the arg structure for this request.
*/
memset((char *)&args, 0, sizeof(args));
- args.name = name;
- args.namelen = namelen;
+ args.name = name->name;
+ args.namelen = name->len;
args.flags = flags;
args.hashval = xfs_da_hashname(args.name, args.namelen);
args.dp = dp;
@@ -575,17 +588,18 @@
const char *name,
int flags)
{
- int namelen;
-
- namelen = strlen(name);
- if (namelen >= MAXNAMELEN)
- return EFAULT; /* match IRIX behaviour */
+ int error;
+ struct xfs_name xname;
XFS_STATS_INC(xs_attr_remove);
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return (EIO);
+ error = xfs_attr_name_to_xname(&xname, name);
+ if (error)
+ return error;
+
xfs_ilock(dp, XFS_ILOCK_SHARED);
if (XFS_IFORK_Q(dp) == 0 ||
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
@@ -595,10 +609,10 @@
}
xfs_iunlock(dp, XFS_ILOCK_SHARED);
- return xfs_attr_remove_int(dp, name, namelen, flags);
+ return xfs_attr_remove_int(dp, &xname, flags);
}
-int /* error */
+STATIC int
xfs_attr_list_int(xfs_attr_list_context_t *context)
{
int error;
@@ -2522,8 +2536,7 @@
{
int error, asize = size;
- error = xfs_attr_get(xfs_vtoi(vp), name, data,
- &asize, xflags, NULL);
+ error = xfs_attr_get(xfs_vtoi(vp), name, data, &asize, xflags);
if (!error)
return asize;
return -error;
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 786eba3..6cfc938 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -158,14 +158,10 @@
/*
* Overall external interface routines.
*/
-int xfs_attr_set_int(struct xfs_inode *, const char *, int, char *, int, int);
-int xfs_attr_remove_int(struct xfs_inode *, const char *, int, int);
-int xfs_attr_list_int(struct xfs_attr_list_context *);
int xfs_attr_inactive(struct xfs_inode *dp);
int xfs_attr_shortform_getvalue(struct xfs_da_args *);
-int xfs_attr_fetch(struct xfs_inode *, const char *, int,
- char *, int *, int, struct cred *);
+int xfs_attr_fetch(struct xfs_inode *, struct xfs_name *, char *, int *, int);
int xfs_attr_rmtval_get(struct xfs_da_args *args);
#endif /* __XFS_ATTR_H__ */
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index eb198c0..53c259f 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -4074,7 +4074,6 @@
error2:
xfs_bmap_cancel(&flist);
error1:
- ASSERT(ismrlocked(&ip->i_lock,MR_UPDATE));
xfs_iunlock(ip, XFS_ILOCK_EXCL);
error0:
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c
index 3f53fad..5f3647c 100644
--- a/fs/xfs/xfs_dfrag.c
+++ b/fs/xfs/xfs_dfrag.c
@@ -162,7 +162,7 @@
ips[1] = ip;
}
- xfs_lock_inodes(ips, 2, 0, lock_flags);
+ xfs_lock_inodes(ips, 2, lock_flags);
locked = 1;
/* Verify that both files have the same format */
@@ -265,7 +265,7 @@
locked = 0;
goto error0;
}
- xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL);
+ xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL);
/*
* Count the number of extended attribute blocks
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index d3a0f53..381ebda 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -462,7 +462,7 @@
xfs_mount_t *mp,
xfs_fsop_counts_t *cnt)
{
- xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT);
+ xfs_icsb_sync_counters(mp, XFS_ICSB_LAZY_COUNT);
spin_lock(&mp->m_sb_lock);
cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp);
cnt->freertx = mp->m_sb.sb_frextents;
@@ -524,7 +524,7 @@
*/
retry:
spin_lock(&mp->m_sb_lock);
- xfs_icsb_sync_counters_flags(mp, XFS_ICSB_SB_LOCKED);
+ xfs_icsb_sync_counters_locked(mp, 0);
/*
* If our previous reservation was larger than the current value,
@@ -552,11 +552,8 @@
mp->m_resblks += free;
mp->m_resblks_avail += free;
fdblks_delta = -free;
- mp->m_sb.sb_fdblocks = XFS_ALLOC_SET_ASIDE(mp);
} else {
fdblks_delta = -delta;
- mp->m_sb.sb_fdblocks =
- lcounter + XFS_ALLOC_SET_ASIDE(mp);
mp->m_resblks = request;
mp->m_resblks_avail += delta;
}
@@ -587,7 +584,6 @@
if (error == ENOSPC)
goto retry;
}
-
return 0;
}
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index a64dfbd..aad8c5d 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -147,6 +147,7 @@
int version; /* inode version number to use */
int isaligned = 0; /* inode allocation at stripe unit */
/* boundary */
+ unsigned int gen;
args.tp = tp;
args.mp = tp->t_mountp;
@@ -290,6 +291,14 @@
else
version = XFS_DINODE_VERSION_1;
+ /*
+ * Seed the new inode cluster with a random generation number. This
+ * prevents short-term reuse of generation numbers if a chunk is
+ * freed and then immediately reallocated. We use random numbers
+ * rather than a linear progression to prevent the next generation
+ * number from being easily guessable.
+ */
+ gen = random32();
for (j = 0; j < nbufs; j++) {
/*
* Get the block.
@@ -309,6 +318,7 @@
free = XFS_MAKE_IPTR(args.mp, fbuf, i);
free->di_core.di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
free->di_core.di_version = version;
+ free->di_core.di_gen = cpu_to_be32(gen);
free->di_next_unlinked = cpu_to_be32(NULLAGINO);
xfs_ialloc_log_di(tp, fbuf, i,
XFS_DI_CORE_BITS | XFS_DI_NEXT_UNLINKED);
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index e657c51..b07604b 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -593,8 +593,9 @@
* XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL
*/
void
-xfs_ilock(xfs_inode_t *ip,
- uint lock_flags)
+xfs_ilock(
+ xfs_inode_t *ip,
+ uint lock_flags)
{
/*
* You can't set both SHARED and EXCL for the same lock,
@@ -607,16 +608,16 @@
(XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
- if (lock_flags & XFS_IOLOCK_EXCL) {
+ if (lock_flags & XFS_IOLOCK_EXCL)
mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
- } else if (lock_flags & XFS_IOLOCK_SHARED) {
+ else if (lock_flags & XFS_IOLOCK_SHARED)
mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags));
- }
- if (lock_flags & XFS_ILOCK_EXCL) {
+
+ if (lock_flags & XFS_ILOCK_EXCL)
mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
- } else if (lock_flags & XFS_ILOCK_SHARED) {
+ else if (lock_flags & XFS_ILOCK_SHARED)
mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags));
- }
+
xfs_ilock_trace(ip, 1, lock_flags, (inst_t *)__return_address);
}
@@ -631,15 +632,12 @@
* lock_flags -- this parameter indicates the inode's locks to be
* to be locked. See the comment for xfs_ilock() for a list
* of valid values.
- *
*/
int
-xfs_ilock_nowait(xfs_inode_t *ip,
- uint lock_flags)
+xfs_ilock_nowait(
+ xfs_inode_t *ip,
+ uint lock_flags)
{
- int iolocked;
- int ilocked;
-
/*
* You can't set both SHARED and EXCL for the same lock,
* and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED,
@@ -651,37 +649,30 @@
(XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_DEP_MASK)) == 0);
- iolocked = 0;
if (lock_flags & XFS_IOLOCK_EXCL) {
- iolocked = mrtryupdate(&ip->i_iolock);
- if (!iolocked) {
- return 0;
- }
+ if (!mrtryupdate(&ip->i_iolock))
+ goto out;
} else if (lock_flags & XFS_IOLOCK_SHARED) {
- iolocked = mrtryaccess(&ip->i_iolock);
- if (!iolocked) {
- return 0;
- }
+ if (!mrtryaccess(&ip->i_iolock))
+ goto out;
}
if (lock_flags & XFS_ILOCK_EXCL) {
- ilocked = mrtryupdate(&ip->i_lock);
- if (!ilocked) {
- if (iolocked) {
- mrunlock(&ip->i_iolock);
- }
- return 0;
- }
+ if (!mrtryupdate(&ip->i_lock))
+ goto out_undo_iolock;
} else if (lock_flags & XFS_ILOCK_SHARED) {
- ilocked = mrtryaccess(&ip->i_lock);
- if (!ilocked) {
- if (iolocked) {
- mrunlock(&ip->i_iolock);
- }
- return 0;
- }
+ if (!mrtryaccess(&ip->i_lock))
+ goto out_undo_iolock;
}
xfs_ilock_trace(ip, 2, lock_flags, (inst_t *)__return_address);
return 1;
+
+ out_undo_iolock:
+ if (lock_flags & XFS_IOLOCK_EXCL)
+ mrunlock_excl(&ip->i_iolock);
+ else if (lock_flags & XFS_IOLOCK_SHARED)
+ mrunlock_shared(&ip->i_iolock);
+ out:
+ return 0;
}
/*
@@ -697,8 +688,9 @@
*
*/
void
-xfs_iunlock(xfs_inode_t *ip,
- uint lock_flags)
+xfs_iunlock(
+ xfs_inode_t *ip,
+ uint lock_flags)
{
/*
* You can't set both SHARED and EXCL for the same lock,
@@ -713,31 +705,25 @@
XFS_LOCK_DEP_MASK)) == 0);
ASSERT(lock_flags != 0);
- if (lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) {
- ASSERT(!(lock_flags & XFS_IOLOCK_SHARED) ||
- (ismrlocked(&ip->i_iolock, MR_ACCESS)));
- ASSERT(!(lock_flags & XFS_IOLOCK_EXCL) ||
- (ismrlocked(&ip->i_iolock, MR_UPDATE)));
- mrunlock(&ip->i_iolock);
- }
+ if (lock_flags & XFS_IOLOCK_EXCL)
+ mrunlock_excl(&ip->i_iolock);
+ else if (lock_flags & XFS_IOLOCK_SHARED)
+ mrunlock_shared(&ip->i_iolock);
- if (lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) {
- ASSERT(!(lock_flags & XFS_ILOCK_SHARED) ||
- (ismrlocked(&ip->i_lock, MR_ACCESS)));
- ASSERT(!(lock_flags & XFS_ILOCK_EXCL) ||
- (ismrlocked(&ip->i_lock, MR_UPDATE)));
- mrunlock(&ip->i_lock);
+ if (lock_flags & XFS_ILOCK_EXCL)
+ mrunlock_excl(&ip->i_lock);
+ else if (lock_flags & XFS_ILOCK_SHARED)
+ mrunlock_shared(&ip->i_lock);
+ if ((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) &&
+ !(lock_flags & XFS_IUNLOCK_NONOTIFY) && ip->i_itemp) {
/*
* Let the AIL know that this item has been unlocked in case
* it is in the AIL and anyone is waiting on it. Don't do
* this if the caller has asked us not to.
*/
- if (!(lock_flags & XFS_IUNLOCK_NONOTIFY) &&
- ip->i_itemp != NULL) {
- xfs_trans_unlocked_item(ip->i_mount,
- (xfs_log_item_t*)(ip->i_itemp));
- }
+ xfs_trans_unlocked_item(ip->i_mount,
+ (xfs_log_item_t*)(ip->i_itemp));
}
xfs_ilock_trace(ip, 3, lock_flags, (inst_t *)__return_address);
}
@@ -747,22 +733,48 @@
* if it is being demoted.
*/
void
-xfs_ilock_demote(xfs_inode_t *ip,
- uint lock_flags)
+xfs_ilock_demote(
+ xfs_inode_t *ip,
+ uint lock_flags)
{
ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL));
ASSERT((lock_flags & ~(XFS_IOLOCK_EXCL|XFS_ILOCK_EXCL)) == 0);
- if (lock_flags & XFS_ILOCK_EXCL) {
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
+ if (lock_flags & XFS_ILOCK_EXCL)
mrdemote(&ip->i_lock);
- }
- if (lock_flags & XFS_IOLOCK_EXCL) {
- ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE));
+ if (lock_flags & XFS_IOLOCK_EXCL)
mrdemote(&ip->i_iolock);
- }
}
+#ifdef DEBUG
+/*
+ * Debug-only routine, without additional rw_semaphore APIs, we can
+ * now only answer requests regarding whether we hold the lock for write
+ * (reader state is outside our visibility, we only track writer state).
+ *
+ * Note: this means !xfs_isilocked would give false positives, so don't do that.
+ */
+int
+xfs_isilocked(
+ xfs_inode_t *ip,
+ uint lock_flags)
+{
+ if ((lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) ==
+ XFS_ILOCK_EXCL) {
+ if (!ip->i_lock.mr_writer)
+ return 0;
+ }
+
+ if ((lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) ==
+ XFS_IOLOCK_EXCL) {
+ if (!ip->i_iolock.mr_writer)
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
/*
* The following three routines simply manage the i_flock
* semaphore embedded in the inode. This semaphore synchronizes
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index ca12acb..cf0bb9c 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1291,7 +1291,7 @@
xfs_fileoff_t size_last_block;
int error;
- ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE | MR_ACCESS));
+ ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED));
mp = ip->i_mount;
/*
@@ -1402,7 +1402,7 @@
bhv_vnode_t *vp;
int error = 0;
- ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0);
+ ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
ASSERT((new_size == 0) || (new_size <= ip->i_size));
ASSERT((flags == XFS_ITRUNC_DEFINITE) ||
(flags == XFS_ITRUNC_MAYBE));
@@ -1528,8 +1528,7 @@
xfs_bmap_free_t free_list;
int error;
- ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE) != 0);
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0);
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
ASSERT((new_size == 0) || (new_size <= ip->i_size));
ASSERT(*tp != NULL);
ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES);
@@ -1780,8 +1779,7 @@
xfs_fsize_t new_size,
cred_t *credp)
{
- ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);
- ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0);
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
ASSERT(new_size > ip->i_size);
/*
@@ -1809,8 +1807,7 @@
xfs_fsize_t new_size,
int change_flag)
{
- ASSERT(ismrlocked(&(ip->i_lock), MR_UPDATE) != 0);
- ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE) != 0);
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_IOLOCK_EXCL));
ASSERT(ip->i_transp == tp);
ASSERT(new_size > ip->i_size);
@@ -2287,7 +2284,7 @@
xfs_dinode_t *dip;
xfs_buf_t *ibp;
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(ip->i_transp == tp);
ASSERT(ip->i_d.di_nlink == 0);
ASSERT(ip->i_d.di_nextents == 0);
@@ -2746,7 +2743,7 @@
xfs_ipin(
xfs_inode_t *ip)
{
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
atomic_inc(&ip->i_pincount);
}
@@ -2779,7 +2776,7 @@
{
xfs_inode_log_item_t *iip = ip->i_itemp;
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE | MR_ACCESS));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
if (atomic_read(&ip->i_pincount) == 0)
return;
@@ -2829,7 +2826,7 @@
xfs_fsblock_t start_block;
ifp = XFS_IFORK_PTR(ip, whichfork);
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
ASSERT(ifp->if_bytes > 0);
nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t);
@@ -3132,7 +3129,7 @@
XFS_STATS_INC(xs_iflush_count);
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
ASSERT(issemalocked(&(ip->i_flock)));
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
ip->i_d.di_nextents > ip->i_df.if_ext_max);
@@ -3297,7 +3294,7 @@
int first;
#endif
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE|MR_ACCESS));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
ASSERT(issemalocked(&(ip->i_flock)));
ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE ||
ip->i_d.di_nextents > ip->i_df.if_ext_max);
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 93c3769..0a999fe 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -386,20 +386,9 @@
#define XFS_ILOCK_EXCL (1<<2)
#define XFS_ILOCK_SHARED (1<<3)
#define XFS_IUNLOCK_NONOTIFY (1<<4)
-/* #define XFS_IOLOCK_NESTED (1<<5) */
-#define XFS_EXTENT_TOKEN_RD (1<<6)
-#define XFS_SIZE_TOKEN_RD (1<<7)
-#define XFS_EXTSIZE_RD (XFS_EXTENT_TOKEN_RD|XFS_SIZE_TOKEN_RD)
-#define XFS_WILLLEND (1<<8) /* Always acquire tokens for lending */
-#define XFS_EXTENT_TOKEN_WR (XFS_EXTENT_TOKEN_RD | XFS_WILLLEND)
-#define XFS_SIZE_TOKEN_WR (XFS_SIZE_TOKEN_RD | XFS_WILLLEND)
-#define XFS_EXTSIZE_WR (XFS_EXTSIZE_RD | XFS_WILLLEND)
-/* TODO:XFS_SIZE_TOKEN_WANT (1<<9) */
#define XFS_LOCK_MASK (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED \
- | XFS_ILOCK_EXCL | XFS_ILOCK_SHARED \
- | XFS_EXTENT_TOKEN_RD | XFS_SIZE_TOKEN_RD \
- | XFS_WILLLEND)
+ | XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)
/*
* Flags for lockdep annotations.
@@ -483,6 +472,7 @@
int xfs_ilock_nowait(xfs_inode_t *, uint);
void xfs_iunlock(xfs_inode_t *, uint);
void xfs_ilock_demote(xfs_inode_t *, uint);
+int xfs_isilocked(xfs_inode_t *, uint);
void xfs_iflock(xfs_inode_t *);
int xfs_iflock_nowait(xfs_inode_t *);
uint xfs_ilock_map_shared(xfs_inode_t *);
@@ -534,7 +524,7 @@
void xfs_iflush_all(struct xfs_mount *);
void xfs_ichgtime(xfs_inode_t *, int);
xfs_fsize_t xfs_file_last_byte(xfs_inode_t *);
-void xfs_lock_inodes(xfs_inode_t **, int, int, uint);
+void xfs_lock_inodes(xfs_inode_t **, int, uint);
void xfs_synchronize_atime(xfs_inode_t *);
void xfs_mark_inode_dirty_sync(xfs_inode_t *);
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 93b5db4..167b33f 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -547,7 +547,7 @@
xfs_inode_item_pin(
xfs_inode_log_item_t *iip)
{
- ASSERT(ismrlocked(&(iip->ili_inode->i_lock), MR_UPDATE));
+ ASSERT(xfs_isilocked(iip->ili_inode, XFS_ILOCK_EXCL));
xfs_ipin(iip->ili_inode);
}
@@ -664,13 +664,13 @@
ASSERT(iip != NULL);
ASSERT(iip->ili_inode->i_itemp != NULL);
- ASSERT(ismrlocked(&(iip->ili_inode->i_lock), MR_UPDATE));
+ ASSERT(xfs_isilocked(iip->ili_inode, XFS_ILOCK_EXCL));
ASSERT((!(iip->ili_inode->i_itemp->ili_flags &
XFS_ILI_IOLOCKED_EXCL)) ||
- ismrlocked(&(iip->ili_inode->i_iolock), MR_UPDATE));
+ xfs_isilocked(iip->ili_inode, XFS_IOLOCK_EXCL));
ASSERT((!(iip->ili_inode->i_itemp->ili_flags &
XFS_ILI_IOLOCKED_SHARED)) ||
- ismrlocked(&(iip->ili_inode->i_iolock), MR_ACCESS));
+ xfs_isilocked(iip->ili_inode, XFS_IOLOCK_SHARED));
/*
* Clear the transaction pointer in the inode.
*/
@@ -769,7 +769,7 @@
ip = iip->ili_inode;
- ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
/*
* The ili_pushbuf_flag keeps others from
@@ -857,7 +857,7 @@
ip = iip->ili_inode;
- ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED));
ASSERT(issemalocked(&(ip->i_flock)));
/*
* Since we were able to lock the inode's flush lock and
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index fb3cf11..7edcde6 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -196,14 +196,14 @@
break;
case BMAPI_WRITE:
xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, ip, offset, count);
- lockmode = XFS_ILOCK_EXCL|XFS_EXTSIZE_WR;
+ lockmode = XFS_ILOCK_EXCL;
if (flags & BMAPI_IGNSTATE)
bmapi_flags |= XFS_BMAPI_IGSTATE|XFS_BMAPI_ENTIRE;
xfs_ilock(ip, lockmode);
break;
case BMAPI_ALLOCATE:
xfs_iomap_enter_trace(XFS_IOMAP_ALLOC_ENTER, ip, offset, count);
- lockmode = XFS_ILOCK_SHARED|XFS_EXTSIZE_RD;
+ lockmode = XFS_ILOCK_SHARED;
bmapi_flags = XFS_BMAPI_ENTIRE;
/* Attempt non-blocking lock */
@@ -523,8 +523,7 @@
goto error_out;
}
- if (unlikely(!imap.br_startblock &&
- !(XFS_IS_REALTIME_INODE(ip)))) {
+ if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip))) {
error = xfs_cmn_err_fsblock_zero(ip, &imap);
goto error_out;
}
@@ -624,7 +623,7 @@
int prealloc, fsynced = 0;
int error;
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE) != 0);
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
/*
* Make sure that the dquots are there. This doesn't hold
@@ -686,8 +685,7 @@
goto retry;
}
- if (unlikely(!imap[0].br_startblock &&
- !(XFS_IS_REALTIME_INODE(ip))))
+ if (!(imap[0].br_startblock || XFS_IS_REALTIME_INODE(ip)))
return xfs_cmn_err_fsblock_zero(ip, &imap[0]);
*ret_imap = imap[0];
@@ -838,9 +836,9 @@
* See if we were able to allocate an extent that
* covers at least part of the callers request
*/
- if (unlikely(!imap.br_startblock &&
- XFS_IS_REALTIME_INODE(ip)))
+ if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip)))
return xfs_cmn_err_fsblock_zero(ip, &imap);
+
if ((offset_fsb >= imap.br_startoff) &&
(offset_fsb < (imap.br_startoff +
imap.br_blockcount))) {
@@ -934,8 +932,7 @@
if (error)
return XFS_ERROR(error);
- if (unlikely(!imap.br_startblock &&
- !(XFS_IS_REALTIME_INODE(ip))))
+ if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip)))
return xfs_cmn_err_fsblock_zero(ip, &imap);
if ((numblks_fsb = imap.br_blockcount) == 0) {
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index eb85bde..419de15 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -71,11 +71,6 @@
ASSERT(ip != NULL);
ASSERT(ip->i_blkno != (xfs_daddr_t)0);
- if (ip->i_d.di_mode == 0) {
- *stat = BULKSTAT_RV_NOTHING;
- error = XFS_ERROR(ENOENT);
- goto out_iput;
- }
vp = XFS_ITOV(ip);
dic = &ip->i_d;
@@ -124,7 +119,6 @@
break;
}
- out_iput:
xfs_iput(ip, XFS_ILOCK_SHARED);
return error;
}
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
index 2fec452..da39884 100644
--- a/fs/xfs/xfs_mount.c
+++ b/fs/xfs/xfs_mount.c
@@ -54,8 +54,9 @@
#ifdef HAVE_PERCPU_SB
STATIC void xfs_icsb_destroy_counters(xfs_mount_t *);
STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t,
- int, int);
-STATIC void xfs_icsb_sync_counters(xfs_mount_t *);
+ int);
+STATIC void xfs_icsb_balance_counter_locked(xfs_mount_t *, xfs_sb_field_t,
+ int);
STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t,
int64_t, int);
STATIC void xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t);
@@ -63,8 +64,8 @@
#else
#define xfs_icsb_destroy_counters(mp) do { } while (0)
-#define xfs_icsb_balance_counter(mp, a, b, c) do { } while (0)
-#define xfs_icsb_sync_counters(mp) do { } while (0)
+#define xfs_icsb_balance_counter(mp, a, b) do { } while (0)
+#define xfs_icsb_balance_counter_locked(mp, a, b) do { } while (0)
#define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0)
#endif
@@ -1400,7 +1401,7 @@
if (!xfs_fs_writable(mp))
return 0;
- xfs_icsb_sync_counters(mp);
+ xfs_icsb_sync_counters(mp, 0);
/*
* we don't need to do this if we are updating the superblock
@@ -2026,9 +2027,9 @@
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
xfs_icsb_lock(mp);
- xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
xfs_icsb_unlock(mp);
break;
case CPU_DEAD:
@@ -2048,12 +2049,9 @@
memset(cntp, 0, sizeof(xfs_icsb_cnts_t));
- xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT,
- XFS_ICSB_SB_LOCKED, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_IFREE,
- XFS_ICSB_SB_LOCKED, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS,
- XFS_ICSB_SB_LOCKED, 0);
+ xfs_icsb_balance_counter_locked(mp, XFS_SBS_ICOUNT, 0);
+ xfs_icsb_balance_counter_locked(mp, XFS_SBS_IFREE, 0);
+ xfs_icsb_balance_counter_locked(mp, XFS_SBS_FDBLOCKS, 0);
spin_unlock(&mp->m_sb_lock);
xfs_icsb_unlock(mp);
break;
@@ -2105,9 +2103,9 @@
* initial balance kicks us off correctly
*/
mp->m_icsb_counters = -1;
- xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0);
- xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0);
+ xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0);
xfs_icsb_unlock(mp);
}
@@ -2223,7 +2221,7 @@
if (!test_and_set_bit(field, &mp->m_icsb_counters)) {
/* drain back to superblock */
- xfs_icsb_count(mp, &cnt, XFS_ICSB_SB_LOCKED|XFS_ICSB_LAZY_COUNT);
+ xfs_icsb_count(mp, &cnt, XFS_ICSB_LAZY_COUNT);
switch(field) {
case XFS_SBS_ICOUNT:
mp->m_sb.sb_icount = cnt.icsb_icount;
@@ -2278,38 +2276,33 @@
}
void
-xfs_icsb_sync_counters_flags(
+xfs_icsb_sync_counters_locked(
xfs_mount_t *mp,
int flags)
{
xfs_icsb_cnts_t cnt;
- /* Pass 1: lock all counters */
- if ((flags & XFS_ICSB_SB_LOCKED) == 0)
- spin_lock(&mp->m_sb_lock);
-
xfs_icsb_count(mp, &cnt, flags);
- /* Step 3: update mp->m_sb fields */
if (!xfs_icsb_counter_disabled(mp, XFS_SBS_ICOUNT))
mp->m_sb.sb_icount = cnt.icsb_icount;
if (!xfs_icsb_counter_disabled(mp, XFS_SBS_IFREE))
mp->m_sb.sb_ifree = cnt.icsb_ifree;
if (!xfs_icsb_counter_disabled(mp, XFS_SBS_FDBLOCKS))
mp->m_sb.sb_fdblocks = cnt.icsb_fdblocks;
-
- if ((flags & XFS_ICSB_SB_LOCKED) == 0)
- spin_unlock(&mp->m_sb_lock);
}
/*
* Accurate update of per-cpu counters to incore superblock
*/
-STATIC void
+void
xfs_icsb_sync_counters(
- xfs_mount_t *mp)
+ xfs_mount_t *mp,
+ int flags)
{
- xfs_icsb_sync_counters_flags(mp, 0);
+ spin_lock(&mp->m_sb_lock);
+ xfs_icsb_sync_counters_locked(mp, flags);
+ spin_unlock(&mp->m_sb_lock);
}
/*
@@ -2332,19 +2325,15 @@
#define XFS_ICSB_FDBLK_CNTR_REENABLE(mp) \
(uint64_t)(512 + XFS_ALLOC_SET_ASIDE(mp))
STATIC void
-xfs_icsb_balance_counter(
+xfs_icsb_balance_counter_locked(
xfs_mount_t *mp,
xfs_sb_field_t field,
- int flags,
int min_per_cpu)
{
uint64_t count, resid;
int weight = num_online_cpus();
uint64_t min = (uint64_t)min_per_cpu;
- if (!(flags & XFS_ICSB_SB_LOCKED))
- spin_lock(&mp->m_sb_lock);
-
/* disable counter and sync counter */
xfs_icsb_disable_counter(mp, field);
@@ -2354,19 +2343,19 @@
count = mp->m_sb.sb_icount;
resid = do_div(count, weight);
if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE))
- goto out;
+ return;
break;
case XFS_SBS_IFREE:
count = mp->m_sb.sb_ifree;
resid = do_div(count, weight);
if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE))
- goto out;
+ return;
break;
case XFS_SBS_FDBLOCKS:
count = mp->m_sb.sb_fdblocks;
resid = do_div(count, weight);
if (count < max(min, XFS_ICSB_FDBLK_CNTR_REENABLE(mp)))
- goto out;
+ return;
break;
default:
BUG();
@@ -2375,9 +2364,17 @@
}
xfs_icsb_enable_counter(mp, field, count, resid);
-out:
- if (!(flags & XFS_ICSB_SB_LOCKED))
- spin_unlock(&mp->m_sb_lock);
+}
+
+STATIC void
+xfs_icsb_balance_counter(
+ xfs_mount_t *mp,
+ xfs_sb_field_t fields,
+ int min_per_cpu)
+{
+ spin_lock(&mp->m_sb_lock);
+ xfs_icsb_balance_counter_locked(mp, fields, min_per_cpu);
+ spin_unlock(&mp->m_sb_lock);
}
STATIC int
@@ -2484,7 +2481,7 @@
* we are done.
*/
if (ret != ENOSPC)
- xfs_icsb_balance_counter(mp, field, 0, 0);
+ xfs_icsb_balance_counter(mp, field, 0);
xfs_icsb_unlock(mp);
return ret;
@@ -2508,7 +2505,7 @@
* will either succeed through the fast path or slow path without
* another balance operation being required.
*/
- xfs_icsb_balance_counter(mp, field, 0, delta);
+ xfs_icsb_balance_counter(mp, field, delta);
xfs_icsb_unlock(mp);
goto again;
}
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index 1ed5751..63e0693 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -206,17 +206,18 @@
#define XFS_ICSB_FLAG_LOCK (1 << 0) /* counter lock bit */
-#define XFS_ICSB_SB_LOCKED (1 << 0) /* sb already locked */
#define XFS_ICSB_LAZY_COUNT (1 << 1) /* accuracy not needed */
extern int xfs_icsb_init_counters(struct xfs_mount *);
extern void xfs_icsb_reinit_counters(struct xfs_mount *);
-extern void xfs_icsb_sync_counters_flags(struct xfs_mount *, int);
+extern void xfs_icsb_sync_counters(struct xfs_mount *, int);
+extern void xfs_icsb_sync_counters_locked(struct xfs_mount *, int);
#else
#define xfs_icsb_init_counters(mp) (0)
#define xfs_icsb_reinit_counters(mp) do { } while (0)
-#define xfs_icsb_sync_counters_flags(mp, flags) do { } while (0)
+#define xfs_icsb_sync_counters(mp, flags) do { } while (0)
+#define xfs_icsb_sync_counters_locked(mp, flags) do { } while (0)
#endif
typedef struct xfs_ail {
diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
index ee37189..d8063e1 100644
--- a/fs/xfs/xfs_rename.c
+++ b/fs/xfs/xfs_rename.c
@@ -55,85 +55,32 @@
xfs_iunlock(i_tab[0], lock_mode);
for (i = 1; i < 4; i++) {
- if (i_tab[i] == NULL) {
+ if (i_tab[i] == NULL)
break;
- }
+
/*
* Watch out for duplicate entries in the table.
*/
- if (i_tab[i] != i_tab[i-1]) {
+ if (i_tab[i] != i_tab[i-1])
xfs_iunlock(i_tab[i], lock_mode);
- }
}
}
-#ifdef DEBUG
-int xfs_rename_skip, xfs_rename_nskip;
-#endif
-
/*
- * The following routine will acquire the locks required for a rename
- * operation. The code understands the semantics of renames and will
- * validate that name1 exists under dp1 & that name2 may or may not
- * exist under dp2.
- *
- * We are renaming dp1/name1 to dp2/name2.
- *
- * Return ENOENT if dp1 does not exist, other lookup errors, or 0 for success.
+ * Enter all inodes for a rename transaction into a sorted array.
*/
-STATIC int
-xfs_lock_for_rename(
+STATIC void
+xfs_sort_for_rename(
xfs_inode_t *dp1, /* in: old (source) directory inode */
xfs_inode_t *dp2, /* in: new (target) directory inode */
xfs_inode_t *ip1, /* in: inode of old entry */
- struct xfs_name *name2, /* in: new entry name */
- xfs_inode_t **ipp2, /* out: inode of new entry, if it
+ xfs_inode_t *ip2, /* in: inode of new entry, if it
already exists, NULL otherwise. */
xfs_inode_t **i_tab,/* out: array of inode returned, sorted */
int *num_inodes) /* out: number of inodes in array */
{
- xfs_inode_t *ip2 = NULL;
xfs_inode_t *temp;
- xfs_ino_t inum1, inum2;
- int error;
int i, j;
- uint lock_mode;
- int diff_dirs = (dp1 != dp2);
-
- /*
- * First, find out the current inums of the entries so that we
- * can determine the initial locking order. We'll have to
- * sanity check stuff after all the locks have been acquired
- * to see if we still have the right inodes, directories, etc.
- */
- lock_mode = xfs_ilock_map_shared(dp1);
- IHOLD(ip1);
- xfs_itrace_ref(ip1);
-
- inum1 = ip1->i_ino;
-
- /*
- * Unlock dp1 and lock dp2 if they are different.
- */
- if (diff_dirs) {
- xfs_iunlock_map_shared(dp1, lock_mode);
- lock_mode = xfs_ilock_map_shared(dp2);
- }
-
- error = xfs_dir_lookup_int(dp2, lock_mode, name2, &inum2, &ip2);
- if (error == ENOENT) { /* target does not need to exist. */
- inum2 = 0;
- } else if (error) {
- /*
- * If dp2 and dp1 are the same, the next line unlocks dp1.
- * Got it?
- */
- xfs_iunlock_map_shared(dp2, lock_mode);
- IRELE (ip1);
- return error;
- } else {
- xfs_itrace_ref(ip2);
- }
/*
* i_tab contains a list of pointers to inodes. We initialize
@@ -145,21 +92,20 @@
i_tab[0] = dp1;
i_tab[1] = dp2;
i_tab[2] = ip1;
- if (inum2 == 0) {
- *num_inodes = 3;
- i_tab[3] = NULL;
- } else {
+ if (ip2) {
*num_inodes = 4;
i_tab[3] = ip2;
+ } else {
+ *num_inodes = 3;
+ i_tab[3] = NULL;
}
- *ipp2 = i_tab[3];
/*
* Sort the elements via bubble sort. (Remember, there are at
* most 4 elements to sort, so this is adequate.)
*/
- for (i=0; i < *num_inodes; i++) {
- for (j=1; j < *num_inodes; j++) {
+ for (i = 0; i < *num_inodes; i++) {
+ for (j = 1; j < *num_inodes; j++) {
if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) {
temp = i_tab[j];
i_tab[j] = i_tab[j-1];
@@ -167,30 +113,6 @@
}
}
}
-
- /*
- * We have dp2 locked. If it isn't first, unlock it.
- * If it is first, tell xfs_lock_inodes so it can skip it
- * when locking. if dp1 == dp2, xfs_lock_inodes will skip both
- * since they are equal. xfs_lock_inodes needs all these inodes
- * so that it can unlock and retry if there might be a dead-lock
- * potential with the log.
- */
-
- if (i_tab[0] == dp2 && lock_mode == XFS_ILOCK_SHARED) {
-#ifdef DEBUG
- xfs_rename_skip++;
-#endif
- xfs_lock_inodes(i_tab, *num_inodes, 1, XFS_ILOCK_SHARED);
- } else {
-#ifdef DEBUG
- xfs_rename_nskip++;
-#endif
- xfs_iunlock_map_shared(dp2, lock_mode);
- xfs_lock_inodes(i_tab, *num_inodes, 0, XFS_ILOCK_SHARED);
- }
-
- return 0;
}
/*
@@ -202,10 +124,10 @@
struct xfs_name *src_name,
xfs_inode_t *src_ip,
xfs_inode_t *target_dp,
- struct xfs_name *target_name)
+ struct xfs_name *target_name,
+ xfs_inode_t *target_ip)
{
- xfs_trans_t *tp;
- xfs_inode_t *target_ip;
+ xfs_trans_t *tp = NULL;
xfs_mount_t *mp = src_dp->i_mount;
int new_parent; /* moving to a new dir */
int src_is_directory; /* src_name is a directory */
@@ -215,9 +137,7 @@
int cancel_flags;
int committed;
xfs_inode_t *inodes[4];
- int target_ip_dropped = 0; /* dropped target_ip link? */
int spaceres;
- int target_link_zero = 0;
int num_inodes;
xfs_itrace_entry(src_dp);
@@ -230,64 +150,27 @@
target_dp, DM_RIGHT_NULL,
src_name->name, target_name->name,
0, 0, 0);
- if (error) {
+ if (error)
return error;
- }
}
/* Return through std_return after this point. */
- /*
- * Lock all the participating inodes. Depending upon whether
- * the target_name exists in the target directory, and
- * whether the target directory is the same as the source
- * directory, we can lock from 2 to 4 inodes.
- * xfs_lock_for_rename() will return ENOENT if src_name
- * does not exist in the source directory.
- */
- tp = NULL;
- error = xfs_lock_for_rename(src_dp, target_dp, src_ip, target_name,
- &target_ip, inodes, &num_inodes);
- if (error) {
- /*
- * We have nothing locked, no inode references, and
- * no transaction, so just get out.
- */
- goto std_return;
- }
-
- ASSERT(src_ip != NULL);
-
- if ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
- /*
- * Check for link count overflow on target_dp
- */
- if (target_ip == NULL && (src_dp != target_dp) &&
- target_dp->i_d.di_nlink >= XFS_MAXLINK) {
- error = XFS_ERROR(EMLINK);
- xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
- goto rele_return;
- }
- }
-
- /*
- * If we are using project inheritance, we only allow renames
- * into our tree when the project IDs are the same; else the
- * tree quota mechanism would be circumvented.
- */
- if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
- (target_dp->i_d.di_projid != src_ip->i_d.di_projid))) {
- error = XFS_ERROR(EXDEV);
- xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
- goto rele_return;
- }
-
new_parent = (src_dp != target_dp);
src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR);
- /*
- * Drop the locks on our inodes so that we can start the transaction.
- */
- xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
+ if (src_is_directory) {
+ /*
+ * Check for link count overflow on target_dp
+ */
+ if (target_ip == NULL && new_parent &&
+ target_dp->i_d.di_nlink >= XFS_MAXLINK) {
+ error = XFS_ERROR(EMLINK);
+ goto std_return;
+ }
+ }
+
+ xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip,
+ inodes, &num_inodes);
XFS_BMAP_INIT(&free_list, &first_block);
tp = xfs_trans_alloc(mp, XFS_TRANS_RENAME);
@@ -302,7 +185,7 @@
}
if (error) {
xfs_trans_cancel(tp, 0);
- goto rele_return;
+ goto std_return;
}
/*
@@ -310,13 +193,29 @@
*/
if ((error = XFS_QM_DQVOPRENAME(mp, inodes))) {
xfs_trans_cancel(tp, cancel_flags);
- goto rele_return;
+ goto std_return;
}
/*
- * Reacquire the inode locks we dropped above.
+ * Lock all the participating inodes. Depending upon whether
+ * the target_name exists in the target directory, and
+ * whether the target directory is the same as the source
+ * directory, we can lock from 2 to 4 inodes.
*/
- xfs_lock_inodes(inodes, num_inodes, 0, XFS_ILOCK_EXCL);
+ xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL);
+
+ /*
+ * If we are using project inheritance, we only allow renames
+ * into our tree when the project IDs are the same; else the
+ * tree quota mechanism would be circumvented.
+ */
+ if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) &&
+ (target_dp->i_d.di_projid != src_ip->i_d.di_projid))) {
+ error = XFS_ERROR(EXDEV);
+ xfs_rename_unlock4(inodes, XFS_ILOCK_SHARED);
+ xfs_trans_cancel(tp, cancel_flags);
+ goto std_return;
+ }
/*
* Join all the inodes to the transaction. From this point on,
@@ -328,17 +227,17 @@
*/
IHOLD(src_dp);
xfs_trans_ijoin(tp, src_dp, XFS_ILOCK_EXCL);
+
if (new_parent) {
IHOLD(target_dp);
xfs_trans_ijoin(tp, target_dp, XFS_ILOCK_EXCL);
}
- if ((src_ip != src_dp) && (src_ip != target_dp)) {
- xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
- }
- if ((target_ip != NULL) &&
- (target_ip != src_ip) &&
- (target_ip != src_dp) &&
- (target_ip != target_dp)) {
+
+ IHOLD(src_ip);
+ xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL);
+
+ if (target_ip) {
+ IHOLD(target_ip);
xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL);
}
@@ -412,7 +311,6 @@
error = xfs_droplink(tp, target_ip);
if (error)
goto abort_return;
- target_ip_dropped = 1;
if (src_is_directory) {
/*
@@ -422,10 +320,6 @@
if (error)
goto abort_return;
}
-
- /* Do this test while we still hold the locks */
- target_link_zero = (target_ip)->i_d.di_nlink==0;
-
} /* target_ip != NULL */
/*
@@ -492,15 +386,6 @@
}
/*
- * If there was a target inode, take an extra reference on
- * it here so that it doesn't go to xfs_inactive() from
- * within the commit.
- */
- if (target_ip != NULL) {
- IHOLD(target_ip);
- }
-
- /*
* If this is a synchronous mount, make sure that the
* rename transaction goes to disk before returning to
* the user.
@@ -509,30 +394,11 @@
xfs_trans_set_sync(tp);
}
- /*
- * Take refs. for vop_link_removed calls below. No need to worry
- * about directory refs. because the caller holds them.
- *
- * Do holds before the xfs_bmap_finish since it might rele them down
- * to zero.
- */
-
- if (target_ip_dropped)
- IHOLD(target_ip);
- IHOLD(src_ip);
-
error = xfs_bmap_finish(&tp, &free_list, &committed);
if (error) {
xfs_bmap_cancel(&free_list);
xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES |
XFS_TRANS_ABORT));
- if (target_ip != NULL) {
- IRELE(target_ip);
- }
- if (target_ip_dropped) {
- IRELE(target_ip);
- }
- IRELE(src_ip);
goto std_return;
}
@@ -541,15 +407,6 @@
* the vnode references.
*/
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
- if (target_ip != NULL)
- IRELE(target_ip);
- /*
- * Let interposed file systems know about removed links.
- */
- if (target_ip_dropped)
- IRELE(target_ip);
-
- IRELE(src_ip);
/* Fall through to std_return with error = 0 or errno from
* xfs_trans_commit */
@@ -571,11 +428,4 @@
xfs_bmap_cancel(&free_list);
xfs_trans_cancel(tp, cancel_flags);
goto std_return;
-
- rele_return:
- IRELE(src_ip);
- if (target_ip != NULL) {
- IRELE(target_ip);
- }
- goto std_return;
}
diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c
index b8db1d5..4c70bf5 100644
--- a/fs/xfs/xfs_trans_inode.c
+++ b/fs/xfs/xfs_trans_inode.c
@@ -111,13 +111,13 @@
*/
ASSERT(ip->i_itemp != NULL);
ASSERT(lock_flags & XFS_ILOCK_EXCL);
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) ||
- ismrlocked(&ip->i_iolock, MR_UPDATE));
+ xfs_isilocked(ip, XFS_IOLOCK_EXCL));
ASSERT((!(lock_flags & XFS_IOLOCK_EXCL)) ||
(ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_EXCL));
ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) ||
- ismrlocked(&ip->i_iolock, (MR_UPDATE | MR_ACCESS)));
+ xfs_isilocked(ip, XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED));
ASSERT((!(lock_flags & XFS_IOLOCK_SHARED)) ||
(ip->i_itemp->ili_flags & XFS_ILI_IOLOCKED_ANY));
@@ -185,7 +185,7 @@
xfs_inode_log_item_t *iip;
ASSERT(ip->i_transp == NULL);
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(lock_flags & XFS_ILOCK_EXCL);
if (ip->i_itemp == NULL)
xfs_inode_item_init(ip, ip->i_mount);
@@ -232,7 +232,7 @@
{
ASSERT(ip->i_transp == tp);
ASSERT(ip->i_itemp != NULL);
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ip->i_itemp->ili_flags |= XFS_ILI_HOLD;
}
@@ -257,7 +257,7 @@
ASSERT(ip->i_transp == tp);
ASSERT(ip->i_itemp != NULL);
- ASSERT(ismrlocked(&ip->i_lock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
lidp = xfs_trans_find_item(tp, (xfs_log_item_t*)(ip->i_itemp));
ASSERT(lidp != NULL);
diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c
index 2b8dc7e..98e5f110 100644
--- a/fs/xfs/xfs_utils.c
+++ b/fs/xfs/xfs_utils.c
@@ -41,49 +41,6 @@
#include "xfs_utils.h"
-int
-xfs_dir_lookup_int(
- xfs_inode_t *dp,
- uint lock_mode,
- struct xfs_name *name,
- xfs_ino_t *inum,
- xfs_inode_t **ipp)
-{
- int error;
-
- xfs_itrace_entry(dp);
-
- error = xfs_dir_lookup(NULL, dp, name, inum);
- if (!error) {
- /*
- * Unlock the directory. We do this because we can't
- * hold the directory lock while doing the vn_get()
- * in xfs_iget(). Doing so could cause us to hold
- * a lock while waiting for the inode to finish
- * being inactive while it's waiting for a log
- * reservation in the inactive routine.
- */
- xfs_iunlock(dp, lock_mode);
- error = xfs_iget(dp->i_mount, NULL, *inum, 0, 0, ipp, 0);
- xfs_ilock(dp, lock_mode);
-
- if (error) {
- *ipp = NULL;
- } else if ((*ipp)->i_d.di_mode == 0) {
- /*
- * The inode has been freed. Something is
- * wrong so just get out of here.
- */
- xfs_iunlock(dp, lock_mode);
- xfs_iput_new(*ipp, 0);
- *ipp = NULL;
- xfs_ilock(dp, lock_mode);
- error = XFS_ERROR(ENOENT);
- }
- }
- return error;
-}
-
/*
* Allocates a new inode from disk and return a pointer to the
* incore copy. This routine will internally commit the current
@@ -310,7 +267,7 @@
{
xfs_mount_t *mp;
- ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
ASSERT(ip->i_d.di_version == XFS_DINODE_VERSION_1);
ip->i_d.di_version = XFS_DINODE_VERSION_2;
diff --git a/fs/xfs/xfs_utils.h b/fs/xfs/xfs_utils.h
index 175b126..f316cb8 100644
--- a/fs/xfs/xfs_utils.h
+++ b/fs/xfs/xfs_utils.h
@@ -21,8 +21,6 @@
#define IRELE(ip) VN_RELE(XFS_ITOV(ip))
#define IHOLD(ip) VN_HOLD(XFS_ITOV(ip))
-extern int xfs_dir_lookup_int(xfs_inode_t *, uint, struct xfs_name *,
- xfs_ino_t *, xfs_inode_t **);
extern int xfs_truncate_file(xfs_mount_t *, xfs_inode_t *);
extern int xfs_dir_ialloc(xfs_trans_t **, xfs_inode_t *, mode_t, xfs_nlink_t,
xfs_dev_t, cred_t *, prid_t, int,
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index fc48158..30bacd8 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -186,6 +186,7 @@
kmem_zone_destroy(xfs_efi_zone);
kmem_zone_destroy(xfs_ifork_zone);
kmem_zone_destroy(xfs_ili_zone);
+ kmem_zone_destroy(xfs_log_ticket_zone);
}
/*
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 6650601..70702a6 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -76,132 +76,6 @@
}
/*
- * xfs_getattr
- */
-int
-xfs_getattr(
- xfs_inode_t *ip,
- bhv_vattr_t *vap,
- int flags)
-{
- bhv_vnode_t *vp = XFS_ITOV(ip);
- xfs_mount_t *mp = ip->i_mount;
-
- xfs_itrace_entry(ip);
-
- if (XFS_FORCED_SHUTDOWN(mp))
- return XFS_ERROR(EIO);
-
- if (!(flags & ATTR_LAZY))
- xfs_ilock(ip, XFS_ILOCK_SHARED);
-
- vap->va_size = XFS_ISIZE(ip);
- if (vap->va_mask == XFS_AT_SIZE)
- goto all_done;
-
- vap->va_nblocks =
- XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);
- vap->va_nodeid = ip->i_ino;
-#if XFS_BIG_INUMS
- vap->va_nodeid += mp->m_inoadd;
-#endif
- vap->va_nlink = ip->i_d.di_nlink;
-
- /*
- * Quick exit for non-stat callers
- */
- if ((vap->va_mask &
- ~(XFS_AT_SIZE|XFS_AT_FSID|XFS_AT_NODEID|
- XFS_AT_NLINK|XFS_AT_BLKSIZE)) == 0)
- goto all_done;
-
- /*
- * Copy from in-core inode.
- */
- 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.
- */
- 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 (!(XFS_IS_REALTIME_INODE(ip))) {
- vap->va_blocksize = xfs_preferred_iosize(mp);
- } else {
-
- /*
- * If the file blocks are being allocated from a
- * realtime partition, then return the inode's
- * realtime extent size or the realtime volume's
- * extent size.
- */
- vap->va_blocksize =
- xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog;
- }
- break;
- }
-
- vn_atime_to_timespec(vp, &vap->va_atime);
- vap->va_mtime.tv_sec = ip->i_d.di_mtime.t_sec;
- vap->va_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec;
- vap->va_ctime.tv_sec = ip->i_d.di_ctime.t_sec;
- vap->va_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec;
-
- /*
- * Exit for stat callers. See if any of the rest of the fields
- * to be filled in are needed.
- */
- if ((vap->va_mask &
- (XFS_AT_XFLAGS|XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|
- XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0)
- goto all_done;
-
- /*
- * Convert di_flags to xflags.
- */
- vap->va_xflags = xfs_ip2xflags(ip);
-
- /*
- * Exit for inode revalidate. See if any of the rest of
- * the fields to be filled in are needed.
- */
- if ((vap->va_mask &
- (XFS_AT_EXTSIZE|XFS_AT_NEXTENTS|XFS_AT_ANEXTENTS|
- XFS_AT_GENCOUNT|XFS_AT_VCODE)) == 0)
- goto all_done;
-
- vap->va_extsize = ip->i_d.di_extsize << mp->m_sb.sb_blocklog;
- vap->va_nextents =
- (ip->i_df.if_flags & XFS_IFEXTENTS) ?
- ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) :
- ip->i_d.di_nextents;
- if (ip->i_afp)
- vap->va_anextents =
- (ip->i_afp->if_flags & XFS_IFEXTENTS) ?
- ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) :
- ip->i_d.di_anextents;
- else
- vap->va_anextents = 0;
- vap->va_gen = ip->i_d.di_gen;
-
- all_done:
- if (!(flags & ATTR_LAZY))
- xfs_iunlock(ip, XFS_ILOCK_SHARED);
- return 0;
-}
-
-
-/*
* xfs_setattr
*/
int
@@ -211,7 +85,6 @@
int flags,
cred_t *credp)
{
- bhv_vnode_t *vp = XFS_ITOV(ip);
xfs_mount_t *mp = ip->i_mount;
xfs_trans_t *tp;
int mask;
@@ -222,7 +95,6 @@
gid_t gid=0, igid=0;
int timeflags = 0;
xfs_prid_t projid=0, iprojid=0;
- int mandlock_before, mandlock_after;
struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2;
int file_owner;
int need_iolock = 1;
@@ -383,7 +255,7 @@
m |= S_ISGID;
#if 0
/* Linux allows this, Irix doesn't. */
- if ((vap->va_mode & S_ISVTX) && !VN_ISDIR(vp))
+ if ((vap->va_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode))
m |= S_ISVTX;
#endif
if (m && !capable(CAP_FSETID))
@@ -461,10 +333,10 @@
goto error_return;
}
- if (VN_ISDIR(vp)) {
+ if (S_ISDIR(ip->i_d.di_mode)) {
code = XFS_ERROR(EISDIR);
goto error_return;
- } else if (!VN_ISREG(vp)) {
+ } else if (!S_ISREG(ip->i_d.di_mode)) {
code = XFS_ERROR(EINVAL);
goto error_return;
}
@@ -626,9 +498,6 @@
xfs_trans_ihold(tp, ip);
}
- /* determine whether mandatory locking mode changes */
- mandlock_before = MANDLOCK(vp, ip->i_d.di_mode);
-
/*
* Truncate file. Must have write permission and not be a directory.
*/
@@ -858,13 +727,6 @@
code = xfs_trans_commit(tp, commit_flags);
}
- /*
- * If the (regular) file's mandatory locking mode changed, then
- * notify the vnode. We do this under the inode lock to prevent
- * racing calls to vop_vnode_change.
- */
- mandlock_after = MANDLOCK(vp, ip->i_d.di_mode);
-
xfs_iunlock(ip, lock_flags);
/*
@@ -1443,7 +1305,7 @@
int error;
xfs_mount_t *mp;
- ASSERT(ismrlocked(&ip->i_iolock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
tp = *tpp;
mp = ip->i_mount;
ASSERT(ip->i_d.di_forkoff != 0);
@@ -1491,7 +1353,7 @@
xfs_mount_t *mp = ip->i_mount;
int error;
- if (!VN_ISREG(vp) || (ip->i_d.di_mode == 0))
+ if (!S_ISREG(ip->i_d.di_mode) || (ip->i_d.di_mode == 0))
return 0;
/* If this is a read-only mount, don't do this (would generate I/O) */
@@ -1774,8 +1636,7 @@
struct xfs_name *name,
xfs_inode_t **ipp)
{
- xfs_inode_t *ip;
- xfs_ino_t e_inum;
+ xfs_ino_t inum;
int error;
uint lock_mode;
@@ -1785,12 +1646,21 @@
return XFS_ERROR(EIO);
lock_mode = xfs_ilock_map_shared(dp);
- error = xfs_dir_lookup_int(dp, lock_mode, name, &e_inum, &ip);
- if (!error) {
- *ipp = ip;
- xfs_itrace_ref(ip);
- }
+ error = xfs_dir_lookup(NULL, dp, name, &inum);
xfs_iunlock_map_shared(dp, lock_mode);
+
+ if (error)
+ goto out;
+
+ error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp, 0);
+ if (error)
+ goto out;
+
+ xfs_itrace_ref(*ipp);
+ return 0;
+
+ out:
+ *ipp = NULL;
return error;
}
@@ -1906,7 +1776,7 @@
* It is locked (and joined to the transaction).
*/
- ASSERT(ismrlocked (&ip->i_lock, MR_UPDATE));
+ ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
/*
* Now we join the directory inode to the transaction. We do not do it
@@ -2112,7 +1982,7 @@
ips[0] = ip;
ips[1] = dp;
- xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL);
+ xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL);
}
/* else e_inum == dp->i_ino */
/* This can happen if we're asked to lock /x/..
@@ -2160,7 +2030,6 @@
xfs_lock_inodes(
xfs_inode_t **ips,
int inodes,
- int first_locked,
uint lock_mode)
{
int attempts = 0, i, j, try_lock;
@@ -2168,13 +2037,8 @@
ASSERT(ips && (inodes >= 2)); /* we need at least two */
- if (first_locked) {
- try_lock = 1;
- i = 1;
- } else {
- try_lock = 0;
- i = 0;
- }
+ try_lock = 0;
+ i = 0;
again:
for (; i < inodes; i++) {
@@ -2298,29 +2162,14 @@
return error;
}
- /*
- * We need to get a reference to ip before we get our log
- * reservation. The reason for this is that we cannot call
- * xfs_iget for an inode for which we do not have a reference
- * once we've acquired a log reservation. This is because the
- * inode we are trying to get might be in xfs_inactive going
- * for a log reservation. Since we'll have to wait for the
- * inactive code to complete before returning from xfs_iget,
- * we need to make sure that we don't have log space reserved
- * when we call xfs_iget. Instead we get an unlocked reference
- * to the inode before getting our log reservation.
- */
- IHOLD(ip);
-
xfs_itrace_entry(ip);
xfs_itrace_ref(ip);
error = XFS_QM_DQATTACH(mp, dp, 0);
- if (!error && dp != ip)
+ if (!error)
error = XFS_QM_DQATTACH(mp, ip, 0);
if (error) {
REMOVE_DEBUG_TRACE(__LINE__);
- IRELE(ip);
goto std_return;
}
@@ -2347,7 +2196,6 @@
ASSERT(error != ENOSPC);
REMOVE_DEBUG_TRACE(__LINE__);
xfs_trans_cancel(tp, 0);
- IRELE(ip);
return error;
}
@@ -2355,7 +2203,6 @@
if (error) {
REMOVE_DEBUG_TRACE(__LINE__);
xfs_trans_cancel(tp, cancel_flags);
- IRELE(ip);
goto std_return;
}
@@ -2363,23 +2210,18 @@
* At this point, we've gotten both the directory and the entry
* inodes locked.
*/
+ IHOLD(ip);
xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
- if (dp != ip) {
- /*
- * Increment vnode ref count only in this case since
- * there's an extra vnode reference in the case where
- * dp == ip.
- */
- IHOLD(dp);
- xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
- }
+
+ IHOLD(dp);
+ xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
/*
* Entry must exist since we did a lookup in xfs_lock_dir_and_entry.
*/
XFS_BMAP_INIT(&free_list, &first_block);
error = xfs_dir_removename(tp, dp, name, ip->i_ino,
- &first_block, &free_list, 0);
+ &first_block, &free_list, resblks);
if (error) {
ASSERT(error != ENOENT);
REMOVE_DEBUG_TRACE(__LINE__);
@@ -2402,12 +2244,6 @@
link_zero = (ip)->i_d.di_nlink==0;
/*
- * Take an extra ref on the inode so that it doesn't
- * go to xfs_inactive() from within the commit.
- */
- IHOLD(ip);
-
- /*
* If this is a synchronous mount, make sure that the
* remove transaction goes to disk before returning to
* the user.
@@ -2423,10 +2259,8 @@
}
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
- if (error) {
- IRELE(ip);
+ if (error)
goto std_return;
- }
/*
* If we are using filestreams, kill the stream association.
@@ -2438,7 +2272,6 @@
xfs_filestream_deassociate(ip);
xfs_itrace_exit(ip);
- IRELE(ip);
/* Fall through to std_return with error = 0 */
std_return:
@@ -2467,8 +2300,6 @@
cancel_flags |= XFS_TRANS_ABORT;
xfs_trans_cancel(tp, cancel_flags);
- IRELE(ip);
-
goto std_return;
}
@@ -2536,7 +2367,7 @@
ips[1] = sip;
}
- xfs_lock_inodes(ips, 2, 0, XFS_ILOCK_EXCL);
+ xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL);
/*
* Increment vnode ref counts since xfs_trans_commit &
@@ -2840,7 +2671,6 @@
struct xfs_name *name,
xfs_inode_t *cdp)
{
- bhv_vnode_t *dir_vp = XFS_ITOV(dp);
xfs_mount_t *mp = dp->i_mount;
xfs_trans_t *tp;
int error;
@@ -2866,27 +2696,12 @@
}
/*
- * We need to get a reference to cdp before we get our log
- * reservation. The reason for this is that we cannot call
- * xfs_iget for an inode for which we do not have a reference
- * once we've acquired a log reservation. This is because the
- * inode we are trying to get might be in xfs_inactive going
- * for a log reservation. Since we'll have to wait for the
- * inactive code to complete before returning from xfs_iget,
- * we need to make sure that we don't have log space reserved
- * when we call xfs_iget. Instead we get an unlocked reference
- * to the inode before getting our log reservation.
- */
- IHOLD(cdp);
-
- /*
* Get the dquots for the inodes.
*/
error = XFS_QM_DQATTACH(mp, dp, 0);
- if (!error && dp != cdp)
+ if (!error)
error = XFS_QM_DQATTACH(mp, cdp, 0);
if (error) {
- IRELE(cdp);
REMOVE_DEBUG_TRACE(__LINE__);
goto std_return;
}
@@ -2913,7 +2728,6 @@
if (error) {
ASSERT(error != ENOSPC);
cancel_flags = 0;
- IRELE(cdp);
goto error_return;
}
XFS_BMAP_INIT(&free_list, &first_block);
@@ -2927,21 +2741,13 @@
error = xfs_lock_dir_and_entry(dp, cdp);
if (error) {
xfs_trans_cancel(tp, cancel_flags);
- IRELE(cdp);
goto std_return;
}
+ IHOLD(dp);
xfs_trans_ijoin(tp, dp, XFS_ILOCK_EXCL);
- if (dp != cdp) {
- /*
- * Only increment the parent directory vnode count if
- * we didn't bump it in looking up cdp. The only time
- * we don't bump it is when we're looking up ".".
- */
- VN_HOLD(dir_vp);
- }
- xfs_itrace_ref(cdp);
+ IHOLD(cdp);
xfs_trans_ijoin(tp, cdp, XFS_ILOCK_EXCL);
ASSERT(cdp->i_d.di_nlink >= 2);
@@ -2995,12 +2801,6 @@
last_cdp_link = (cdp)->i_d.di_nlink==0;
/*
- * Take an extra ref on the child vnode so that it
- * does not go to xfs_inactive() from within the commit.
- */
- IHOLD(cdp);
-
- /*
* If this is a synchronous mount, make sure that the
* rmdir transaction goes to disk before returning to
* the user.
@@ -3014,19 +2814,15 @@
xfs_bmap_cancel(&free_list);
xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES |
XFS_TRANS_ABORT));
- IRELE(cdp);
goto std_return;
}
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES);
if (error) {
- IRELE(cdp);
goto std_return;
}
- IRELE(cdp);
-
/* Fall through to std_return with error = 0 or the errno
* from xfs_trans_commit. */
std_return:
diff --git a/fs/xfs/xfs_vnodeops.h b/fs/xfs/xfs_vnodeops.h
index 24c5392..8abe8f1 100644
--- a/fs/xfs/xfs_vnodeops.h
+++ b/fs/xfs/xfs_vnodeops.h
@@ -15,7 +15,6 @@
int xfs_open(struct xfs_inode *ip);
-int xfs_getattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags);
int xfs_setattr(struct xfs_inode *ip, struct bhv_vattr *vap, int flags,
struct cred *credp);
int xfs_readlink(struct xfs_inode *ip, char *link);
@@ -48,9 +47,9 @@
struct cred *credp, int attr_flags);
int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name,
struct xfs_inode *src_ip, struct xfs_inode *target_dp,
- struct xfs_name *target_name);
+ struct xfs_name *target_name, struct xfs_inode *target_ip);
int xfs_attr_get(struct xfs_inode *ip, const char *name, char *value,
- int *valuelenp, int flags, cred_t *cred);
+ int *valuelenp, int flags);
int xfs_attr_set(struct xfs_inode *dp, const char *name, char *value,
int valuelen, int flags);
int xfs_attr_remove(struct xfs_inode *dp, const char *name, int flags);
@@ -61,9 +60,6 @@
ssize_t xfs_read(struct xfs_inode *ip, struct kiocb *iocb,
const struct iovec *iovp, unsigned int segs,
loff_t *offset, int ioflags);
-ssize_t xfs_sendfile(struct xfs_inode *ip, struct file *filp,
- loff_t *offset, int ioflags, size_t count,
- read_actor_t actor, void *target);
ssize_t xfs_splice_read(struct xfs_inode *ip, struct file *infilp,
loff_t *ppos, struct pipe_inode_info *pipe, size_t count,
int flags, int ioflags);
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index 422f29c..28fe8ba 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -63,7 +63,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20070126
+#define ACPI_CA_VERSION 0x20080321
/*
* OS name, used for the _OS object. The _OS object is essentially obsolete,
@@ -150,6 +150,17 @@
#define ACPI_OBJ_NUM_OPERANDS 8
#define ACPI_OBJ_MAX_OPERAND 7
+/* Number of elements in the Result Stack frame, can be an arbitrary value */
+
+#define ACPI_RESULTS_FRAME_OBJ_NUM 8
+
+/*
+ * Maximal number of elements the Result Stack can contain,
+ * it may be an arbitray value not exceeding the types of
+ * result_size and result_count (now u8).
+ */
+#define ACPI_RESULTS_OBJ_NUM_MAX 255
+
/* Names within the namespace are 4 bytes long */
#define ACPI_NAME_SIZE 4
diff --git a/include/acpi/acdebug.h b/include/acpi/acdebug.h
index d626bb1..c5a1b50 100644
--- a/include/acpi/acdebug.h
+++ b/include/acpi/acdebug.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
index 389d772..788f887 100644
--- a/include/acpi/acdisasm.h
+++ b/include/acpi/acdisasm.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -97,19 +97,23 @@
#define ACPI_DMT_CHKSUM 20
#define ACPI_DMT_SPACEID 21
#define ACPI_DMT_GAS 22
-#define ACPI_DMT_DMAR 23
-#define ACPI_DMT_MADT 24
-#define ACPI_DMT_SRAT 25
-#define ACPI_DMT_EXIT 26
-#define ACPI_DMT_SIG 27
+#define ACPI_DMT_ASF 23
+#define ACPI_DMT_DMAR 24
+#define ACPI_DMT_HEST 25
+#define ACPI_DMT_HESTNTFY 26
+#define ACPI_DMT_HESTNTYP 27
+#define ACPI_DMT_MADT 28
+#define ACPI_DMT_SRAT 29
+#define ACPI_DMT_EXIT 30
+#define ACPI_DMT_SIG 31
typedef
-void (*ACPI_TABLE_HANDLER) (struct acpi_table_header * table);
+void (*acpi_dmtable_handler) (struct acpi_table_header * table);
struct acpi_dmtable_data {
char *signature;
struct acpi_dmtable_info *table_info;
- ACPI_TABLE_HANDLER table_handler;
+ acpi_dmtable_handler table_handler;
char *name;
};
@@ -149,6 +153,7 @@
extern struct acpi_dmtable_info acpi_dm_table_info_asf4[];
extern struct acpi_dmtable_info acpi_dm_table_info_asf_hdr[];
extern struct acpi_dmtable_info acpi_dm_table_info_boot[];
+extern struct acpi_dmtable_info acpi_dm_table_info_bert[];
extern struct acpi_dmtable_info acpi_dm_table_info_cpep[];
extern struct acpi_dmtable_info acpi_dm_table_info_cpep0[];
extern struct acpi_dmtable_info acpi_dm_table_info_dbgp[];
@@ -158,11 +163,17 @@
extern struct acpi_dmtable_info acpi_dm_table_info_dmar0[];
extern struct acpi_dmtable_info acpi_dm_table_info_dmar1[];
extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[];
+extern struct acpi_dmtable_info acpi_dm_table_info_einj[];
+extern struct acpi_dmtable_info acpi_dm_table_info_einj0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_erst[];
extern struct acpi_dmtable_info acpi_dm_table_info_facs[];
extern struct acpi_dmtable_info acpi_dm_table_info_fadt1[];
extern struct acpi_dmtable_info acpi_dm_table_info_fadt2[];
extern struct acpi_dmtable_info acpi_dm_table_info_gas[];
extern struct acpi_dmtable_info acpi_dm_table_info_header[];
+extern struct acpi_dmtable_info acpi_dm_table_info_hest[];
+extern struct acpi_dmtable_info acpi_dm_table_info_hest9[];
+extern struct acpi_dmtable_info acpi_dm_table_info_hest_notify[];
extern struct acpi_dmtable_info acpi_dm_table_info_hpet[];
extern struct acpi_dmtable_info acpi_dm_table_info_madt[];
extern struct acpi_dmtable_info acpi_dm_table_info_madt0[];
@@ -180,6 +191,7 @@
extern struct acpi_dmtable_info acpi_dm_table_info_rsdp1[];
extern struct acpi_dmtable_info acpi_dm_table_info_rsdp2[];
extern struct acpi_dmtable_info acpi_dm_table_info_sbst[];
+extern struct acpi_dmtable_info acpi_dm_table_info_slic[];
extern struct acpi_dmtable_info acpi_dm_table_info_slit[];
extern struct acpi_dmtable_info acpi_dm_table_info_spcr[];
extern struct acpi_dmtable_info acpi_dm_table_info_spmi[];
@@ -194,7 +206,7 @@
*/
void acpi_dm_dump_data_table(struct acpi_table_header *table);
-void
+acpi_status
acpi_dm_dump_table(u32 table_length,
u32 table_offset,
void *table,
@@ -213,9 +225,13 @@
void acpi_dm_dump_dmar(struct acpi_table_header *table);
+void acpi_dm_dump_einj(struct acpi_table_header *table);
+
+void acpi_dm_dump_erst(struct acpi_table_header *table);
+
void acpi_dm_dump_fadt(struct acpi_table_header *table);
-void acpi_dm_dump_srat(struct acpi_table_header *table);
+void acpi_dm_dump_hest(struct acpi_table_header *table);
void acpi_dm_dump_mcfg(struct acpi_table_header *table);
@@ -227,6 +243,8 @@
void acpi_dm_dump_slit(struct acpi_table_header *table);
+void acpi_dm_dump_srat(struct acpi_table_header *table);
+
void acpi_dm_dump_xsdt(struct acpi_table_header *table);
/*
diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h
index 7f690bb..910f018 100644
--- a/include/acpi/acdispat.h
+++ b/include/acpi/acdispat.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -53,6 +53,9 @@
acpi_status
acpi_ds_get_buffer_field_arguments(union acpi_operand_object *obj_desc);
+acpi_status
+acpi_ds_get_bank_field_arguments(union acpi_operand_object *obj_desc);
+
acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *rgn_desc);
acpi_status acpi_ds_get_buffer_arguments(union acpi_operand_object *obj_desc);
@@ -68,10 +71,18 @@
union acpi_parse_object *op);
acpi_status
+acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+acpi_status
acpi_ds_eval_data_object_operands(struct acpi_walk_state *walk_state,
union acpi_parse_object *op,
union acpi_operand_object *obj_desc);
+acpi_status
+acpi_ds_eval_bank_field_operands(struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
acpi_status acpi_ds_initialize_region(acpi_handle obj_handle);
/*
@@ -269,6 +280,8 @@
void acpi_ds_clear_operands(struct acpi_walk_state *walk_state);
+acpi_status acpi_ds_evaluate_name_path(struct acpi_walk_state *walk_state);
+
/*
* dswscope - Scope Stack manipulation
*/
@@ -303,7 +316,7 @@
u32 aml_length,
struct acpi_evaluate_info *info, u8 pass_number);
-acpi_status
+void
acpi_ds_obj_stack_pop_and_delete(u32 pop_count,
struct acpi_walk_state *walk_state);
@@ -316,21 +329,11 @@
acpi_ds_push_walk_state(struct acpi_walk_state *walk_state,
struct acpi_thread_state *thread);
-acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state);
-
-acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state);
-
acpi_status acpi_ds_result_stack_clear(struct acpi_walk_state *walk_state);
struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state
*thread);
-#ifdef ACPI_FUTURE_USAGE
-acpi_status
-acpi_ds_result_remove(union acpi_operand_object **object,
- u32 index, struct acpi_walk_state *walk_state);
-#endif
-
acpi_status
acpi_ds_result_pop(union acpi_operand_object **object,
struct acpi_walk_state *walk_state);
@@ -339,8 +342,4 @@
acpi_ds_result_push(union acpi_operand_object *object,
struct acpi_walk_state *walk_state);
-acpi_status
-acpi_ds_result_pop_from_bottom(union acpi_operand_object **object,
- struct acpi_walk_state *walk_state);
-
#endif /* _ACDISPAT_H_ */
diff --git a/include/acpi/acevents.h b/include/acpi/acevents.h
index d23cdf3..d5d099b 100644
--- a/include/acpi/acevents.h
+++ b/include/acpi/acevents.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index b73f18a..1f59117 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index 47a1fd8..74ad971 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -170,10 +170,14 @@
ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
/*
- * Global lock semaphore works in conjunction with the actual HW global lock
+ * Global lock mutex is an actual AML mutex object
+ * Global lock semaphore works in conjunction with the HW global lock
*/
-ACPI_EXTERN acpi_mutex acpi_gbl_global_lock_mutex;
+ACPI_EXTERN union acpi_operand_object *acpi_gbl_global_lock_mutex;
ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
+ACPI_EXTERN u16 acpi_gbl_global_lock_handle;
+ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
+ACPI_EXTERN u8 acpi_gbl_global_lock_present;
/*
* Spinlocks are used for interfaces that can be possibly called at
@@ -213,27 +217,33 @@
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify;
ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
+ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
+ACPI_EXTERN void *acpi_gbl_table_handler_context;
ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
+/* Owner ID support */
+
+ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS];
+ACPI_EXTERN u8 acpi_gbl_last_owner_id_index;
+ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset;
+
/* Misc */
ACPI_EXTERN u32 acpi_gbl_original_mode;
ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
ACPI_EXTERN u32 acpi_gbl_ps_find_count;
-ACPI_EXTERN u32 acpi_gbl_owner_id_mask[ACPI_NUM_OWNERID_MASKS];
ACPI_EXTERN u16 acpi_gbl_pm1_enable_register_save;
-ACPI_EXTERN u16 acpi_gbl_global_lock_handle;
-ACPI_EXTERN u8 acpi_gbl_last_owner_id_index;
-ACPI_EXTERN u8 acpi_gbl_next_owner_id_offset;
ACPI_EXTERN u8 acpi_gbl_debugger_configuration;
-ACPI_EXTERN u8 acpi_gbl_global_lock_acquired;
ACPI_EXTERN u8 acpi_gbl_step_to_next_call;
ACPI_EXTERN u8 acpi_gbl_acpi_hardware_present;
-ACPI_EXTERN u8 acpi_gbl_global_lock_present;
ACPI_EXTERN u8 acpi_gbl_events_initialized;
ACPI_EXTERN u8 acpi_gbl_system_awake_and_running;
+#ifndef DEFINE_ACPI_GLOBALS
+
+/* Other miscellaneous */
+
extern u8 acpi_gbl_shutdown;
extern u32 acpi_gbl_startup_flags;
extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
@@ -241,6 +251,8 @@
extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
+#endif
+
/* Exception codes */
extern char const *acpi_gbl_exception_names_env[];
@@ -255,8 +267,6 @@
*
****************************************************************************/
-#define NUM_NS_TYPES ACPI_TYPE_INVALID+1
-
#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
#define NUM_PREDEFINED_NAMES 10
#else
@@ -267,7 +277,7 @@
ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_root_node;
ACPI_EXTERN struct acpi_namespace_node *acpi_gbl_fadt_gpe_device;
-extern const u8 acpi_gbl_ns_properties[NUM_NS_TYPES];
+extern const u8 acpi_gbl_ns_properties[ACPI_NUM_NS_TYPES];
extern const struct acpi_predefined_names
acpi_gbl_pre_defined_names[NUM_PREDEFINED_NAMES];
@@ -275,8 +285,8 @@
ACPI_EXTERN u32 acpi_gbl_current_node_count;
ACPI_EXTERN u32 acpi_gbl_current_node_size;
ACPI_EXTERN u32 acpi_gbl_max_concurrent_node_count;
-ACPI_EXTERN acpi_size acpi_gbl_entry_stack_pointer;
-ACPI_EXTERN acpi_size acpi_gbl_lowest_stack_pointer;
+ACPI_EXTERN acpi_size *acpi_gbl_entry_stack_pointer;
+ACPI_EXTERN acpi_size *acpi_gbl_lowest_stack_pointer;
ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
#endif
diff --git a/include/acpi/achware.h b/include/acpi/achware.h
index 4053df9..d4fb9bb 100644
--- a/include/acpi/achware.h
+++ b/include/acpi/achware.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h
index ce7c9d6..e249ce5 100644
--- a/include/acpi/acinterp.h
+++ b/include/acpi/acinterp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -215,8 +215,6 @@
u32 aml_length,
u8 region_space, struct acpi_walk_state *walk_state);
-acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state);
-
acpi_status acpi_ex_create_event(struct acpi_walk_state *walk_state);
acpi_status acpi_ex_create_alias(struct acpi_walk_state *walk_state);
@@ -248,9 +246,16 @@
struct acpi_walk_state *walk_state);
acpi_status
+acpi_ex_acquire_mutex_object(u16 timeout,
+ union acpi_operand_object *obj_desc,
+ acpi_thread_id thread_id);
+
+acpi_status
acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state);
+acpi_status acpi_ex_release_mutex_object(union acpi_operand_object *obj_desc);
+
void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread);
void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc);
@@ -455,9 +460,9 @@
void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
-u8 acpi_ex_acquire_global_lock(u32 rule);
+void acpi_ex_acquire_global_lock(u32 rule);
-void acpi_ex_release_global_lock(u8 locked);
+void acpi_ex_release_global_lock(u32 rule);
void acpi_ex_eisa_id_to_string(u32 numeric_id, char *out_string);
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index 202cd42..c5cdc32 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -522,9 +522,8 @@
* AML arguments
*/
struct acpi_result_values {
- ACPI_STATE_COMMON u8 num_results;
- u8 last_insert;
- union acpi_operand_object *obj_desc[ACPI_OBJ_NUM_OPERANDS];
+ ACPI_STATE_COMMON
+ union acpi_operand_object *obj_desc[ACPI_RESULTS_FRAME_OBJ_NUM];
};
typedef
@@ -604,6 +603,7 @@
union acpi_parse_object *next; /* Next op */\
struct acpi_namespace_node *node; /* For use by interpreter */\
union acpi_parse_value value; /* Value or args associated with the opcode */\
+ u8 arg_list_length; /* Number of elements in the arg list */\
ACPI_DISASM_ONLY_MEMBERS (\
u8 disasm_flags; /* Used during AML disassembly */\
u8 disasm_opcode; /* Subtype used for disassembly */\
@@ -696,6 +696,8 @@
#define ACPI_PARSEOP_NAMED 0x02
#define ACPI_PARSEOP_DEFERRED 0x04
#define ACPI_PARSEOP_BYTELIST 0x08
+#define ACPI_PARSEOP_IN_STACK 0x10
+#define ACPI_PARSEOP_TARGET 0x20
#define ACPI_PARSEOP_IN_CACHE 0x80
/* Parse object disasm_flags */
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index 99d171c..fb41a3b 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,30 +61,6 @@
#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0]))
-#ifdef ACPI_NO_INTEGER64_SUPPORT
-/*
- * acpi_integer is 32-bits, no 64-bit support on this platform
- */
-#define ACPI_LODWORD(l) ((u32)(l))
-#define ACPI_HIDWORD(l) ((u32)(0))
-
-#else
-
-/*
- * Full 64-bit address/integer on both 32-bit and 64-bit platforms
- */
-#define ACPI_LODWORD(l) ((u32)(u64)(l))
-#define ACPI_HIDWORD(l) ((u32)(((*(struct uint64_struct *)(void *)(&l))).hi))
-#endif
-
-/*
- * printf() format helpers
- */
-
-/* Split 64-bit integer into two 32-bit values. Use with %8.8_x%8.8_x */
-
-#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i)
-
/*
* Extract data using a pointer. Any more than a byte and we
* get into potential aligment issues -- see the STORE macros below.
@@ -122,6 +98,31 @@
#endif
/*
+ * Full 64-bit integer must be available on both 32-bit and 64-bit platforms
+ */
+struct acpi_integer_overlay {
+ u32 lo_dword;
+ u32 hi_dword;
+};
+
+#define ACPI_LODWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->lo_dword)
+#define ACPI_HIDWORD(integer) (ACPI_CAST_PTR (struct acpi_integer_overlay, &integer)->hi_dword)
+
+/*
+ * printf() format helpers
+ */
+
+/* Split 64-bit integer into two 32-bit values. Use with %8.8_x%8.8_x */
+
+#define ACPI_FORMAT_UINT64(i) ACPI_HIDWORD(i),ACPI_LODWORD(i)
+
+#if ACPI_MACHINE_WIDTH == 64
+#define ACPI_FORMAT_NATIVE_UINT(i) ACPI_FORMAT_UINT64(i)
+#else
+#define ACPI_FORMAT_NATIVE_UINT(i) 0, (i)
+#endif
+
+/*
* Macros for moving data around to/from buffers that are possibly unaligned.
* If the hardware supports the transfer of unaligned data, just do the store.
* Otherwise, we have to move one byte at a time.
@@ -137,29 +138,29 @@
/* These macros reverse the bytes during the move, converting little-endian to big endian */
- /* Big Endian <== Little Endian */
- /* Hi...Lo Lo...Hi */
+ /* Big Endian <== Little Endian */
+ /* Hi...Lo Lo...Hi */
/* 16-bit source, 16/32/64 destination */
#define ACPI_MOVE_16_TO_16(d,s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[1];\
- (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];}
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[0];}
#define ACPI_MOVE_16_TO_32(d,s) {(*(u32 *)(void *)(d))=0;\
- ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
- ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
+ ((u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
+ ((u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
#define ACPI_MOVE_16_TO_64(d,s) {(*(u64 *)(void *)(d))=0;\
- ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\
- ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];}
+ ((u8 *)(void *)(d))[6] = ((u8 *)(void *)(s))[1];\
+ ((u8 *)(void *)(d))[7] = ((u8 *)(void *)(s))[0];}
/* 32-bit source, 16/32/64 destination */
#define ACPI_MOVE_32_TO_16(d,s) ACPI_MOVE_16_TO_16(d,s) /* Truncate to 16 */
#define ACPI_MOVE_32_TO_32(d,s) {(( u8 *)(void *)(d))[0] = ((u8 *)(void *)(s))[3];\
- (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\
- (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
- (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
+ (( u8 *)(void *)(d))[1] = ((u8 *)(void *)(s))[2];\
+ (( u8 *)(void *)(d))[2] = ((u8 *)(void *)(s))[1];\
+ (( u8 *)(void *)(d))[3] = ((u8 *)(void *)(s))[0];}
#define ACPI_MOVE_32_TO_64(d,s) {(*(u64 *)(void *)(d))=0;\
((u8 *)(void *)(d))[4] = ((u8 *)(void *)(s))[3];\
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h
index 34bfae8..c1343a9 100644
--- a/include/acpi/acnames.h
+++ b/include/acpi/acnames.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h
index 5ef38a6..713b309 100644
--- a/include/acpi/acnamesp.h
+++ b/include/acpi/acnamesp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -113,7 +113,8 @@
acpi_status
acpi_ns_one_complete_parse(acpi_native_uint pass_number,
- acpi_native_uint table_index);
+ acpi_native_uint table_index,
+ struct acpi_namespace_node *start_node);
/*
* nsaccess - Top-level namespace access
diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h
index 7e1211a..e9657da 100644
--- a/include/acpi/acobject.h
+++ b/include/acpi/acobject.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -155,8 +155,9 @@
struct acpi_object_mutex {
ACPI_OBJECT_COMMON_HEADER u8 sync_level; /* 0-15, specified in Mutex() call */
u16 acquisition_depth; /* Allow multiple Acquires, same thread */
- struct acpi_thread_state *owner_thread; /* Current owner of the mutex */
acpi_mutex os_mutex; /* Actual OS synchronization object */
+ acpi_thread_id thread_id; /* Current owner of the mutex */
+ struct acpi_thread_state *owner_thread; /* Current owner of the mutex */
union acpi_operand_object *prev; /* Link for list of acquired mutexes */
union acpi_operand_object *next; /* Link for list of acquired mutexes */
struct acpi_namespace_node *node; /* Containing namespace node */
diff --git a/include/acpi/acopcode.h b/include/acpi/acopcode.h
index e6f76a2..dfdf633 100644
--- a/include/acpi/acopcode.h
+++ b/include/acpi/acopcode.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -233,7 +233,7 @@
#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING)
#define ARGI_DEBUG_OP ARG_NONE
-#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
+#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_TARGETREF)
#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING)
#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE
#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF)
@@ -246,7 +246,7 @@
#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET)
#define ARGI_IF_OP ARGI_INVALID_OPCODE
-#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
+#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_TARGETREF)
#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE
#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF)
#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h
index c090a8b..e17873d 100644
--- a/include/acpi/acoutput.h
+++ b/include/acpi/acoutput.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h
index 85c358e..23ee0fb 100644
--- a/include/acpi/acparser.h
+++ b/include/acpi/acparser.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -109,6 +109,8 @@
char *acpi_ps_get_opcode_name(u16 opcode);
+u8 acpi_ps_get_argument_count(u32 op_type);
+
/*
* psparse - top level parsing routines
*/
diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h
index 2e5f00d..c515ef6 100644
--- a/include/acpi/acpi.h
+++ b/include/acpi/acpi.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 4839f2a..d4a560d 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -8,7 +8,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index d970f7f..2c3806e 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -119,6 +119,11 @@
acpi_get_table_by_index(acpi_native_uint table_index,
struct acpi_table_header **out_table);
+acpi_status
+acpi_install_table_handler(acpi_tbl_handler handler, void *context);
+
+acpi_status acpi_remove_table_handler(acpi_tbl_handler handler);
+
/*
* Namespace and name interfaces
*/
diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h
index 9486ab2..eef5bd7 100644
--- a/include/acpi/acresrc.h
+++ b/include/acpi/acresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -94,6 +94,7 @@
#define ACPI_RSC_BITMASK16 18
#define ACPI_RSC_EXIT_NE 19
#define ACPI_RSC_EXIT_LE 20
+#define ACPI_RSC_EXIT_EQ 21
/* Resource Conversion sub-opcodes */
diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h
index 8848265..a907c67 100644
--- a/include/acpi/acstruct.h
+++ b/include/acpi/acstruct.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -80,12 +80,15 @@
u16 opcode; /* Current AML opcode */
u8 next_op_info; /* Info about next_op */
u8 num_operands; /* Stack pointer for Operands[] array */
+ u8 operand_index; /* Index into operand stack, to be used by acpi_ds_obj_stack_push */
acpi_owner_id owner_id; /* Owner of objects created during the walk */
u8 last_predicate; /* Result of last predicate */
u8 current_result;
u8 return_used;
u8 scope_depth;
u8 pass_number; /* Parse pass during table load */
+ u8 result_size; /* Total elements for the result stack */
+ u8 result_count; /* Current number of occupied elements of result stack */
u32 aml_offset;
u32 arg_types;
u32 method_breakpoint; /* For single stepping */
diff --git a/include/acpi/actables.h b/include/acpi/actables.h
index 2b9f46f..4b36a55 100644
--- a/include/acpi/actables.h
+++ b/include/acpi/actables.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 955adfb..1ebbe88 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/actbl1.h b/include/acpi/actbl1.h
index a1b1b2e..9af239b 100644
--- a/include/acpi/actbl1.h
+++ b/include/acpi/actbl1.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -58,20 +58,28 @@
* it more difficult to inadvertently type in the wrong signature.
*/
#define ACPI_SIG_ASF "ASF!" /* Alert Standard Format table */
+#define ACPI_SIG_BERT "BERT" /* Boot Error Record Table */
#define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */
#define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */
#define ACPI_SIG_DBGP "DBGP" /* Debug Port table */
#define ACPI_SIG_DMAR "DMAR" /* DMA Remapping table */
#define ACPI_SIG_ECDT "ECDT" /* Embedded Controller Boot Resources Table */
+#define ACPI_SIG_EINJ "EINJ" /* Error Injection table */
+#define ACPI_SIG_ERST "ERST" /* Error Record Serialization Table */
+#define ACPI_SIG_HEST "HEST" /* Hardware Error Source Table */
#define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */
+#define ACPI_SIG_IBFT "IBFT" /* i_sCSI Boot Firmware Table */
#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */
#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */
#define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */
+#define ACPI_SIG_SLIC "SLIC" /* Software Licensing Description Table */
#define ACPI_SIG_SLIT "SLIT" /* System Locality Distance Information Table */
#define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */
#define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */
#define ACPI_SIG_SRAT "SRAT" /* System Resource Affinity Table */
#define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */
+#define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */
+#define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */
#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */
/*
@@ -86,13 +94,25 @@
* portable, so do not use any other bitfield types.
*/
-/* Common Sub-table header (used in MADT, SRAT, etc.) */
+/* Common Subtable header (used in MADT, SRAT, etc.) */
struct acpi_subtable_header {
u8 type;
u8 length;
};
+/* Common Subtable header for WHEA tables (EINJ, ERST, WDAT) */
+
+struct acpi_whea_header {
+ u8 action;
+ u8 instruction;
+ u8 flags;
+ u8 reserved;
+ struct acpi_generic_address register_region;
+ u64 value; /* Value used with Read/Write register */
+ u64 mask; /* Bitmask required for this register instruction */
+};
+
/*******************************************************************************
*
* ASF - Alert Standard Format table (Signature "ASF!")
@@ -204,6 +224,35 @@
/*******************************************************************************
*
+ * BERT - Boot Error Record Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_bert {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 region_length; /* Length of the boot error region */
+ u64 address; /* Physical addresss of the error region */
+};
+
+/* Boot Error Region */
+
+struct acpi_bert_region {
+ u32 block_status;
+ u32 raw_data_offset;
+ u32 raw_data_length;
+ u32 data_length;
+ u32 error_severity;
+};
+
+/* block_status Flags */
+
+#define ACPI_BERT_UNCORRECTABLE (1)
+#define ACPI_BERT_CORRECTABLE (2)
+#define ACPI_BERT_MULTIPLE_UNCORRECTABLE (4)
+#define ACPI_BERT_MULTIPLE_CORRECTABLE (8)
+
+/*******************************************************************************
+ *
* BOOT - Simple Boot Flag Table
*
******************************************************************************/
@@ -350,6 +399,352 @@
/*******************************************************************************
*
+ * EINJ - Error Injection Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_einj {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 header_length;
+ u32 reserved;
+ u32 entries;
+};
+
+/* EINJ Injection Instruction Entries (actions) */
+
+struct acpi_einj_entry {
+ struct acpi_whea_header whea_header; /* Common header for WHEA tables */
+};
+
+/* Values for Action field above */
+
+enum acpi_einj_actions {
+ ACPI_EINJ_BEGIN_OPERATION = 0,
+ ACPI_EINJ_GET_TRIGGER_TABLE = 1,
+ ACPI_EINJ_SET_ERROR_TYPE = 2,
+ ACPI_EINJ_GET_ERROR_TYPE = 3,
+ ACPI_EINJ_END_OPERATION = 4,
+ ACPI_EINJ_EXECUTE_OPERATION = 5,
+ ACPI_EINJ_CHECK_BUSY_STATUS = 6,
+ ACPI_EINJ_GET_COMMAND_STATUS = 7,
+ ACPI_EINJ_ACTION_RESERVED = 8, /* 8 and greater are reserved */
+ ACPI_EINJ_TRIGGER_ERROR = 0xFF /* Except for this value */
+};
+
+/* Values for Instruction field above */
+
+enum acpi_einj_instructions {
+ ACPI_EINJ_READ_REGISTER = 0,
+ ACPI_EINJ_READ_REGISTER_VALUE = 1,
+ ACPI_EINJ_WRITE_REGISTER = 2,
+ ACPI_EINJ_WRITE_REGISTER_VALUE = 3,
+ ACPI_EINJ_NOOP = 4,
+ ACPI_EINJ_INSTRUCTION_RESERVED = 5 /* 5 and greater are reserved */
+};
+
+/* EINJ Trigger Error Action Table */
+
+struct acpi_einj_trigger {
+ u32 header_size;
+ u32 revision;
+ u32 table_size;
+ u32 entry_count;
+};
+
+/*******************************************************************************
+ *
+ * ERST - Error Record Serialization Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_erst {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 header_length;
+ u32 reserved;
+ u32 entries;
+};
+
+/* ERST Serialization Entries (actions) */
+
+struct acpi_erst_entry {
+ struct acpi_whea_header whea_header; /* Common header for WHEA tables */
+};
+
+/* Values for Action field above */
+
+enum acpi_erst_actions {
+ ACPI_ERST_BEGIN_WRITE_OPERATION = 0,
+ ACPI_ERST_BEGIN_READ_OPERATION = 1,
+ ACPI_ERST_BETGIN_CLEAR_OPERATION = 2,
+ ACPI_ERST_END_OPERATION = 3,
+ ACPI_ERST_SET_RECORD_OFFSET = 4,
+ ACPI_ERST_EXECUTE_OPERATION = 5,
+ ACPI_ERST_CHECK_BUSY_STATUS = 6,
+ ACPI_ERST_GET_COMMAND_STATUS = 7,
+ ACPI_ERST_GET_RECORD_IDENTIFIER = 8,
+ ACPI_ERST_SET_RECORD_IDENTIFIER = 9,
+ ACPI_ERST_GET_RECORD_COUNT = 10,
+ ACPI_ERST_BEGIN_DUMMY_WRIITE = 11,
+ ACPI_ERST_NOT_USED = 12,
+ ACPI_ERST_GET_ERROR_RANGE = 13,
+ ACPI_ERST_GET_ERROR_LENGTH = 14,
+ ACPI_ERST_GET_ERROR_ATTRIBUTES = 15,
+ ACPI_ERST_ACTION_RESERVED = 16 /* 16 and greater are reserved */
+};
+
+/* Values for Instruction field above */
+
+enum acpi_erst_instructions {
+ ACPI_ERST_READ_REGISTER = 0,
+ ACPI_ERST_READ_REGISTER_VALUE = 1,
+ ACPI_ERST_WRITE_REGISTER = 2,
+ ACPI_ERST_WRITE_REGISTER_VALUE = 3,
+ ACPI_ERST_NOOP = 4,
+ ACPI_ERST_LOAD_VAR1 = 5,
+ ACPI_ERST_LOAD_VAR2 = 6,
+ ACPI_ERST_STORE_VAR1 = 7,
+ ACPI_ERST_ADD = 8,
+ ACPI_ERST_SUBTRACT = 9,
+ ACPI_ERST_ADD_VALUE = 10,
+ ACPI_ERST_SUBTRACT_VALUE = 11,
+ ACPI_ERST_STALL = 12,
+ ACPI_ERST_STALL_WHILE_TRUE = 13,
+ ACPI_ERST_SKIP_NEXT_IF_TRUE = 14,
+ ACPI_ERST_GOTO = 15,
+ ACPI_ERST_SET_SRC_ADDRESS_BASE = 16,
+ ACPI_ERST_SET_DST_ADDRESS_BASE = 17,
+ ACPI_ERST_MOVE_DATA = 18,
+ ACPI_ERST_INSTRUCTION_RESERVED = 19 /* 19 and greater are reserved */
+};
+
+/*******************************************************************************
+ *
+ * HEST - Hardware Error Source Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_hest {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 error_source_count;
+};
+
+/* HEST subtable header */
+
+struct acpi_hest_header {
+ u16 type;
+};
+
+/* Values for Type field above for subtables */
+
+enum acpi_hest_types {
+ ACPI_HEST_TYPE_XPF_MACHINE_CHECK = 0,
+ ACPI_HEST_TYPE_XPF_CORRECTED_MACHINE_CHECK = 1,
+ ACPI_HEST_TYPE_XPF_UNUSED = 2,
+ ACPI_HEST_TYPE_XPF_NON_MASKABLE_INTERRUPT = 3,
+ ACPI_HEST_TYPE_IPF_CORRECTED_MACHINE_CHECK = 4,
+ ACPI_HEST_TYPE_IPF_CORRECTED_PLATFORM_ERROR = 5,
+ ACPI_HEST_TYPE_AER_ROOT_PORT = 6,
+ ACPI_HEST_TYPE_AER_ENDPOINT = 7,
+ ACPI_HEST_TYPE_AER_BRIDGE = 8,
+ ACPI_HEST_TYPE_GENERIC_HARDWARE_ERROR_SOURCE = 9,
+ ACPI_HEST_TYPE_RESERVED = 10 /* 10 and greater are reserved */
+};
+
+/*
+ * HEST Sub-subtables
+ */
+
+/* XPF Machine Check Error Bank */
+
+struct acpi_hest_xpf_error_bank {
+ u8 bank_number;
+ u8 clear_status_on_init;
+ u8 status_format;
+ u8 config_write_enable;
+ u32 control_register;
+ u64 control_init_data;
+ u32 status_register;
+ u32 address_register;
+ u32 misc_register;
+};
+
+/* Generic Error Status */
+
+struct acpi_hest_generic_status {
+ u32 block_status;
+ u32 raw_data_offset;
+ u32 raw_data_length;
+ u32 data_length;
+ u32 error_severity;
+};
+
+/* Generic Error Data */
+
+struct acpi_hest_generic_data {
+ u8 section_type[16];
+ u32 error_severity;
+ u16 revision;
+ u8 validation_bits;
+ u8 flags;
+ u32 error_data_length;
+ u8 fru_id[16];
+ u8 fru_text[20];
+};
+
+/* Common HEST structure for PCI/AER types below (6,7,8) */
+
+struct acpi_hest_aer_common {
+ u16 source_id;
+ u16 config_write_enable;
+ u8 flags;
+ u8 enabled;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ u32 bus;
+ u16 device;
+ u16 function;
+ u16 device_control;
+ u16 reserved;
+ u32 uncorrectable_error_mask;
+ u32 uncorrectable_error_severity;
+ u32 correctable_error_mask;
+ u32 advanced_error_cababilities;
+};
+
+/* Hardware Error Notification */
+
+struct acpi_hest_notify {
+ u8 type;
+ u8 length;
+ u16 config_write_enable;
+ u32 poll_interval;
+ u32 vector;
+ u32 polling_threshold_value;
+ u32 polling_threshold_window;
+ u32 error_threshold_value;
+ u32 error_threshold_window;
+};
+
+/* Values for Notify Type field above */
+
+enum acpi_hest_notify_types {
+ ACPI_HEST_NOTIFY_POLLED = 0,
+ ACPI_HEST_NOTIFY_EXTERNAL = 1,
+ ACPI_HEST_NOTIFY_LOCAL = 2,
+ ACPI_HEST_NOTIFY_SCI = 3,
+ ACPI_HEST_NOTIFY_NMI = 4,
+ ACPI_HEST_NOTIFY_RESERVED = 5 /* 5 and greater are reserved */
+};
+
+/*
+ * HEST subtables
+ *
+ * From WHEA Design Document, 16 May 2007.
+ * Note: There is no subtable type 2 in this version of the document,
+ * and there are two different subtable type 3s.
+ */
+
+ /* 0: XPF Machine Check Exception */
+
+struct acpi_hest_xpf_machine_check {
+ struct acpi_hest_header header;
+ u16 source_id;
+ u16 config_write_enable;
+ u8 flags;
+ u8 reserved1;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ u64 global_capability_data;
+ u64 global_control_data;
+ u8 num_hardware_banks;
+ u8 reserved2[7];
+};
+
+/* 1: XPF Corrected Machine Check */
+
+struct acpi_table_hest_xpf_corrected {
+ struct acpi_hest_header header;
+ u16 source_id;
+ u16 config_write_enable;
+ u8 flags;
+ u8 enabled;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ struct acpi_hest_notify notify;
+ u8 num_hardware_banks;
+ u8 reserved[3];
+};
+
+/* 3: XPF Non-Maskable Interrupt */
+
+struct acpi_hest_xpf_nmi {
+ struct acpi_hest_header header;
+ u16 source_id;
+ u32 reserved;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ u32 max_raw_data_length;
+};
+
+/* 4: IPF Corrected Machine Check */
+
+struct acpi_hest_ipf_corrected {
+ struct acpi_hest_header header;
+ u8 enabled;
+ u8 reserved;
+};
+
+/* 5: IPF Corrected Platform Error */
+
+struct acpi_hest_ipf_corrected_platform {
+ struct acpi_hest_header header;
+ u8 enabled;
+ u8 reserved;
+};
+
+/* 6: PCI Express Root Port AER */
+
+struct acpi_hest_aer_root {
+ struct acpi_hest_header header;
+ struct acpi_hest_aer_common aer;
+ u32 root_error_command;
+};
+
+/* 7: PCI Express AER (AER Endpoint) */
+
+struct acpi_hest_aer {
+ struct acpi_hest_header header;
+ struct acpi_hest_aer_common aer;
+};
+
+/* 8: PCI Express/PCI-X Bridge AER */
+
+struct acpi_hest_aer_bridge {
+ struct acpi_hest_header header;
+ struct acpi_hest_aer_common aer;
+ u32 secondary_uncorrectable_error_mask;
+ u32 secondary_uncorrectable_error_severity;
+ u32 secondary_advanced_capabilities;
+};
+
+/* 9: Generic Hardware Error Source */
+
+struct acpi_hest_generic {
+ struct acpi_hest_header header;
+ u16 source_id;
+ u16 related_source_id;
+ u8 config_write_enable;
+ u8 enabled;
+ u32 records_to_pre_allocate;
+ u32 max_sections_per_record;
+ u32 max_raw_data_length;
+ struct acpi_generic_address error_status_address;
+ struct acpi_hest_notify notify;
+ u32 error_status_block_length;
+};
+
+/*******************************************************************************
+ *
* HPET - High Precision Event Timer table
*
******************************************************************************/
@@ -373,6 +768,96 @@
/*******************************************************************************
*
+ * IBFT - Boot Firmware Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_ibft {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 reserved[12];
+};
+
+/* IBFT common subtable header */
+
+struct acpi_ibft_header {
+ u8 type;
+ u8 version;
+ u16 length;
+ u8 index;
+ u8 flags;
+};
+
+/* Values for Type field above */
+
+enum acpi_ibft_type {
+ ACPI_IBFT_TYPE_NOT_USED = 0,
+ ACPI_IBFT_TYPE_CONTROL = 1,
+ ACPI_IBFT_TYPE_INITIATOR = 2,
+ ACPI_IBFT_TYPE_NIC = 3,
+ ACPI_IBFT_TYPE_TARGET = 4,
+ ACPI_IBFT_TYPE_EXTENSIONS = 5,
+ ACPI_IBFT_TYPE_RESERVED = 6 /* 6 and greater are reserved */
+};
+
+/* IBFT subtables */
+
+struct acpi_ibft_control {
+ struct acpi_ibft_header header;
+ u16 extensions;
+ u16 initiator_offset;
+ u16 nic0_offset;
+ u16 target0_offset;
+ u16 nic1_offset;
+ u16 target1_offset;
+};
+
+struct acpi_ibft_initiator {
+ struct acpi_ibft_header header;
+ u8 sns_server[16];
+ u8 slp_server[16];
+ u8 primary_server[16];
+ u8 secondary_server[16];
+ u16 name_length;
+ u16 name_offset;
+};
+
+struct acpi_ibft_nic {
+ struct acpi_ibft_header header;
+ u8 ip_address[16];
+ u8 subnet_mask_prefix;
+ u8 origin;
+ u8 gateway[16];
+ u8 primary_dns[16];
+ u8 secondary_dns[16];
+ u8 dhcp[16];
+ u16 vlan;
+ u8 mac_address[6];
+ u16 pci_address;
+ u16 name_length;
+ u16 name_offset;
+};
+
+struct acpi_ibft_target {
+ struct acpi_ibft_header header;
+ u8 target_ip_address[16];
+ u16 target_ip_socket;
+ u8 target_boot_lun[8];
+ u8 chap_type;
+ u8 nic_association;
+ u16 target_name_length;
+ u16 target_name_offset;
+ u16 chap_name_length;
+ u16 chap_name_offset;
+ u16 chap_secret_length;
+ u16 chap_secret_offset;
+ u16 reverse_chap_name_length;
+ u16 reverse_chap_name_offset;
+ u16 reverse_chap_secret_length;
+ u16 reverse_chap_secret_offset;
+};
+
+/*******************************************************************************
+ *
* MADT - Multiple APIC Description Table
*
******************************************************************************/
@@ -697,6 +1182,78 @@
/*******************************************************************************
*
+ * UEFI - UEFI Boot optimization Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_uefi {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u8 identifier[16]; /* UUID identifier */
+ u16 data_offset; /* Offset of remaining data in table */
+ u8 data;
+};
+
+/*******************************************************************************
+ *
+ * WDAT - Watchdog Action Table
+ *
+ ******************************************************************************/
+
+struct acpi_table_wdat {
+ struct acpi_table_header header; /* Common ACPI table header */
+ u32 header_length; /* Watchdog Header Length */
+ u16 pci_segment; /* PCI Segment number */
+ u8 pci_bus; /* PCI Bus number */
+ u8 pci_device; /* PCI Device number */
+ u8 pci_function; /* PCI Function number */
+ u8 reserved[3];
+ u32 timer_period; /* Period of one timer count (msec) */
+ u32 max_count; /* Maximum counter value supported */
+ u32 min_count; /* Minimum counter value */
+ u8 flags;
+ u8 reserved2[3];
+ u32 entries; /* Number of watchdog entries that follow */
+};
+
+/* WDAT Instruction Entries (actions) */
+
+struct acpi_wdat_entry {
+ struct acpi_whea_header whea_header; /* Common header for WHEA tables */
+};
+
+/* Values for Action field above */
+
+enum acpi_wdat_actions {
+ ACPI_WDAT_RESET = 1,
+ ACPI_WDAT_GET_CURRENT_COUNTDOWN = 4,
+ ACPI_WDAT_GET_COUNTDOWN = 5,
+ ACPI_WDAT_SET_COUNTDOWN = 6,
+ ACPI_WDAT_GET_RUNNING_STATE = 8,
+ ACPI_WDAT_SET_RUNNING_STATE = 9,
+ ACPI_WDAT_GET_STOPPED_STATE = 10,
+ ACPI_WDAT_SET_STOPPED_STATE = 11,
+ ACPI_WDAT_GET_REBOOT = 16,
+ ACPI_WDAT_SET_REBOOT = 17,
+ ACPI_WDAT_GET_SHUTDOWN = 18,
+ ACPI_WDAT_SET_SHUTDOWN = 19,
+ ACPI_WDAT_GET_STATUS = 32,
+ ACPI_WDAT_SET_STATUS = 33,
+ ACPI_WDAT_ACTION_RESERVED = 34 /* 34 and greater are reserved */
+};
+
+/* Values for Instruction field above */
+
+enum acpi_wdat_instructions {
+ ACPI_WDAT_READ_VALUE = 0,
+ ACPI_WDAT_READ_COUNTDOWN = 1,
+ ACPI_WDAT_WRITE_VALUE = 2,
+ ACPI_WDAT_WRITE_COUNTDOWN = 3,
+ ACPI_WDAT_INSTRUCTION_RESERVED = 4, /* 4 and greater are reserved */
+ ACPI_WDAT_PRESERVE_REGISTER = 0x80 /* Except for this value */
+};
+
+/*******************************************************************************
+ *
* WDRT - Watchdog Resource Table
*
******************************************************************************/
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index e73a389..dfea2d4 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -323,27 +323,11 @@
#define acpi_semaphore void *
/*
- * Acpi integer width. In ACPI version 1, integers are
- * 32 bits. In ACPI version 2, integers are 64 bits.
- * Note that this pertains to the ACPI integer type only, not
- * other integers used in the implementation of the ACPI CA
+ * Acpi integer width. In ACPI version 1, integers are 32 bits. In ACPI
+ * version 2, integers are 64 bits. Note that this pertains to the ACPI integer
+ * type only, not other integers used in the implementation of the ACPI CA
* subsystem.
*/
-#ifdef ACPI_NO_INTEGER64_SUPPORT
-
-/* 32-bit integers only, no 64-bit support */
-
-typedef u32 acpi_integer;
-#define ACPI_INTEGER_MAX ACPI_UINT32_MAX
-#define ACPI_INTEGER_BIT_SIZE 32
-#define ACPI_MAX_DECIMAL_DIGITS 10 /* 2^32 = 4,294,967,296 */
-
-#define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 32-bit divide */
-
-#else
-
-/* 64-bit integers */
-
typedef unsigned long long acpi_integer;
#define ACPI_INTEGER_MAX ACPI_UINT64_MAX
#define ACPI_INTEGER_BIT_SIZE 64
@@ -352,7 +336,6 @@
#if ACPI_MACHINE_WIDTH == 64
#define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 64-bit divide */
#endif
-#endif
#define ACPI_MAX64_DECIMAL_DIGITS 20
#define ACPI_MAX32_DECIMAL_DIGITS 10
@@ -419,14 +402,20 @@
/*
* Standard notify values
*/
-#define ACPI_NOTIFY_BUS_CHECK (u8) 0
-#define ACPI_NOTIFY_DEVICE_CHECK (u8) 1
-#define ACPI_NOTIFY_DEVICE_WAKE (u8) 2
-#define ACPI_NOTIFY_EJECT_REQUEST (u8) 3
-#define ACPI_NOTIFY_DEVICE_CHECK_LIGHT (u8) 4
-#define ACPI_NOTIFY_FREQUENCY_MISMATCH (u8) 5
-#define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 6
-#define ACPI_NOTIFY_POWER_FAULT (u8) 7
+#define ACPI_NOTIFY_BUS_CHECK (u8) 0x00
+#define ACPI_NOTIFY_DEVICE_CHECK (u8) 0x01
+#define ACPI_NOTIFY_DEVICE_WAKE (u8) 0x02
+#define ACPI_NOTIFY_EJECT_REQUEST (u8) 0x03
+#define ACPI_NOTIFY_DEVICE_CHECK_LIGHT (u8) 0x04
+#define ACPI_NOTIFY_FREQUENCY_MISMATCH (u8) 0x05
+#define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 0x06
+#define ACPI_NOTIFY_POWER_FAULT (u8) 0x07
+#define ACPI_NOTIFY_CAPABILITIES_CHECK (u8) 0x08
+#define ACPI_NOTIFY_DEVICE_PLD_CHECK (u8) 0x09
+#define ACPI_NOTIFY_RESERVED (u8) 0x0A
+#define ACPI_NOTIFY_LOCALITY_UPDATE (u8) 0x0B
+
+#define ACPI_NOTIFY_MAX 0x0B
/*
* Types associated with ACPI names and objects. The first group of
@@ -494,6 +483,8 @@
#define ACPI_TYPE_INVALID 0x1E
#define ACPI_TYPE_NOT_FOUND 0xFF
+#define ACPI_NUM_NS_TYPES (ACPI_TYPE_INVALID + 1)
+
/*
* All I/O
*/
@@ -599,7 +590,7 @@
#define ACPI_SYSTEM_NOTIFY 0x1
#define ACPI_DEVICE_NOTIFY 0x2
-#define ACPI_ALL_NOTIFY 0x3
+#define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY)
#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3
#define ACPI_MAX_SYS_NOTIFY 0x7f
@@ -654,46 +645,51 @@
/*
* External ACPI object definition
*/
+
+/*
+ * Note: Type == ACPI_TYPE_ANY (0) is used to indicate a NULL package element
+ * or an unresolved named reference.
+ */
union acpi_object {
acpi_object_type type; /* See definition of acpi_ns_type for values */
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_INTEGER */
acpi_integer value; /* The actual number */
} integer;
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_STRING */
u32 length; /* # of bytes in string, excluding trailing null */
char *pointer; /* points to the string value */
} string;
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_BUFFER */
u32 length; /* # of bytes in buffer */
u8 *pointer; /* points to the buffer */
} buffer;
struct {
- acpi_object_type type;
- u32 fill1;
- acpi_handle handle; /* object reference */
- } reference;
-
- struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_PACKAGE */
u32 count; /* # of elements in package */
union acpi_object *elements; /* Pointer to an array of ACPI_OBJECTs */
} package;
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_LOCAL_REFERENCE */
+ acpi_object_type actual_type; /* Type associated with the Handle */
+ acpi_handle handle; /* object reference */
+ } reference;
+
+ struct {
+ acpi_object_type type; /* ACPI_TYPE_PROCESSOR */
u32 proc_id;
acpi_io_address pblk_address;
u32 pblk_length;
} processor;
struct {
- acpi_object_type type;
+ acpi_object_type type; /* ACPI_TYPE_POWER */
u32 system_level;
u32 resource_order;
} power_resource;
@@ -747,6 +743,12 @@
u32 debug_layer;
};
+/* Table Event Types */
+
+#define ACPI_TABLE_EVENT_LOAD 0x0
+#define ACPI_TABLE_EVENT_UNLOAD 0x1
+#define ACPI_NUM_TABLE_EVENTS 2
+
/*
* Types specific to the OS service interfaces
*/
@@ -776,6 +778,11 @@
u16 opcode,
u32 aml_offset, void *context);
+/* Table Event handler (Load, load_table etc) and types */
+
+typedef
+acpi_status(*acpi_tbl_handler) (u32 event, void *table, void *context);
+
/* Address Spaces (For Operation Regions) */
typedef
@@ -990,6 +997,7 @@
* Structures used to describe device resources
*/
struct acpi_resource_irq {
+ u8 descriptor_length;
u8 triggering;
u8 polarity;
u8 sharable;
@@ -1006,6 +1014,7 @@
};
struct acpi_resource_start_dependent {
+ u8 descriptor_length;
u8 compatibility_priority;
u8 performance_robustness;
};
diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h
index a2918547..b42cadf 100644
--- a/include/acpi/acutils.h
+++ b/include/acpi/acutils.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -116,6 +116,8 @@
char *acpi_ut_get_mutex_name(u32 mutex_id);
+const char *acpi_ut_get_notify_name(u32 notify_value);
+
#endif
char *acpi_ut_get_type_name(acpi_object_type type);
diff --git a/include/acpi/amlcode.h b/include/acpi/amlcode.h
index da53a4e..ff851c5 100644
--- a/include/acpi/amlcode.h
+++ b/include/acpi/amlcode.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/amlresrc.h b/include/acpi/amlresrc.h
index f7d5412..7b070e4 100644
--- a/include/acpi/amlresrc.h
+++ b/include/acpi/amlresrc.h
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index c785485..fcd2572 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/acgcc.h b/include/acpi/platform/acgcc.h
index 3bb5049..8996dba 100644
--- a/include/acpi/platform/acgcc.h
+++ b/include/acpi/platform/acgcc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/acpi/platform/aclinux.h b/include/acpi/platform/aclinux.h
index 6ed15a0..9af4645 100644
--- a/include/acpi/platform/aclinux.h
+++ b/include/acpi/platform/aclinux.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2007, R. Byron Moore
+ * Copyright (C) 2000 - 2008, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/include/asm-alpha/unaligned.h b/include/asm-alpha/unaligned.h
index a1d7284..3787c60 100644
--- a/include/asm-alpha/unaligned.h
+++ b/include/asm-alpha/unaligned.h
@@ -1,6 +1,11 @@
-#ifndef __ALPHA_UNALIGNED_H
-#define __ALPHA_UNALIGNED_H
+#ifndef _ASM_ALPHA_UNALIGNED_H
+#define _ASM_ALPHA_UNALIGNED_H
-#include <asm-generic/unaligned.h>
+#include <linux/unaligned/le_struct.h>
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/generic.h>
-#endif
+#define get_unaligned __get_unaligned_le
+#define put_unaligned __put_unaligned_le
+
+#endif /* _ASM_ALPHA_UNALIGNED_H */
diff --git a/include/asm-arm/arch-orion5x/io.h b/include/asm-arm/arch-orion5x/io.h
index 5148ab7..50f8c88 100644
--- a/include/asm-arm/arch-orion5x/io.h
+++ b/include/asm-arm/arch-orion5x/io.h
@@ -20,11 +20,10 @@
__arch_ioremap(unsigned long paddr, size_t size, unsigned int mtype)
{
void __iomem *retval;
-
- if (mtype == MT_DEVICE && size && paddr >= ORION5X_REGS_PHYS_BASE &&
- paddr + size <= ORION5X_REGS_PHYS_BASE + ORION5X_REGS_SIZE) {
- retval = (void __iomem *)ORION5X_REGS_VIRT_BASE +
- (paddr - ORION5X_REGS_PHYS_BASE);
+ unsigned long offs = paddr - ORION5X_REGS_PHYS_BASE;
+ if (mtype == MT_DEVICE && size && offs < ORION5X_REGS_SIZE &&
+ size <= ORION5X_REGS_SIZE && offs + size <= ORION5X_REGS_SIZE) {
+ retval = (void __iomem *)ORION5X_REGS_VIRT_BASE + offs;
} else {
retval = __arm_ioremap(paddr, size, mtype);
}
diff --git a/include/asm-arm/arch-pxa/irqs.h b/include/asm-arm/arch-pxa/irqs.h
index 50c77ea..b6c8fe3 100644
--- a/include/asm-arm/arch-pxa/irqs.h
+++ b/include/asm-arm/arch-pxa/irqs.h
@@ -239,7 +239,7 @@
/* ITE8152 irqs */
/* add IT8152 IRQs beyond BOARD_END */
#ifdef CONFIG_PCI_HOST_ITE8152
-#define IT8152_IRQ(x) (IRQ_GPIO(IRQ_BOARD_END) + 1 + (x))
+#define IT8152_IRQ(x) (IRQ_BOARD_END + (x))
/* IRQ-sources in 3 groups - local devices, LPC (serial), and external PCI */
#define IT8152_LD_IRQ_COUNT 9
@@ -253,6 +253,9 @@
#define IT8152_LAST_IRQ IT8152_LD_IRQ(IT8152_LD_IRQ_COUNT - 1)
+#if NR_IRQS < (IT8152_LAST_IRQ+1)
#undef NR_IRQS
#define NR_IRQS (IT8152_LAST_IRQ+1)
#endif
+
+#endif /* CONFIG_PCI_HOST_ITE8152 */
diff --git a/include/asm-arm/arch-pxa/magician.h b/include/asm-arm/arch-pxa/magician.h
index b34fd56..169b374 100644
--- a/include/asm-arm/arch-pxa/magician.h
+++ b/include/asm-arm/arch-pxa/magician.h
@@ -13,7 +13,6 @@
#define _MAGICIAN_H_
#include <asm/arch/irqs.h>
-#include <asm/arch/pxa2xx-gpio.h>
/*
* PXA GPIOs
@@ -64,54 +63,6 @@
#define GPIO120_MAGICIAN_UNKNOWN 120
/*
- * PXA GPIO alternate function mode & direction
- */
-
-#define GPIO0_MAGICIAN_KEY_POWER_MD (0 | GPIO_IN)
-#define GPIO9_MAGICIAN_UNKNOWN_MD (9 | GPIO_IN)
-#define GPIO10_MAGICIAN_GSM_IRQ_MD (10 | GPIO_IN)
-#define GPIO11_MAGICIAN_GSM_OUT1_MD (11 | GPIO_OUT)
-#define GPIO13_MAGICIAN_CPLD_IRQ_MD (13 | GPIO_IN)
-#define GPIO18_MAGICIAN_UNKNOWN_MD (18 | GPIO_OUT)
-#define GPIO22_MAGICIAN_VIBRA_EN_MD (22 | GPIO_OUT)
-#define GPIO26_MAGICIAN_GSM_POWER_MD (26 | GPIO_OUT)
-#define GPIO27_MAGICIAN_USBC_PUEN_MD (27 | GPIO_OUT)
-#define GPIO30_MAGICIAN_nCHARGE_EN_MD (30 | GPIO_OUT)
-#define GPIO37_MAGICIAN_KEY_HANGUP_MD (37 | GPIO_OUT)
-#define GPIO38_MAGICIAN_KEY_CONTACTS_MD (38 | GPIO_OUT)
-#define GPIO40_MAGICIAN_GSM_OUT2_MD (40 | GPIO_OUT)
-#define GPIO48_MAGICIAN_UNKNOWN_MD (48 | GPIO_OUT)
-#define GPIO56_MAGICIAN_UNKNOWN_MD (56 | GPIO_OUT)
-#define GPIO57_MAGICIAN_CAM_RESET_MD (57 | GPIO_OUT)
-#define GPIO75_MAGICIAN_SAMSUNG_POWER_MD (75 | GPIO_OUT)
-#define GPIO83_MAGICIAN_nIR_EN_MD (83 | GPIO_OUT)
-#define GPIO86_MAGICIAN_GSM_RESET_MD (86 | GPIO_OUT)
-#define GPIO87_MAGICIAN_GSM_SELECT_MD (87 | GPIO_OUT)
-#define GPIO90_MAGICIAN_KEY_CALENDAR_MD (90 | GPIO_OUT)
-#define GPIO91_MAGICIAN_KEY_CAMERA_MD (91 | GPIO_OUT)
-#define GPIO93_MAGICIAN_KEY_UP_MD (93 | GPIO_IN)
-#define GPIO94_MAGICIAN_KEY_DOWN_MD (94 | GPIO_IN)
-#define GPIO95_MAGICIAN_KEY_LEFT_MD (95 | GPIO_IN)
-#define GPIO96_MAGICIAN_KEY_RIGHT_MD (96 | GPIO_IN)
-#define GPIO97_MAGICIAN_KEY_ENTER_MD (97 | GPIO_IN)
-#define GPIO98_MAGICIAN_KEY_RECORD_MD (98 | GPIO_IN)
-#define GPIO99_MAGICIAN_HEADPHONE_IN_MD (99 | GPIO_IN)
-#define GPIO100_MAGICIAN_KEY_VOL_UP_MD (100 | GPIO_IN)
-#define GPIO101_MAGICIAN_KEY_VOL_DOWN_MD (101 | GPIO_IN)
-#define GPIO102_MAGICIAN_KEY_PHONE_MD (102 | GPIO_IN)
-#define GPIO103_MAGICIAN_LED_KP_MD (103 | GPIO_OUT)
-#define GPIO104_MAGICIAN_LCD_POWER_1_MD (104 | GPIO_OUT)
-#define GPIO105_MAGICIAN_LCD_POWER_2_MD (105 | GPIO_OUT)
-#define GPIO106_MAGICIAN_LCD_POWER_3_MD (106 | GPIO_OUT)
-#define GPIO107_MAGICIAN_DS1WM_IRQ_MD (107 | GPIO_IN)
-#define GPIO108_MAGICIAN_GSM_READY_MD (108 | GPIO_IN)
-#define GPIO114_MAGICIAN_UNKNOWN_MD (114 | GPIO_OUT)
-#define GPIO115_MAGICIAN_nPEN_IRQ_MD (115 | GPIO_IN)
-#define GPIO116_MAGICIAN_nCAM_EN_MD (116 | GPIO_OUT)
-#define GPIO119_MAGICIAN_UNKNOWN_MD (119 | GPIO_OUT)
-#define GPIO120_MAGICIAN_UNKNOWN_MD (120 | GPIO_OUT)
-
-/*
* CPLD IRQs
*/
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index a322012..4b2ea1e 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1406,202 +1406,6 @@
#define OSCC_OON (1 << 1) /* 32.768kHz OON (write-once only bit) */
#define OSCC_OOK (1 << 0) /* 32.768kHz OOK (read-only bit) */
-
-/*
- * LCD
- */
-
-#define LCCR0 __REG(0x44000000) /* LCD Controller Control Register 0 */
-#define LCCR1 __REG(0x44000004) /* LCD Controller Control Register 1 */
-#define LCCR2 __REG(0x44000008) /* LCD Controller Control Register 2 */
-#define LCCR3 __REG(0x4400000C) /* LCD Controller Control Register 3 */
-#define LCCR4 __REG(0x44000010) /* LCD Controller Control Register 3 */
-#define DFBR0 __REG(0x44000020) /* DMA Channel 0 Frame Branch Register */
-#define DFBR1 __REG(0x44000024) /* DMA Channel 1 Frame Branch Register */
-#define LCSR __REG(0x44000038) /* LCD Controller Status Register */
-#define LIIDR __REG(0x4400003C) /* LCD Controller Interrupt ID Register */
-#define TMEDRGBR __REG(0x44000040) /* TMED RGB Seed Register */
-#define TMEDCR __REG(0x44000044) /* TMED Control Register */
-
-#define LCCR3_1BPP (0 << 24)
-#define LCCR3_2BPP (1 << 24)
-#define LCCR3_4BPP (2 << 24)
-#define LCCR3_8BPP (3 << 24)
-#define LCCR3_16BPP (4 << 24)
-
-#define LCCR3_PDFOR_0 (0 << 30)
-#define LCCR3_PDFOR_1 (1 << 30)
-#define LCCR3_PDFOR_2 (2 << 30)
-#define LCCR3_PDFOR_3 (3 << 30)
-
-#define LCCR4_PAL_FOR_0 (0 << 15)
-#define LCCR4_PAL_FOR_1 (1 << 15)
-#define LCCR4_PAL_FOR_2 (2 << 15)
-#define LCCR4_PAL_FOR_MASK (3 << 15)
-
-#define FDADR0 __REG(0x44000200) /* DMA Channel 0 Frame Descriptor Address Register */
-#define FSADR0 __REG(0x44000204) /* DMA Channel 0 Frame Source Address Register */
-#define FIDR0 __REG(0x44000208) /* DMA Channel 0 Frame ID Register */
-#define LDCMD0 __REG(0x4400020C) /* DMA Channel 0 Command Register */
-#define FDADR1 __REG(0x44000210) /* DMA Channel 1 Frame Descriptor Address Register */
-#define FSADR1 __REG(0x44000214) /* DMA Channel 1 Frame Source Address Register */
-#define FIDR1 __REG(0x44000218) /* DMA Channel 1 Frame ID Register */
-#define LDCMD1 __REG(0x4400021C) /* DMA Channel 1 Command Register */
-
-#define LCCR0_ENB (1 << 0) /* LCD Controller enable */
-#define LCCR0_CMS (1 << 1) /* Color/Monochrome Display Select */
-#define LCCR0_Color (LCCR0_CMS*0) /* Color display */
-#define LCCR0_Mono (LCCR0_CMS*1) /* Monochrome display */
-#define LCCR0_SDS (1 << 2) /* Single/Dual Panel Display */
- /* Select */
-#define LCCR0_Sngl (LCCR0_SDS*0) /* Single panel display */
-#define LCCR0_Dual (LCCR0_SDS*1) /* Dual panel display */
-
-#define LCCR0_LDM (1 << 3) /* LCD Disable Done Mask */
-#define LCCR0_SFM (1 << 4) /* Start of frame mask */
-#define LCCR0_IUM (1 << 5) /* Input FIFO underrun mask */
-#define LCCR0_EFM (1 << 6) /* End of Frame mask */
-#define LCCR0_PAS (1 << 7) /* Passive/Active display Select */
-#define LCCR0_Pas (LCCR0_PAS*0) /* Passive display (STN) */
-#define LCCR0_Act (LCCR0_PAS*1) /* Active display (TFT) */
-#define LCCR0_DPD (1 << 9) /* Double Pixel Data (monochrome */
- /* display mode) */
-#define LCCR0_4PixMono (LCCR0_DPD*0) /* 4-Pixel/clock Monochrome */
- /* display */
-#define LCCR0_8PixMono (LCCR0_DPD*1) /* 8-Pixel/clock Monochrome */
- /* display */
-#define LCCR0_DIS (1 << 10) /* LCD Disable */
-#define LCCR0_QDM (1 << 11) /* LCD Quick Disable mask */
-#define LCCR0_PDD (0xff << 12) /* Palette DMA request delay */
-#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.] */ \
- (((Pixel) - 1) << FShft (LCCR1_PPL))
-
-#define LCCR1_HSW Fld (6, 10) /* Horizontal Synchronization */
-#define LCCR1_HorSnchWdth(Tpix) /* Horizontal Synchronization */ \
- /* pulse Width [1..64 Tpix] */ \
- (((Tpix) - 1) << FShft (LCCR1_HSW))
-
-#define LCCR1_ELW Fld (8, 16) /* End-of-Line pixel clock Wait */
- /* count - 1 [Tpix] */
-#define LCCR1_EndLnDel(Tpix) /* End-of-Line Delay */ \
- /* [1..256 Tpix] */ \
- (((Tpix) - 1) << FShft (LCCR1_ELW))
-
-#define LCCR1_BLW Fld (8, 24) /* Beginning-of-Line pixel clock */
- /* Wait count - 1 [Tpix] */
-#define LCCR1_BegLnDel(Tpix) /* Beginning-of-Line Delay */ \
- /* [1..256 Tpix] */ \
- (((Tpix) - 1) << FShft (LCCR1_BLW))
-
-
-#define LCCR2_LPP Fld (10, 0) /* Line Per Panel - 1 */
-#define LCCR2_DisHght(Line) /* Display Height [1..1024 lines] */ \
- (((Line) - 1) << FShft (LCCR2_LPP))
-
-#define LCCR2_VSW Fld (6, 10) /* Vertical Synchronization pulse */
- /* Width - 1 [Tln] (L_FCLK) */
-#define LCCR2_VrtSnchWdth(Tln) /* Vertical Synchronization pulse */ \
- /* Width [1..64 Tln] */ \
- (((Tln) - 1) << FShft (LCCR2_VSW))
-
-#define LCCR2_EFW Fld (8, 16) /* End-of-Frame line clock Wait */
- /* count [Tln] */
-#define LCCR2_EndFrmDel(Tln) /* End-of-Frame Delay */ \
- /* [0..255 Tln] */ \
- ((Tln) << FShft (LCCR2_EFW))
-
-#define LCCR2_BFW Fld (8, 24) /* Beginning-of-Frame line clock */
- /* Wait count [Tln] */
-#define LCCR2_BegFrmDel(Tln) /* Beginning-of-Frame Delay */ \
- /* [0..255 Tln] */ \
- ((Tln) << FShft (LCCR2_BFW))
-
-#if 0
-#define LCCR3_PCD (0xff) /* Pixel clock divisor */
-#define LCCR3_ACB (0xff << 8) /* AC Bias pin frequency */
-#define LCCR3_ACB_S 8
-#endif
-
-#define LCCR3_API (0xf << 16) /* AC Bias pin trasitions per interrupt */
-#define LCCR3_API_S 16
-#define LCCR3_VSP (1 << 20) /* vertical sync polarity */
-#define LCCR3_HSP (1 << 21) /* horizontal sync polarity */
-#define LCCR3_PCP (1 << 22) /* Pixel Clock Polarity (L_PCLK) */
-#define LCCR3_PixRsEdg (LCCR3_PCP*0) /* Pixel clock Rising-Edge */
-#define LCCR3_PixFlEdg (LCCR3_PCP*1) /* Pixel clock Falling-Edge */
-
-#define LCCR3_OEP (1 << 23) /* Output Enable Polarity (L_BIAS, */
- /* active display mode) */
-#define LCCR3_OutEnH (LCCR3_OEP*0) /* Output Enable active High */
-#define LCCR3_OutEnL (LCCR3_OEP*1) /* Output Enable active Low */
-
-#if 0
-#define LCCR3_BPP (7 << 24) /* bits per pixel */
-#define LCCR3_BPP_S 24
-#endif
-#define LCCR3_DPC (1 << 27) /* double pixel clock mode */
-
-
-#define LCCR3_PCD Fld (8, 0) /* Pixel Clock Divisor */
-#define LCCR3_PixClkDiv(Div) /* Pixel Clock Divisor */ \
- (((Div) << FShft (LCCR3_PCD)))
-
-
-#define LCCR3_BPP Fld (3, 24) /* Bit Per Pixel */
-#define LCCR3_Bpp(Bpp) /* Bit Per Pixel */ \
- (((Bpp) << FShft (LCCR3_BPP)))
-
-#define LCCR3_ACB Fld (8, 8) /* AC Bias */
-#define LCCR3_Acb(Acb) /* BAC Bias */ \
- (((Acb) << FShft (LCCR3_ACB)))
-
-#define LCCR3_HorSnchH (LCCR3_HSP*0) /* Horizontal Synchronization */
- /* pulse active High */
-#define LCCR3_HorSnchL (LCCR3_HSP*1) /* Horizontal Synchronization */
-
-#define LCCR3_VrtSnchH (LCCR3_VSP*0) /* Vertical Synchronization pulse */
- /* active High */
-#define LCCR3_VrtSnchL (LCCR3_VSP*1) /* Vertical Synchronization pulse */
- /* active Low */
-
-#define LCSR_LDD (1 << 0) /* LCD Disable Done */
-#define LCSR_SOF (1 << 1) /* Start of frame */
-#define LCSR_BER (1 << 2) /* Bus error */
-#define LCSR_ABC (1 << 3) /* AC Bias count */
-#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */
-#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */
-#define LCSR_OU (1 << 6) /* output FIFO underrun */
-#define LCSR_QD (1 << 7) /* quick disable */
-#define LCSR_EOF (1 << 8) /* end of frame */
-#define LCSR_BS (1 << 9) /* branch status */
-#define LCSR_SINT (1 << 10) /* subsequent interrupt */
-
-#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */
-
-#define LCSR_LDD (1 << 0) /* LCD Disable Done */
-#define LCSR_SOF (1 << 1) /* Start of frame */
-#define LCSR_BER (1 << 2) /* Bus error */
-#define LCSR_ABC (1 << 3) /* AC Bias count */
-#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */
-#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */
-#define LCSR_OU (1 << 6) /* output FIFO underrun */
-#define LCSR_QD (1 << 7) /* quick disable */
-#define LCSR_EOF (1 << 8) /* end of frame */
-#define LCSR_BS (1 << 9) /* branch status */
-#define LCSR_SINT (1 << 10) /* subsequent interrupt */
-
-#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */
-
#ifdef CONFIG_PXA27x
/* Camera Interface */
diff --git a/include/asm-arm/arch-pxa/pxafb.h b/include/asm-arm/arch-pxa/pxafb.h
index ea2336a..bbd2239 100644
--- a/include/asm-arm/arch-pxa/pxafb.h
+++ b/include/asm-arm/arch-pxa/pxafb.h
@@ -13,6 +13,50 @@
*/
#include <linux/fb.h>
+#include <asm/arch/regs-lcd.h>
+
+/*
+ * Supported LCD connections
+ *
+ * bits 0 - 3: for LCD panel type:
+ *
+ * STN - for passive matrix
+ * DSTN - for dual scan passive matrix
+ * TFT - for active matrix
+ *
+ * bits 4 - 9 : for bus width
+ * bits 10-17 : for AC Bias Pin Frequency
+ * bit 18 : for output enable polarity
+ * bit 19 : for pixel clock edge
+ */
+#define LCD_CONN_TYPE(_x) ((_x) & 0x0f)
+#define LCD_CONN_WIDTH(_x) (((_x) >> 4) & 0x1f)
+
+#define LCD_TYPE_UNKNOWN 0
+#define LCD_TYPE_MONO_STN 1
+#define LCD_TYPE_MONO_DSTN 2
+#define LCD_TYPE_COLOR_STN 3
+#define LCD_TYPE_COLOR_DSTN 4
+#define LCD_TYPE_COLOR_TFT 5
+#define LCD_TYPE_SMART_PANEL 6
+#define LCD_TYPE_MAX 7
+
+#define LCD_MONO_STN_4BPP ((4 << 4) | LCD_TYPE_MONO_STN)
+#define LCD_MONO_STN_8BPP ((8 << 4) | LCD_TYPE_MONO_STN)
+#define LCD_MONO_DSTN_8BPP ((8 << 4) | LCD_TYPE_MONO_DSTN)
+#define LCD_COLOR_STN_8BPP ((8 << 4) | LCD_TYPE_COLOR_STN)
+#define LCD_COLOR_DSTN_16BPP ((16 << 4) | LCD_TYPE_COLOR_DSTN)
+#define LCD_COLOR_TFT_16BPP ((16 << 4) | LCD_TYPE_COLOR_TFT)
+#define LCD_COLOR_TFT_18BPP ((18 << 4) | LCD_TYPE_COLOR_TFT)
+#define LCD_SMART_PANEL_8BPP ((8 << 4) | LCD_TYPE_SMART_PANEL)
+#define LCD_SMART_PANEL_16BPP ((16 << 4) | LCD_TYPE_SMART_PANEL)
+#define LCD_SMART_PANEL_18BPP ((18 << 4) | LCD_TYPE_SMART_PANEL)
+
+#define LCD_AC_BIAS_FREQ(x) (((x) & 0xff) << 10)
+#define LCD_BIAS_ACTIVE_HIGH (0 << 17)
+#define LCD_BIAS_ACTIVE_LOW (1 << 17)
+#define LCD_PCLK_EDGE_RISE (0 << 18)
+#define LCD_PCLK_EDGE_FALL (1 << 18)
/*
* This structure describes the machine which we are running on.
@@ -26,6 +70,10 @@
u_short yres;
u_char bpp;
+ u_int cmap_greyscale:1,
+ unused:31;
+
+ /* Parallel Mode Timing */
u_char hsync_len;
u_char left_margin;
u_char right_margin;
@@ -35,14 +83,28 @@
u_char lower_margin;
u_char sync;
- u_int cmap_greyscale:1,
- unused:31;
+ /* Smart Panel Mode Timing - see PXA27x DM 7.4.15.0.3 for details
+ * Note:
+ * 1. all parameters in nanosecond (ns)
+ * 2. a0cs{rd,wr}_set_hld are controlled by the same register bits
+ * in pxa27x and pxa3xx, initialize them to the same value or
+ * the larger one will be used
+ * 3. same to {rd,wr}_pulse_width
+ */
+ unsigned a0csrd_set_hld; /* A0 and CS Setup/Hold Time before/after L_FCLK_RD */
+ unsigned a0cswr_set_hld; /* A0 and CS Setup/Hold Time before/after L_PCLK_WR */
+ unsigned wr_pulse_width; /* L_PCLK_WR pulse width */
+ unsigned rd_pulse_width; /* L_FCLK_RD pulse width */
+ unsigned cmd_inh_time; /* Command Inhibit time between two writes */
+ unsigned op_hold_time; /* Output Hold time from L_FCLK_RD negation */
};
struct pxafb_mach_info {
struct pxafb_mode_info *modes;
unsigned int num_modes;
+ unsigned int lcd_conn;
+
u_int fixed_modes:1,
cmap_inverse:1,
cmap_static:1,
@@ -78,8 +140,11 @@
u_int lccr4;
void (*pxafb_backlight_power)(int);
void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
-
+ void (*smart_update)(struct fb_info *);
};
void set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info);
void set_pxa_fb_parent(struct device *parent_dev);
unsigned long pxafb_get_hsync_time(struct device *dev);
+
+extern int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int);
+extern int pxafb_smart_flush(struct fb_info *info);
diff --git a/include/asm-arm/arch-pxa/regs-lcd.h b/include/asm-arm/arch-pxa/regs-lcd.h
new file mode 100644
index 0000000..f762493
--- /dev/null
+++ b/include/asm-arm/arch-pxa/regs-lcd.h
@@ -0,0 +1,171 @@
+#ifndef __ASM_ARCH_REGS_LCD_H
+#define __ASM_ARCH_REGS_LCD_H
+/*
+ * LCD Controller Registers and Bits Definitions
+ */
+#define LCCR0 (0x000) /* LCD Controller Control Register 0 */
+#define LCCR1 (0x004) /* LCD Controller Control Register 1 */
+#define LCCR2 (0x008) /* LCD Controller Control Register 2 */
+#define LCCR3 (0x00C) /* LCD Controller Control Register 3 */
+#define LCCR4 (0x010) /* LCD Controller Control Register 4 */
+#define LCCR5 (0x014) /* LCD Controller Control Register 5 */
+#define DFBR0 (0x020) /* DMA Channel 0 Frame Branch Register */
+#define DFBR1 (0x024) /* DMA Channel 1 Frame Branch Register */
+#define LCSR (0x038) /* LCD Controller Status Register */
+#define LIIDR (0x03C) /* LCD Controller Interrupt ID Register */
+#define TMEDRGBR (0x040) /* TMED RGB Seed Register */
+#define TMEDCR (0x044) /* TMED Control Register */
+
+#define CMDCR (0x100) /* Command Control Register */
+#define PRSR (0x104) /* Panel Read Status Register */
+
+#define LCCR3_1BPP (0 << 24)
+#define LCCR3_2BPP (1 << 24)
+#define LCCR3_4BPP (2 << 24)
+#define LCCR3_8BPP (3 << 24)
+#define LCCR3_16BPP (4 << 24)
+
+#define LCCR3_PDFOR_0 (0 << 30)
+#define LCCR3_PDFOR_1 (1 << 30)
+#define LCCR3_PDFOR_2 (2 << 30)
+#define LCCR3_PDFOR_3 (3 << 30)
+
+#define LCCR4_PAL_FOR_0 (0 << 15)
+#define LCCR4_PAL_FOR_1 (1 << 15)
+#define LCCR4_PAL_FOR_2 (2 << 15)
+#define LCCR4_PAL_FOR_MASK (3 << 15)
+
+#define FDADR0 (0x200) /* DMA Channel 0 Frame Descriptor Address Register */
+#define FSADR0 (0x204) /* DMA Channel 0 Frame Source Address Register */
+#define FIDR0 (0x208) /* DMA Channel 0 Frame ID Register */
+#define LDCMD0 (0x20C) /* DMA Channel 0 Command Register */
+#define FDADR1 (0x210) /* DMA Channel 1 Frame Descriptor Address Register */
+#define FSADR1 (0x214) /* DMA Channel 1 Frame Source Address Register */
+#define FIDR1 (0x218) /* DMA Channel 1 Frame ID Register */
+#define LDCMD1 (0x21C) /* DMA Channel 1 Command Register */
+#define FDADR6 (0x260) /* DMA Channel 6 Frame Descriptor Address Register */
+#define FSADR6 (0x264) /* DMA Channel 6 Frame Source Address Register */
+#define FIDR6 (0x268) /* DMA Channel 6 Frame ID Register */
+
+#define LCCR0_ENB (1 << 0) /* LCD Controller enable */
+#define LCCR0_CMS (1 << 1) /* Color/Monochrome Display Select */
+#define LCCR0_Color (LCCR0_CMS*0) /* Color display */
+#define LCCR0_Mono (LCCR0_CMS*1) /* Monochrome display */
+#define LCCR0_SDS (1 << 2) /* Single/Dual Panel Display Select */
+#define LCCR0_Sngl (LCCR0_SDS*0) /* Single panel display */
+#define LCCR0_Dual (LCCR0_SDS*1) /* Dual panel display */
+
+#define LCCR0_LDM (1 << 3) /* LCD Disable Done Mask */
+#define LCCR0_SFM (1 << 4) /* Start of frame mask */
+#define LCCR0_IUM (1 << 5) /* Input FIFO underrun mask */
+#define LCCR0_EFM (1 << 6) /* End of Frame mask */
+#define LCCR0_PAS (1 << 7) /* Passive/Active display Select */
+#define LCCR0_Pas (LCCR0_PAS*0) /* Passive display (STN) */
+#define LCCR0_Act (LCCR0_PAS*1) /* Active display (TFT) */
+#define LCCR0_DPD (1 << 9) /* Double Pixel Data (monochrome) */
+#define LCCR0_4PixMono (LCCR0_DPD*0) /* 4-Pixel/clock Monochrome display */
+#define LCCR0_8PixMono (LCCR0_DPD*1) /* 8-Pixel/clock Monochrome display */
+#define LCCR0_DIS (1 << 10) /* LCD Disable */
+#define LCCR0_QDM (1 << 11) /* LCD Quick Disable mask */
+#define LCCR0_PDD (0xff << 12) /* Palette DMA request delay */
+#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) (((Pixel) - 1) << FShft (LCCR1_PPL))
+
+#define LCCR1_HSW Fld (6, 10) /* Horizontal Synchronization */
+#define LCCR1_HorSnchWdth(Tpix) (((Tpix) - 1) << FShft (LCCR1_HSW))
+
+#define LCCR1_ELW Fld (8, 16) /* End-of-Line pixel clock Wait - 1 */
+#define LCCR1_EndLnDel(Tpix) (((Tpix) - 1) << FShft (LCCR1_ELW))
+
+#define LCCR1_BLW Fld (8, 24) /* Beginning-of-Line pixel clock */
+#define LCCR1_BegLnDel(Tpix) (((Tpix) - 1) << FShft (LCCR1_BLW))
+
+#define LCCR2_LPP Fld (10, 0) /* Line Per Panel - 1 */
+#define LCCR2_DisHght(Line) (((Line) - 1) << FShft (LCCR2_LPP))
+
+#define LCCR2_VSW Fld (6, 10) /* Vertical Synchronization pulse - 1 */
+#define LCCR2_VrtSnchWdth(Tln) (((Tln) - 1) << FShft (LCCR2_VSW))
+
+#define LCCR2_EFW Fld (8, 16) /* End-of-Frame line clock Wait */
+#define LCCR2_EndFrmDel(Tln) ((Tln) << FShft (LCCR2_EFW))
+
+#define LCCR2_BFW Fld (8, 24) /* Beginning-of-Frame line clock */
+#define LCCR2_BegFrmDel(Tln) ((Tln) << FShft (LCCR2_BFW))
+
+#define LCCR3_API (0xf << 16) /* AC Bias pin trasitions per interrupt */
+#define LCCR3_API_S 16
+#define LCCR3_VSP (1 << 20) /* vertical sync polarity */
+#define LCCR3_HSP (1 << 21) /* horizontal sync polarity */
+#define LCCR3_PCP (1 << 22) /* Pixel Clock Polarity (L_PCLK) */
+#define LCCR3_PixRsEdg (LCCR3_PCP*0) /* Pixel clock Rising-Edge */
+#define LCCR3_PixFlEdg (LCCR3_PCP*1) /* Pixel clock Falling-Edge */
+
+#define LCCR3_OEP (1 << 23) /* Output Enable Polarity */
+#define LCCR3_OutEnH (LCCR3_OEP*0) /* Output Enable active High */
+#define LCCR3_OutEnL (LCCR3_OEP*1) /* Output Enable active Low */
+
+#define LCCR3_DPC (1 << 27) /* double pixel clock mode */
+#define LCCR3_PCD Fld (8, 0) /* Pixel Clock Divisor */
+#define LCCR3_PixClkDiv(Div) (((Div) << FShft (LCCR3_PCD)))
+
+#define LCCR3_BPP Fld (3, 24) /* Bit Per Pixel */
+#define LCCR3_Bpp(Bpp) (((Bpp) << FShft (LCCR3_BPP)))
+
+#define LCCR3_ACB Fld (8, 8) /* AC Bias */
+#define LCCR3_Acb(Acb) (((Acb) << FShft (LCCR3_ACB)))
+
+#define LCCR3_HorSnchH (LCCR3_HSP*0) /* HSP Active High */
+#define LCCR3_HorSnchL (LCCR3_HSP*1) /* HSP Active Low */
+
+#define LCCR3_VrtSnchH (LCCR3_VSP*0) /* VSP Active High */
+#define LCCR3_VrtSnchL (LCCR3_VSP*1) /* VSP Active Low */
+
+#define LCCR5_IUM(x) (1 << ((x) + 23)) /* input underrun mask */
+#define LCCR5_BSM(x) (1 << ((x) + 15)) /* branch mask */
+#define LCCR5_EOFM(x) (1 << ((x) + 7)) /* end of frame mask */
+#define LCCR5_SOFM(x) (1 << ((x) + 0)) /* start of frame mask */
+
+#define LCSR_LDD (1 << 0) /* LCD Disable Done */
+#define LCSR_SOF (1 << 1) /* Start of frame */
+#define LCSR_BER (1 << 2) /* Bus error */
+#define LCSR_ABC (1 << 3) /* AC Bias count */
+#define LCSR_IUL (1 << 4) /* input FIFO underrun Lower panel */
+#define LCSR_IUU (1 << 5) /* input FIFO underrun Upper panel */
+#define LCSR_OU (1 << 6) /* output FIFO underrun */
+#define LCSR_QD (1 << 7) /* quick disable */
+#define LCSR_EOF (1 << 8) /* end of frame */
+#define LCSR_BS (1 << 9) /* branch status */
+#define LCSR_SINT (1 << 10) /* subsequent interrupt */
+#define LCSR_RD_ST (1 << 11) /* read status */
+#define LCSR_CMD_INT (1 << 12) /* command interrupt */
+
+#define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */
+
+/* smartpanel related */
+#define PRSR_DATA(x) ((x) & 0xff) /* Panel Data */
+#define PRSR_A0 (1 << 8) /* Read Data Source */
+#define PRSR_ST_OK (1 << 9) /* Status OK */
+#define PRSR_CON_NT (1 << 10) /* Continue to Next Command */
+
+#define SMART_CMD_A0 (0x1 << 8)
+#define SMART_CMD_READ_STATUS_REG (0x0 << 9)
+#define SMART_CMD_READ_FRAME_BUFFER ((0x0 << 9) | SMART_CMD_A0)
+#define SMART_CMD_WRITE_COMMAND (0x1 << 9)
+#define SMART_CMD_WRITE_DATA ((0x1 << 9) | SMART_CMD_A0)
+#define SMART_CMD_WRITE_FRAME ((0x2 << 9) | SMART_CMD_A0)
+#define SMART_CMD_WAIT_FOR_VSYNC (0x3 << 9)
+#define SMART_CMD_NOOP (0x4 << 9)
+#define SMART_CMD_INTERRUPT (0x5 << 9)
+
+#define SMART_CMD(x) (SMART_CMD_WRITE_COMMAND | ((x) & 0xff))
+#define SMART_DAT(x) (SMART_CMD_WRITE_DATA | ((x) & 0xff))
+#endif /* __ASM_ARCH_REGS_LCD_H */
diff --git a/include/asm-arm/arch-pxa/system.h b/include/asm-arm/arch-pxa/system.h
index 1d56a3e..a758a71 100644
--- a/include/asm-arm/arch-pxa/system.h
+++ b/include/asm-arm/arch-pxa/system.h
@@ -22,6 +22,8 @@
static inline void arch_reset(char mode)
{
+ RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
+
if (mode == 's') {
/* Jump into ROM at address 0 */
cpu_reset(0);
diff --git a/include/asm-arm/div64.h b/include/asm-arm/div64.h
index 0b5f881..5001390 100644
--- a/include/asm-arm/div64.h
+++ b/include/asm-arm/div64.h
@@ -224,6 +224,4 @@
#endif
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
-
#endif
diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h
index c86f68e..5c22b01 100644
--- a/include/asm-arm/page.h
+++ b/include/asm-arm/page.h
@@ -71,6 +71,14 @@
# endif
#endif
+#ifdef CONFIG_CPU_COPY_FEROCEON
+# ifdef _USER
+# define MULTI_USER 1
+# else
+# define _USER feroceon
+# endif
+#endif
+
#ifdef CONFIG_CPU_SA1100
# ifdef _USER
# define MULTI_USER 1
diff --git a/include/asm-arm/unaligned.h b/include/asm-arm/unaligned.h
index 5db03cf..44593a8 100644
--- a/include/asm-arm/unaligned.h
+++ b/include/asm-arm/unaligned.h
@@ -1,171 +1,9 @@
-#ifndef __ASM_ARM_UNALIGNED_H
-#define __ASM_ARM_UNALIGNED_H
+#ifndef _ASM_ARM_UNALIGNED_H
+#define _ASM_ARM_UNALIGNED_H
-#include <asm/types.h>
-
-extern int __bug_unaligned_x(const void *ptr);
-
-/*
- * What is the most efficient way of loading/storing an unaligned value?
- *
- * That is the subject of this file. Efficiency here is defined as
- * minimum code size with minimum register usage for the common cases.
- * It is currently not believed that long longs are common, so we
- * trade efficiency for the chars, shorts and longs against the long
- * longs.
- *
- * Current stats with gcc 2.7.2.2 for these functions:
- *
- * ptrsize get: code regs put: code regs
- * 1 1 1 1 2
- * 2 3 2 3 2
- * 4 7 3 7 3
- * 8 20 6 16 6
- *
- * gcc 2.95.1 seems to code differently:
- *
- * ptrsize get: code regs put: code regs
- * 1 1 1 1 2
- * 2 3 2 3 2
- * 4 7 4 7 4
- * 8 19 8 15 6
- *
- * which may or may not be more efficient (depending upon whether
- * you can afford the extra registers). Hopefully the gcc 2.95
- * is inteligent enough to decide if it is better to use the
- * extra register, but evidence so far seems to suggest otherwise.
- *
- * Unfortunately, gcc is not able to optimise the high word
- * out of long long >> 32, or the low word from long long << 32
- */
-
-#define __get_unaligned_2_le(__p) \
- (unsigned int)(__p[0] | __p[1] << 8)
-
-#define __get_unaligned_2_be(__p) \
- (unsigned int)(__p[0] << 8 | __p[1])
-
-#define __get_unaligned_4_le(__p) \
- (unsigned int)(__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24)
-
-#define __get_unaligned_4_be(__p) \
- (unsigned int)(__p[0] << 24 | __p[1] << 16 | __p[2] << 8 | __p[3])
-
-#define __get_unaligned_8_le(__p) \
- ((unsigned long long)__get_unaligned_4_le((__p+4)) << 32 | \
- __get_unaligned_4_le(__p))
-
-#define __get_unaligned_8_be(__p) \
- ((unsigned long long)__get_unaligned_4_be(__p) << 32 | \
- __get_unaligned_4_be((__p+4)))
-
-#define __get_unaligned_le(ptr) \
- ((__force typeof(*(ptr)))({ \
- const __u8 *__p = (const __u8 *)(ptr); \
- __builtin_choose_expr(sizeof(*(ptr)) == 1, *__p, \
- __builtin_choose_expr(sizeof(*(ptr)) == 2, __get_unaligned_2_le(__p), \
- __builtin_choose_expr(sizeof(*(ptr)) == 4, __get_unaligned_4_le(__p), \
- __builtin_choose_expr(sizeof(*(ptr)) == 8, __get_unaligned_8_le(__p), \
- (void)__bug_unaligned_x(__p))))); \
- }))
-
-#define __get_unaligned_be(ptr) \
- ((__force typeof(*(ptr)))({ \
- const __u8 *__p = (const __u8 *)(ptr); \
- __builtin_choose_expr(sizeof(*(ptr)) == 1, *__p, \
- __builtin_choose_expr(sizeof(*(ptr)) == 2, __get_unaligned_2_be(__p), \
- __builtin_choose_expr(sizeof(*(ptr)) == 4, __get_unaligned_4_be(__p), \
- __builtin_choose_expr(sizeof(*(ptr)) == 8, __get_unaligned_8_be(__p), \
- (void)__bug_unaligned_x(__p))))); \
- }))
-
-
-static inline void __put_unaligned_2_le(__u32 __v, register __u8 *__p)
-{
- *__p++ = __v;
- *__p++ = __v >> 8;
-}
-
-static inline void __put_unaligned_2_be(__u32 __v, register __u8 *__p)
-{
- *__p++ = __v >> 8;
- *__p++ = __v;
-}
-
-static inline void __put_unaligned_4_le(__u32 __v, register __u8 *__p)
-{
- __put_unaligned_2_le(__v >> 16, __p + 2);
- __put_unaligned_2_le(__v, __p);
-}
-
-static inline void __put_unaligned_4_be(__u32 __v, register __u8 *__p)
-{
- __put_unaligned_2_be(__v >> 16, __p);
- __put_unaligned_2_be(__v, __p + 2);
-}
-
-static inline void __put_unaligned_8_le(const unsigned long long __v, register __u8 *__p)
-{
- /*
- * tradeoff: 8 bytes of stack for all unaligned puts (2
- * instructions), or an extra register in the long long
- * case - go for the extra register.
- */
- __put_unaligned_4_le(__v >> 32, __p+4);
- __put_unaligned_4_le(__v, __p);
-}
-
-static inline void __put_unaligned_8_be(const unsigned long long __v, register __u8 *__p)
-{
- /*
- * tradeoff: 8 bytes of stack for all unaligned puts (2
- * instructions), or an extra register in the long long
- * case - go for the extra register.
- */
- __put_unaligned_4_be(__v >> 32, __p);
- __put_unaligned_4_be(__v, __p+4);
-}
-
-/*
- * Try to store an unaligned value as efficiently as possible.
- */
-#define __put_unaligned_le(val,ptr) \
- ({ \
- (void)sizeof(*(ptr) = (val)); \
- switch (sizeof(*(ptr))) { \
- case 1: \
- *(ptr) = (val); \
- break; \
- case 2: __put_unaligned_2_le((__force u16)(val),(__u8 *)(ptr)); \
- break; \
- case 4: __put_unaligned_4_le((__force u32)(val),(__u8 *)(ptr)); \
- break; \
- case 8: __put_unaligned_8_le((__force u64)(val),(__u8 *)(ptr)); \
- break; \
- default: __bug_unaligned_x(ptr); \
- break; \
- } \
- (void) 0; \
- })
-
-#define __put_unaligned_be(val,ptr) \
- ({ \
- (void)sizeof(*(ptr) = (val)); \
- switch (sizeof(*(ptr))) { \
- case 1: \
- *(ptr) = (val); \
- break; \
- case 2: __put_unaligned_2_be((__force u16)(val),(__u8 *)(ptr)); \
- break; \
- case 4: __put_unaligned_4_be((__force u32)(val),(__u8 *)(ptr)); \
- break; \
- case 8: __put_unaligned_8_be((__force u64)(val),(__u8 *)(ptr)); \
- break; \
- default: __bug_unaligned_x(ptr); \
- break; \
- } \
- (void) 0; \
- })
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/generic.h>
/*
* Select endianness
@@ -178,4 +16,4 @@
#define put_unaligned __put_unaligned_be
#endif
-#endif
+#endif /* _ASM_ARM_UNALIGNED_H */
diff --git a/include/asm-avr32/unaligned.h b/include/asm-avr32/unaligned.h
index 36f5fd4..0418772 100644
--- a/include/asm-avr32/unaligned.h
+++ b/include/asm-avr32/unaligned.h
@@ -1,5 +1,5 @@
-#ifndef __ASM_AVR32_UNALIGNED_H
-#define __ASM_AVR32_UNALIGNED_H
+#ifndef _ASM_AVR32_UNALIGNED_H
+#define _ASM_AVR32_UNALIGNED_H
/*
* AVR32 can handle some unaligned accesses, depending on the
@@ -11,6 +11,11 @@
* optimize word loads in general.
*/
-#include <asm-generic/unaligned.h>
+#include <linux/unaligned/be_struct.h>
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/generic.h>
-#endif /* __ASM_AVR32_UNALIGNED_H */
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
+
+#endif /* _ASM_AVR32_UNALIGNED_H */
diff --git a/include/asm-blackfin/unaligned.h b/include/asm-blackfin/unaligned.h
index 10081dc..fd8a1d6 100644
--- a/include/asm-blackfin/unaligned.h
+++ b/include/asm-blackfin/unaligned.h
@@ -1,6 +1,11 @@
-#ifndef __BFIN_UNALIGNED_H
-#define __BFIN_UNALIGNED_H
+#ifndef _ASM_BLACKFIN_UNALIGNED_H
+#define _ASM_BLACKFIN_UNALIGNED_H
-#include <asm-generic/unaligned.h>
+#include <linux/unaligned/le_struct.h>
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/generic.h>
-#endif /* __BFIN_UNALIGNED_H */
+#define get_unaligned __get_unaligned_le
+#define put_unaligned __put_unaligned_le
+
+#endif /* _ASM_BLACKFIN_UNALIGNED_H */
diff --git a/include/asm-cris/unaligned.h b/include/asm-cris/unaligned.h
index 7fbbb39..7b3f3fe 100644
--- a/include/asm-cris/unaligned.h
+++ b/include/asm-cris/unaligned.h
@@ -1,16 +1,13 @@
-#ifndef __CRIS_UNALIGNED_H
-#define __CRIS_UNALIGNED_H
+#ifndef _ASM_CRIS_UNALIGNED_H
+#define _ASM_CRIS_UNALIGNED_H
/*
* CRIS can do unaligned accesses itself.
- *
- * The strange macros are there to make sure these can't
- * be misused in a way that makes them not work on other
- * architectures where unaligned accesses aren't as simple.
*/
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
-#define get_unaligned(ptr) (*(ptr))
+#define get_unaligned __get_unaligned_le
+#define put_unaligned __put_unaligned_le
-#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
-
-#endif
+#endif /* _ASM_CRIS_UNALIGNED_H */
diff --git a/include/asm-frv/unaligned.h b/include/asm-frv/unaligned.h
index dc8e9c9..839a2fb 100644
--- a/include/asm-frv/unaligned.h
+++ b/include/asm-frv/unaligned.h
@@ -12,191 +12,11 @@
#ifndef _ASM_UNALIGNED_H
#define _ASM_UNALIGNED_H
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/generic.h>
-/*
- * Unaligned accesses on uClinux can't be performed in a fault handler - the
- * CPU detects them as imprecise exceptions making this impossible.
- *
- * With the FR451, however, they are precise, and so we used to fix them up in
- * the memory access fault handler. However, instruction bundling make this
- * impractical. So, now we fall back to using memcpy.
- */
-#ifdef CONFIG_MMU
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
-/*
- * The asm statement in the macros below is a way to get GCC to copy a
- * value from one variable to another without having any clue it's
- * actually doing so, so that it won't have any idea that the values
- * in the two variables are related.
- */
-
-#define get_unaligned(ptr) ({ \
- typeof((*(ptr))) __x; \
- void *__ptrcopy; \
- asm("" : "=r" (__ptrcopy) : "0" (ptr)); \
- memcpy(&__x, __ptrcopy, sizeof(*(ptr))); \
- __x; \
-})
-
-#define put_unaligned(val, ptr) ({ \
- typeof((*(ptr))) __x = (val); \
- void *__ptrcopy; \
- asm("" : "=r" (__ptrcopy) : "0" (ptr)); \
- memcpy(__ptrcopy, &__x, sizeof(*(ptr))); \
-})
-
-extern int handle_misalignment(unsigned long esr0, unsigned long ear0, unsigned long epcr0);
-
-#else
-
-#define get_unaligned(ptr) \
-({ \
- typeof(*(ptr)) x; \
- const char *__p = (const char *) (ptr); \
- \
- switch (sizeof(x)) { \
- case 1: \
- x = *(ptr); \
- break; \
- case 2: \
- { \
- uint8_t a; \
- asm(" ldub%I2 %M2,%0 \n" \
- " ldub%I3.p %M3,%1 \n" \
- " slli %0,#8,%0 \n" \
- " or %0,%1,%0 \n" \
- : "=&r"(x), "=&r"(a) \
- : "m"(__p[0]), "m"(__p[1]) \
- ); \
- break; \
- } \
- \
- case 4: \
- { \
- uint8_t a; \
- asm(" ldub%I2 %M2,%0 \n" \
- " ldub%I3.p %M3,%1 \n" \
- " slli %0,#8,%0 \n" \
- " or %0,%1,%0 \n" \
- " ldub%I4.p %M4,%1 \n" \
- " slli %0,#8,%0 \n" \
- " or %0,%1,%0 \n" \
- " ldub%I5.p %M5,%1 \n" \
- " slli %0,#8,%0 \n" \
- " or %0,%1,%0 \n" \
- : "=&r"(x), "=&r"(a) \
- : "m"(__p[0]), "m"(__p[1]), "m"(__p[2]), "m"(__p[3]) \
- ); \
- break; \
- } \
- \
- case 8: \
- { \
- union { uint64_t x; u32 y[2]; } z; \
- uint8_t a; \
- asm(" ldub%I3 %M3,%0 \n" \
- " ldub%I4.p %M4,%2 \n" \
- " slli %0,#8,%0 \n" \
- " or %0,%2,%0 \n" \
- " ldub%I5.p %M5,%2 \n" \
- " slli %0,#8,%0 \n" \
- " or %0,%2,%0 \n" \
- " ldub%I6.p %M6,%2 \n" \
- " slli %0,#8,%0 \n" \
- " or %0,%2,%0 \n" \
- " ldub%I7 %M7,%1 \n" \
- " ldub%I8.p %M8,%2 \n" \
- " slli %1,#8,%1 \n" \
- " or %1,%2,%1 \n" \
- " ldub%I9.p %M9,%2 \n" \
- " slli %1,#8,%1 \n" \
- " or %1,%2,%1 \n" \
- " ldub%I10.p %M10,%2 \n" \
- " slli %1,#8,%1 \n" \
- " or %1,%2,%1 \n" \
- : "=&r"(z.y[0]), "=&r"(z.y[1]), "=&r"(a) \
- : "m"(__p[0]), "m"(__p[1]), "m"(__p[2]), "m"(__p[3]), \
- "m"(__p[4]), "m"(__p[5]), "m"(__p[6]), "m"(__p[7]) \
- ); \
- x = z.x; \
- break; \
- } \
- \
- default: \
- x = 0; \
- BUG(); \
- break; \
- } \
- \
- x; \
-})
-
-#define put_unaligned(val, ptr) \
-do { \
- char *__p = (char *) (ptr); \
- int x; \
- \
- switch (sizeof(*ptr)) { \
- case 2: \
- { \
- asm(" stb%I1.p %0,%M1 \n" \
- " srli %0,#8,%0 \n" \
- " stb%I2 %0,%M2 \n" \
- : "=r"(x), "=m"(__p[1]), "=m"(__p[0]) \
- : "0"(val) \
- ); \
- break; \
- } \
- \
- case 4: \
- { \
- asm(" stb%I1.p %0,%M1 \n" \
- " srli %0,#8,%0 \n" \
- " stb%I2.p %0,%M2 \n" \
- " srli %0,#8,%0 \n" \
- " stb%I3.p %0,%M3 \n" \
- " srli %0,#8,%0 \n" \
- " stb%I4 %0,%M4 \n" \
- : "=r"(x), "=m"(__p[3]), "=m"(__p[2]), "=m"(__p[1]), "=m"(__p[0]) \
- : "0"(val) \
- ); \
- break; \
- } \
- \
- case 8: \
- { \
- uint32_t __high, __low; \
- __high = (uint64_t)val >> 32; \
- __low = val & 0xffffffff; \
- asm(" stb%I2.p %0,%M2 \n" \
- " srli %0,#8,%0 \n" \
- " stb%I3.p %0,%M3 \n" \
- " srli %0,#8,%0 \n" \
- " stb%I4.p %0,%M4 \n" \
- " srli %0,#8,%0 \n" \
- " stb%I5.p %0,%M5 \n" \
- " srli %0,#8,%0 \n" \
- " stb%I6.p %1,%M6 \n" \
- " srli %1,#8,%1 \n" \
- " stb%I7.p %1,%M7 \n" \
- " srli %1,#8,%1 \n" \
- " stb%I8.p %1,%M8 \n" \
- " srli %1,#8,%1 \n" \
- " stb%I9 %1,%M9 \n" \
- : "=&r"(__low), "=&r"(__high), "=m"(__p[7]), "=m"(__p[6]), \
- "=m"(__p[5]), "=m"(__p[4]), "=m"(__p[3]), "=m"(__p[2]), \
- "=m"(__p[1]), "=m"(__p[0]) \
- : "0"(__low), "1"(__high) \
- ); \
- break; \
- } \
- \
- default: \
- *(ptr) = (val); \
- break; \
- } \
-} while(0)
-
-#endif
-
-#endif
+#endif /* _ASM_UNALIGNED_H */
diff --git a/include/asm-generic/bitops.h b/include/asm-generic/bitops.h
index 15e6f25..c9f369c 100644
--- a/include/asm-generic/bitops.h
+++ b/include/asm-generic/bitops.h
@@ -17,8 +17,6 @@
#include <asm-generic/bitops/fls64.h>
#include <asm-generic/bitops/find.h>
-#ifdef __KERNEL__
-
#ifndef _LINUX_BITOPS_H
#error only <linux/bitops.h> can be included directly
#endif
@@ -32,6 +30,4 @@
#include <asm-generic/bitops/ext2-atomic.h>
#include <asm-generic/bitops/minix.h>
-#endif /* __KERNEL__ */
-
#endif /* _ASM_GENERIC_BITOPS_H */
diff --git a/include/asm-generic/div64.h b/include/asm-generic/div64.h
index a4a4937..8f4e319 100644
--- a/include/asm-generic/div64.h
+++ b/include/asm-generic/div64.h
@@ -30,11 +30,6 @@
__rem; \
})
-static inline uint64_t div64_64(uint64_t dividend, uint64_t divisor)
-{
- return dividend / divisor;
-}
-
#elif BITS_PER_LONG == 32
extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor);
@@ -54,8 +49,6 @@
__rem; \
})
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
-
#else /* BITS_PER_LONG == ?? */
# error do_div() does not yet support the C64
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index f422df0..3c2344f 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -1,11 +1,9 @@
#ifndef _ASM_GENERIC_FUTEX_H
#define _ASM_GENERIC_FUTEX_H
-#ifdef __KERNEL__
-
#include <linux/futex.h>
+#include <linux/uaccess.h>
#include <asm/errno.h>
-#include <asm/uaccess.h>
static inline int
futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
@@ -56,4 +54,3 @@
}
#endif
-#endif
diff --git a/include/asm-generic/ioctl.h b/include/asm-generic/ioctl.h
index cd02729..8641813 100644
--- a/include/asm-generic/ioctl.h
+++ b/include/asm-generic/ioctl.h
@@ -21,8 +21,19 @@
*/
#define _IOC_NRBITS 8
#define _IOC_TYPEBITS 8
-#define _IOC_SIZEBITS 14
-#define _IOC_DIRBITS 2
+
+/*
+ * Let any architecture override either of the following before
+ * including this file.
+ */
+
+#ifndef _IOC_SIZEBITS
+# define _IOC_SIZEBITS 14
+#endif
+
+#ifndef _IOC_DIRBITS
+# define _IOC_DIRBITS 2
+#endif
#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
@@ -35,11 +46,21 @@
#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
/*
- * Direction bits.
+ * Direction bits, which any architecture can choose to override
+ * before including this file.
*/
-#define _IOC_NONE 0U
-#define _IOC_WRITE 1U
-#define _IOC_READ 2U
+
+#ifndef _IOC_NONE
+# define _IOC_NONE 0U
+#endif
+
+#ifndef _IOC_WRITE
+# define _IOC_WRITE 1U
+#endif
+
+#ifndef _IOC_READ
+# define _IOC_READ 2U
+#endif
#define _IOC(dir,type,nr,size) \
(((dir) << _IOC_DIRSHIFT) | \
diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h
index 52226e1..ae060c6 100644
--- a/include/asm-generic/memory_model.h
+++ b/include/asm-generic/memory_model.h
@@ -1,7 +1,6 @@
#ifndef __ASM_MEMORY_MODEL_H
#define __ASM_MEMORY_MODEL_H
-#ifdef __KERNEL__
#ifndef __ASSEMBLY__
#if defined(CONFIG_FLATMEM)
@@ -81,6 +80,5 @@
#endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */
#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
#endif
diff --git a/include/asm-generic/page.h b/include/asm-generic/page.h
index a96b5d9..14db733 100644
--- a/include/asm-generic/page.h
+++ b/include/asm-generic/page.h
@@ -1,7 +1,6 @@
#ifndef _ASM_GENERIC_PAGE_H
#define _ASM_GENERIC_PAGE_H
-#ifdef __KERNEL__
#ifndef __ASSEMBLY__
#include <linux/compiler.h>
@@ -21,6 +20,5 @@
}
#endif /* __ASSEMBLY__ */
-#endif /* __KERNEL__ */
#endif /* _ASM_GENERIC_PAGE_H */
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index dd1bed8..be4af00 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -12,8 +12,6 @@
#ifndef __ASM_RTC_H__
#define __ASM_RTC_H__
-#ifdef __KERNEL__
-
#include <linux/mc146818rtc.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
@@ -213,5 +211,4 @@
return -EINVAL;
}
-#endif /* __KERNEL__ */
#endif /* __ASM_RTC_H__ */
diff --git a/include/asm-generic/unaligned.h b/include/asm-generic/unaligned.h
deleted file mode 100644
index 2fe1b2e..0000000
--- a/include/asm-generic/unaligned.h
+++ /dev/null
@@ -1,124 +0,0 @@
-#ifndef _ASM_GENERIC_UNALIGNED_H_
-#define _ASM_GENERIC_UNALIGNED_H_
-
-/*
- * For the benefit of those who are trying to port Linux to another
- * architecture, here are some C-language equivalents.
- *
- * This is based almost entirely upon Richard Henderson's
- * asm-alpha/unaligned.h implementation. Some comments were
- * taken from David Mosberger's asm-ia64/unaligned.h header.
- */
-
-#include <linux/types.h>
-
-/*
- * The main single-value unaligned transfer routines.
- */
-#define get_unaligned(ptr) \
- __get_unaligned((ptr), sizeof(*(ptr)))
-#define put_unaligned(x,ptr) \
- ((void)sizeof(*(ptr)=(x)),\
- __put_unaligned((__force __u64)(x), (ptr), sizeof(*(ptr))))
-
-/*
- * This function doesn't actually exist. The idea is that when
- * someone uses the macros below with an unsupported size (datatype),
- * the linker will alert us to the problem via an unresolved reference
- * error.
- */
-extern void bad_unaligned_access_length(void) __attribute__((noreturn));
-
-struct __una_u64 { __u64 x __attribute__((packed)); };
-struct __una_u32 { __u32 x __attribute__((packed)); };
-struct __una_u16 { __u16 x __attribute__((packed)); };
-
-/*
- * Elemental unaligned loads
- */
-
-static inline __u64 __uldq(const __u64 *addr)
-{
- const struct __una_u64 *ptr = (const struct __una_u64 *) addr;
- return ptr->x;
-}
-
-static inline __u32 __uldl(const __u32 *addr)
-{
- const struct __una_u32 *ptr = (const struct __una_u32 *) addr;
- return ptr->x;
-}
-
-static inline __u16 __uldw(const __u16 *addr)
-{
- const struct __una_u16 *ptr = (const struct __una_u16 *) addr;
- return ptr->x;
-}
-
-/*
- * Elemental unaligned stores
- */
-
-static inline void __ustq(__u64 val, __u64 *addr)
-{
- struct __una_u64 *ptr = (struct __una_u64 *) addr;
- ptr->x = val;
-}
-
-static inline void __ustl(__u32 val, __u32 *addr)
-{
- struct __una_u32 *ptr = (struct __una_u32 *) addr;
- ptr->x = val;
-}
-
-static inline void __ustw(__u16 val, __u16 *addr)
-{
- struct __una_u16 *ptr = (struct __una_u16 *) addr;
- ptr->x = val;
-}
-
-#define __get_unaligned(ptr, size) ({ \
- const void *__gu_p = ptr; \
- __u64 __val; \
- switch (size) { \
- case 1: \
- __val = *(const __u8 *)__gu_p; \
- break; \
- case 2: \
- __val = __uldw(__gu_p); \
- break; \
- case 4: \
- __val = __uldl(__gu_p); \
- break; \
- case 8: \
- __val = __uldq(__gu_p); \
- break; \
- default: \
- bad_unaligned_access_length(); \
- }; \
- (__force __typeof__(*(ptr)))__val; \
-})
-
-#define __put_unaligned(val, ptr, size) \
-({ \
- void *__gu_p = ptr; \
- switch (size) { \
- case 1: \
- *(__u8 *)__gu_p = (__force __u8)val; \
- break; \
- case 2: \
- __ustw((__force __u16)val, __gu_p); \
- break; \
- case 4: \
- __ustl((__force __u32)val, __gu_p); \
- break; \
- case 8: \
- __ustq(val, __gu_p); \
- break; \
- default: \
- bad_unaligned_access_length(); \
- }; \
- (void)0; \
-})
-
-#endif /* _ASM_GENERIC_UNALIGNED_H */
diff --git a/include/asm-h8300/unaligned.h b/include/asm-h8300/unaligned.h
index ffb67f4..b8d06c7 100644
--- a/include/asm-h8300/unaligned.h
+++ b/include/asm-h8300/unaligned.h
@@ -1,15 +1,11 @@
-#ifndef __H8300_UNALIGNED_H
-#define __H8300_UNALIGNED_H
+#ifndef _ASM_H8300_UNALIGNED_H
+#define _ASM_H8300_UNALIGNED_H
+#include <linux/unaligned/be_memmove.h>
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/generic.h>
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
-#define get_unaligned(ptr) \
- ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr) \
- ({ __typeof__(*(ptr)) __tmp = (val); \
- memmove((ptr), &__tmp, sizeof(*(ptr))); \
- (void)0; })
-
-#endif
+#endif /* _ASM_H8300_UNALIGNED_H */
diff --git a/include/asm-ia64/cpu.h b/include/asm-ia64/cpu.h
index e87fa32..fcca30b 100644
--- a/include/asm-ia64/cpu.h
+++ b/include/asm-ia64/cpu.h
@@ -14,8 +14,8 @@
DECLARE_PER_CPU(int, cpu_state);
-extern int arch_register_cpu(int num);
#ifdef CONFIG_HOTPLUG_CPU
+extern int arch_register_cpu(int num);
extern void arch_unregister_cpu(int);
#endif
diff --git a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h
index f1735a2..9f0df9b 100644
--- a/include/asm-ia64/dma-mapping.h
+++ b/include/asm-ia64/dma-mapping.h
@@ -23,10 +23,30 @@
{
dma_free_coherent(dev, size, cpu_addr, dma_handle);
}
-#define dma_map_single platform_dma_map_single
-#define dma_map_sg platform_dma_map_sg
-#define dma_unmap_single platform_dma_unmap_single
-#define dma_unmap_sg platform_dma_unmap_sg
+#define dma_map_single_attrs platform_dma_map_single_attrs
+static inline dma_addr_t dma_map_single(struct device *dev, void *cpu_addr,
+ size_t size, int dir)
+{
+ return dma_map_single_attrs(dev, cpu_addr, size, dir, NULL);
+}
+#define dma_map_sg_attrs platform_dma_map_sg_attrs
+static inline int dma_map_sg(struct device *dev, struct scatterlist *sgl,
+ int nents, int dir)
+{
+ return dma_map_sg_attrs(dev, sgl, nents, dir, NULL);
+}
+#define dma_unmap_single_attrs platform_dma_unmap_single_attrs
+static inline void dma_unmap_single(struct device *dev, dma_addr_t cpu_addr,
+ size_t size, int dir)
+{
+ return dma_unmap_single_attrs(dev, cpu_addr, size, dir, NULL);
+}
+#define dma_unmap_sg_attrs platform_dma_unmap_sg_attrs
+static inline void dma_unmap_sg(struct device *dev, struct scatterlist *sgl,
+ int nents, int dir)
+{
+ return dma_unmap_sg_attrs(dev, sgl, nents, dir, NULL);
+}
#define dma_sync_single_for_cpu platform_dma_sync_single_for_cpu
#define dma_sync_sg_for_cpu platform_dma_sync_sg_for_cpu
#define dma_sync_single_for_device platform_dma_sync_single_for_device
diff --git a/include/asm-ia64/dmi.h b/include/asm-ia64/dmi.h
index f3efaa2..00eb1b1 100644
--- a/include/asm-ia64/dmi.h
+++ b/include/asm-ia64/dmi.h
@@ -3,4 +3,9 @@
#include <asm/io.h>
+/* Use normal IO mappings for DMI */
+#define dmi_ioremap ioremap
+#define dmi_iounmap(x,l) iounmap(x)
+#define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
+
#endif
diff --git a/include/asm-ia64/futex.h b/include/asm-ia64/futex.h
index 8a98a26..c7f0f06 100644
--- a/include/asm-ia64/futex.h
+++ b/include/asm-ia64/futex.h
@@ -2,9 +2,9 @@
#define _ASM_FUTEX_H
#include <linux/futex.h>
+#include <linux/uaccess.h>
#include <asm/errno.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
do { \
diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
index 4ebed77..260a85a 100644
--- a/include/asm-ia64/io.h
+++ b/include/asm-ia64/io.h
@@ -423,11 +423,6 @@
extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
extern void iounmap (volatile void __iomem *addr);
-/* Use normal IO mappings for DMI */
-#define dmi_ioremap ioremap
-#define dmi_iounmap(x,l) iounmap(x)
-#define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
-
/*
* String version of IO memory access ops:
*/
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index c201a20..9f020eb 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -22,6 +22,7 @@
struct task_struct;
struct pci_dev;
struct msi_desc;
+struct dma_attrs;
typedef void ia64_mv_setup_t (char **);
typedef void ia64_mv_cpu_init_t (void);
@@ -56,6 +57,11 @@
typedef int ia64_mv_dma_mapping_error (dma_addr_t dma_addr);
typedef int ia64_mv_dma_supported (struct device *, u64);
+typedef dma_addr_t ia64_mv_dma_map_single_attrs (struct device *, void *, size_t, int, struct dma_attrs *);
+typedef void ia64_mv_dma_unmap_single_attrs (struct device *, dma_addr_t, size_t, int, struct dma_attrs *);
+typedef int ia64_mv_dma_map_sg_attrs (struct device *, struct scatterlist *, int, int, struct dma_attrs *);
+typedef void ia64_mv_dma_unmap_sg_attrs (struct device *, struct scatterlist *, int, int, struct dma_attrs *);
+
/*
* WARNING: The legacy I/O space is _architected_. Platforms are
* expected to follow this architected model (see Section 10.7 in the
@@ -136,10 +142,10 @@
# define platform_dma_init ia64_mv.dma_init
# define platform_dma_alloc_coherent ia64_mv.dma_alloc_coherent
# define platform_dma_free_coherent ia64_mv.dma_free_coherent
-# define platform_dma_map_single ia64_mv.dma_map_single
-# define platform_dma_unmap_single ia64_mv.dma_unmap_single
-# define platform_dma_map_sg ia64_mv.dma_map_sg
-# define platform_dma_unmap_sg ia64_mv.dma_unmap_sg
+# define platform_dma_map_single_attrs ia64_mv.dma_map_single_attrs
+# define platform_dma_unmap_single_attrs ia64_mv.dma_unmap_single_attrs
+# define platform_dma_map_sg_attrs ia64_mv.dma_map_sg_attrs
+# define platform_dma_unmap_sg_attrs ia64_mv.dma_unmap_sg_attrs
# define platform_dma_sync_single_for_cpu ia64_mv.dma_sync_single_for_cpu
# define platform_dma_sync_sg_for_cpu ia64_mv.dma_sync_sg_for_cpu
# define platform_dma_sync_single_for_device ia64_mv.dma_sync_single_for_device
@@ -190,10 +196,10 @@
ia64_mv_dma_init *dma_init;
ia64_mv_dma_alloc_coherent *dma_alloc_coherent;
ia64_mv_dma_free_coherent *dma_free_coherent;
- ia64_mv_dma_map_single *dma_map_single;
- ia64_mv_dma_unmap_single *dma_unmap_single;
- ia64_mv_dma_map_sg *dma_map_sg;
- ia64_mv_dma_unmap_sg *dma_unmap_sg;
+ ia64_mv_dma_map_single_attrs *dma_map_single_attrs;
+ ia64_mv_dma_unmap_single_attrs *dma_unmap_single_attrs;
+ ia64_mv_dma_map_sg_attrs *dma_map_sg_attrs;
+ ia64_mv_dma_unmap_sg_attrs *dma_unmap_sg_attrs;
ia64_mv_dma_sync_single_for_cpu *dma_sync_single_for_cpu;
ia64_mv_dma_sync_sg_for_cpu *dma_sync_sg_for_cpu;
ia64_mv_dma_sync_single_for_device *dma_sync_single_for_device;
@@ -240,10 +246,10 @@
platform_dma_init, \
platform_dma_alloc_coherent, \
platform_dma_free_coherent, \
- platform_dma_map_single, \
- platform_dma_unmap_single, \
- platform_dma_map_sg, \
- platform_dma_unmap_sg, \
+ platform_dma_map_single_attrs, \
+ platform_dma_unmap_single_attrs, \
+ platform_dma_map_sg_attrs, \
+ platform_dma_unmap_sg_attrs, \
platform_dma_sync_single_for_cpu, \
platform_dma_sync_sg_for_cpu, \
platform_dma_sync_single_for_device, \
@@ -292,9 +298,13 @@
extern ia64_mv_dma_alloc_coherent swiotlb_alloc_coherent;
extern ia64_mv_dma_free_coherent swiotlb_free_coherent;
extern ia64_mv_dma_map_single swiotlb_map_single;
+extern ia64_mv_dma_map_single_attrs swiotlb_map_single_attrs;
extern ia64_mv_dma_unmap_single swiotlb_unmap_single;
+extern ia64_mv_dma_unmap_single_attrs swiotlb_unmap_single_attrs;
extern ia64_mv_dma_map_sg swiotlb_map_sg;
+extern ia64_mv_dma_map_sg_attrs swiotlb_map_sg_attrs;
extern ia64_mv_dma_unmap_sg swiotlb_unmap_sg;
+extern ia64_mv_dma_unmap_sg_attrs swiotlb_unmap_sg_attrs;
extern ia64_mv_dma_sync_single_for_cpu swiotlb_sync_single_for_cpu;
extern ia64_mv_dma_sync_sg_for_cpu swiotlb_sync_sg_for_cpu;
extern ia64_mv_dma_sync_single_for_device swiotlb_sync_single_for_device;
@@ -340,17 +350,17 @@
#ifndef platform_dma_free_coherent
# define platform_dma_free_coherent swiotlb_free_coherent
#endif
-#ifndef platform_dma_map_single
-# define platform_dma_map_single swiotlb_map_single
+#ifndef platform_dma_map_single_attrs
+# define platform_dma_map_single_attrs swiotlb_map_single_attrs
#endif
-#ifndef platform_dma_unmap_single
-# define platform_dma_unmap_single swiotlb_unmap_single
+#ifndef platform_dma_unmap_single_attrs
+# define platform_dma_unmap_single_attrs swiotlb_unmap_single_attrs
#endif
-#ifndef platform_dma_map_sg
-# define platform_dma_map_sg swiotlb_map_sg
+#ifndef platform_dma_map_sg_attrs
+# define platform_dma_map_sg_attrs swiotlb_map_sg_attrs
#endif
-#ifndef platform_dma_unmap_sg
-# define platform_dma_unmap_sg swiotlb_unmap_sg
+#ifndef platform_dma_unmap_sg_attrs
+# define platform_dma_unmap_sg_attrs swiotlb_unmap_sg_attrs
#endif
#ifndef platform_dma_sync_single_for_cpu
# define platform_dma_sync_single_for_cpu swiotlb_sync_single_for_cpu
diff --git a/include/asm-ia64/machvec_hpzx1.h b/include/asm-ia64/machvec_hpzx1.h
index e90daf9..2f57f51 100644
--- a/include/asm-ia64/machvec_hpzx1.h
+++ b/include/asm-ia64/machvec_hpzx1.h
@@ -4,10 +4,10 @@
extern ia64_mv_setup_t dig_setup;
extern ia64_mv_dma_alloc_coherent sba_alloc_coherent;
extern ia64_mv_dma_free_coherent sba_free_coherent;
-extern ia64_mv_dma_map_single sba_map_single;
-extern ia64_mv_dma_unmap_single sba_unmap_single;
-extern ia64_mv_dma_map_sg sba_map_sg;
-extern ia64_mv_dma_unmap_sg sba_unmap_sg;
+extern ia64_mv_dma_map_single_attrs sba_map_single_attrs;
+extern ia64_mv_dma_unmap_single_attrs sba_unmap_single_attrs;
+extern ia64_mv_dma_map_sg_attrs sba_map_sg_attrs;
+extern ia64_mv_dma_unmap_sg_attrs sba_unmap_sg_attrs;
extern ia64_mv_dma_supported sba_dma_supported;
extern ia64_mv_dma_mapping_error sba_dma_mapping_error;
@@ -23,10 +23,10 @@
#define platform_dma_init machvec_noop
#define platform_dma_alloc_coherent sba_alloc_coherent
#define platform_dma_free_coherent sba_free_coherent
-#define platform_dma_map_single sba_map_single
-#define platform_dma_unmap_single sba_unmap_single
-#define platform_dma_map_sg sba_map_sg
-#define platform_dma_unmap_sg sba_unmap_sg
+#define platform_dma_map_single_attrs sba_map_single_attrs
+#define platform_dma_unmap_single_attrs sba_unmap_single_attrs
+#define platform_dma_map_sg_attrs sba_map_sg_attrs
+#define platform_dma_unmap_sg_attrs sba_unmap_sg_attrs
#define platform_dma_sync_single_for_cpu machvec_dma_sync_single
#define platform_dma_sync_sg_for_cpu machvec_dma_sync_sg
#define platform_dma_sync_single_for_device machvec_dma_sync_single
diff --git a/include/asm-ia64/machvec_hpzx1_swiotlb.h b/include/asm-ia64/machvec_hpzx1_swiotlb.h
index f00a34a..a842cdd 100644
--- a/include/asm-ia64/machvec_hpzx1_swiotlb.h
+++ b/include/asm-ia64/machvec_hpzx1_swiotlb.h
@@ -4,10 +4,10 @@
extern ia64_mv_setup_t dig_setup;
extern ia64_mv_dma_alloc_coherent hwsw_alloc_coherent;
extern ia64_mv_dma_free_coherent hwsw_free_coherent;
-extern ia64_mv_dma_map_single hwsw_map_single;
-extern ia64_mv_dma_unmap_single hwsw_unmap_single;
-extern ia64_mv_dma_map_sg hwsw_map_sg;
-extern ia64_mv_dma_unmap_sg hwsw_unmap_sg;
+extern ia64_mv_dma_map_single_attrs hwsw_map_single_attrs;
+extern ia64_mv_dma_unmap_single_attrs hwsw_unmap_single_attrs;
+extern ia64_mv_dma_map_sg_attrs hwsw_map_sg_attrs;
+extern ia64_mv_dma_unmap_sg_attrs hwsw_unmap_sg_attrs;
extern ia64_mv_dma_supported hwsw_dma_supported;
extern ia64_mv_dma_mapping_error hwsw_dma_mapping_error;
extern ia64_mv_dma_sync_single_for_cpu hwsw_sync_single_for_cpu;
@@ -28,10 +28,10 @@
#define platform_dma_init machvec_noop
#define platform_dma_alloc_coherent hwsw_alloc_coherent
#define platform_dma_free_coherent hwsw_free_coherent
-#define platform_dma_map_single hwsw_map_single
-#define platform_dma_unmap_single hwsw_unmap_single
-#define platform_dma_map_sg hwsw_map_sg
-#define platform_dma_unmap_sg hwsw_unmap_sg
+#define platform_dma_map_single_attrs hwsw_map_single_attrs
+#define platform_dma_unmap_single_attrs hwsw_unmap_single_attrs
+#define platform_dma_map_sg_attrs hwsw_map_sg_attrs
+#define platform_dma_unmap_sg_attrs hwsw_unmap_sg_attrs
#define platform_dma_supported hwsw_dma_supported
#define platform_dma_mapping_error hwsw_dma_mapping_error
#define platform_dma_sync_single_for_cpu hwsw_sync_single_for_cpu
diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h
index 61439a7..781308e 100644
--- a/include/asm-ia64/machvec_sn2.h
+++ b/include/asm-ia64/machvec_sn2.h
@@ -57,10 +57,10 @@
extern ia64_mv_readq_t __sn_readq_relaxed;
extern ia64_mv_dma_alloc_coherent sn_dma_alloc_coherent;
extern ia64_mv_dma_free_coherent sn_dma_free_coherent;
-extern ia64_mv_dma_map_single sn_dma_map_single;
-extern ia64_mv_dma_unmap_single sn_dma_unmap_single;
-extern ia64_mv_dma_map_sg sn_dma_map_sg;
-extern ia64_mv_dma_unmap_sg sn_dma_unmap_sg;
+extern ia64_mv_dma_map_single_attrs sn_dma_map_single_attrs;
+extern ia64_mv_dma_unmap_single_attrs sn_dma_unmap_single_attrs;
+extern ia64_mv_dma_map_sg_attrs sn_dma_map_sg_attrs;
+extern ia64_mv_dma_unmap_sg_attrs sn_dma_unmap_sg_attrs;
extern ia64_mv_dma_sync_single_for_cpu sn_dma_sync_single_for_cpu;
extern ia64_mv_dma_sync_sg_for_cpu sn_dma_sync_sg_for_cpu;
extern ia64_mv_dma_sync_single_for_device sn_dma_sync_single_for_device;
@@ -113,10 +113,10 @@
#define platform_dma_init machvec_noop
#define platform_dma_alloc_coherent sn_dma_alloc_coherent
#define platform_dma_free_coherent sn_dma_free_coherent
-#define platform_dma_map_single sn_dma_map_single
-#define platform_dma_unmap_single sn_dma_unmap_single
-#define platform_dma_map_sg sn_dma_map_sg
-#define platform_dma_unmap_sg sn_dma_unmap_sg
+#define platform_dma_map_single_attrs sn_dma_map_single_attrs
+#define platform_dma_unmap_single_attrs sn_dma_unmap_single_attrs
+#define platform_dma_map_sg_attrs sn_dma_map_sg_attrs
+#define platform_dma_unmap_sg_attrs sn_dma_unmap_sg_attrs
#define platform_dma_sync_single_for_cpu sn_dma_sync_single_for_cpu
#define platform_dma_sync_sg_for_cpu sn_dma_sync_sg_for_cpu
#define platform_dma_sync_single_for_device sn_dma_sync_single_for_device
diff --git a/include/asm-ia64/thread_info.h b/include/asm-ia64/thread_info.h
index 6da8069..2422ac6 100644
--- a/include/asm-ia64/thread_info.h
+++ b/include/asm-ia64/thread_info.h
@@ -101,7 +101,6 @@
#define TIF_SYSCALL_TRACE 2 /* syscall trace active */
#define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */
#define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
-#define TIF_RESTORE_SIGMASK 5 /* restore signal mask in do_signal() */
#define TIF_NOTIFY_RESUME 6 /* resumption notification requested */
#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 17
@@ -114,7 +113,6 @@
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
#define _TIF_SYSCALL_TRACEAUDIT (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
@@ -126,13 +124,23 @@
/* "work to do on user-return" bits */
#define TIF_ALLWORK_MASK (_TIF_SIGPENDING|_TIF_NOTIFY_RESUME|_TIF_SYSCALL_AUDIT|\
- _TIF_NEED_RESCHED| _TIF_SYSCALL_TRACE|\
- _TIF_RESTORE_SIGMASK)
+ _TIF_NEED_RESCHED|_TIF_SYSCALL_TRACE)
/* like TIF_ALLWORK_BITS but sans TIF_SYSCALL_TRACE or TIF_SYSCALL_AUDIT */
#define TIF_WORK_MASK (TIF_ALLWORK_MASK&~(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT))
#define TS_POLLING 1 /* true if in idle loop and not sleeping */
+#define TS_RESTORE_SIGMASK 2 /* restore signal mask in do_signal() */
#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+ struct thread_info *ti = current_thread_info();
+ ti->status |= TS_RESTORE_SIGMASK;
+ set_bit(TIF_SIGPENDING, &ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
+
#endif /* _ASM_IA64_THREAD_INFO_H */
diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h
index f2f72ef..32863b3 100644
--- a/include/asm-ia64/topology.h
+++ b/include/asm-ia64/topology.h
@@ -116,6 +116,8 @@
#define smt_capable() (smp_num_siblings > 1)
#endif
+extern void arch_fix_phys_package_id(int num, u32 slot);
+
#define pcibus_to_cpumask(bus) (pcibus_to_node(bus) == -1 ? \
CPU_MASK_ALL : \
node_to_cpumask(pcibus_to_node(bus)) \
diff --git a/include/asm-ia64/unaligned.h b/include/asm-ia64/unaligned.h
index bb85598..7bddc7f 100644
--- a/include/asm-ia64/unaligned.h
+++ b/include/asm-ia64/unaligned.h
@@ -1,6 +1,11 @@
#ifndef _ASM_IA64_UNALIGNED_H
#define _ASM_IA64_UNALIGNED_H
-#include <asm-generic/unaligned.h>
+#include <linux/unaligned/le_struct.h>
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/generic.h>
+
+#define get_unaligned __get_unaligned_le
+#define put_unaligned __put_unaligned_le
#endif /* _ASM_IA64_UNALIGNED_H */
diff --git a/include/asm-ia64/uncached.h b/include/asm-ia64/uncached.h
index b82d923..13d7e65 100644
--- a/include/asm-ia64/uncached.h
+++ b/include/asm-ia64/uncached.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001-2005 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2001-2008 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
@@ -8,5 +8,5 @@
* Prototypes for the uncached page allocator
*/
-extern unsigned long uncached_alloc_page(int nid);
-extern void uncached_free_page(unsigned long);
+extern unsigned long uncached_alloc_page(int starting_nid, int n_pages);
+extern void uncached_free_page(unsigned long uc_addr, int n_pages);
diff --git a/include/asm-m32r/unaligned.h b/include/asm-m32r/unaligned.h
index fccc180..377eb20 100644
--- a/include/asm-m32r/unaligned.h
+++ b/include/asm-m32r/unaligned.h
@@ -1,19 +1,18 @@
#ifndef _ASM_M32R_UNALIGNED_H
#define _ASM_M32R_UNALIGNED_H
-/*
- * For the benefit of those who are trying to port Linux to another
- * architecture, here are some C-language equivalents.
- */
-
-#include <asm/string.h>
-
-#define get_unaligned(ptr) \
- ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr) \
- ({ __typeof__(*(ptr)) __tmp = (val); \
- memmove((ptr), &__tmp, sizeof(*(ptr))); \
- (void)0; })
+#if defined(__LITTLE_ENDIAN__)
+# include <linux/unaligned/le_memmove.h>
+# include <linux/unaligned/be_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_le
+# define put_unaligned __put_unaligned_le
+#else
+# include <linux/unaligned/be_memmove.h>
+# include <linux/unaligned/le_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_be
+# define put_unaligned __put_unaligned_be
+#endif
#endif /* _ASM_M32R_UNALIGNED_H */
diff --git a/include/asm-m68k/div64.h b/include/asm-m68k/div64.h
index 33caad1..8243c93 100644
--- a/include/asm-m68k/div64.h
+++ b/include/asm-m68k/div64.h
@@ -25,5 +25,4 @@
__rem; \
})
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
#endif /* _M68K_DIV64_H */
diff --git a/include/asm-m68k/unaligned.h b/include/asm-m68k/unaligned.h
index 804cb3f..77698f2 100644
--- a/include/asm-m68k/unaligned.h
+++ b/include/asm-m68k/unaligned.h
@@ -1,16 +1,13 @@
-#ifndef __M68K_UNALIGNED_H
-#define __M68K_UNALIGNED_H
+#ifndef _ASM_M68K_UNALIGNED_H
+#define _ASM_M68K_UNALIGNED_H
/*
* The m68k can do unaligned accesses itself.
- *
- * The strange macros are there to make sure these can't
- * be misused in a way that makes them not work on other
- * architectures where unaligned accesses aren't as simple.
*/
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
-#define get_unaligned(ptr) (*(ptr))
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
-#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
-
-#endif
+#endif /* _ASM_M68K_UNALIGNED_H */
diff --git a/include/asm-m68knommu/dma.h b/include/asm-m68knommu/dma.h
index 3f20419..939a020 100644
--- a/include/asm-m68knommu/dma.h
+++ b/include/asm-m68knommu/dma.h
@@ -35,7 +35,8 @@
/*
* Set number of channels of DMA on ColdFire for different implementations.
*/
-#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407)
+#if defined(CONFIG_M5249) || defined(CONFIG_M5307) || defined(CONFIG_M5407) || \
+ defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
#define MAX_M68K_DMA_CHANNELS 4
#elif defined(CONFIG_M5272)
#define MAX_M68K_DMA_CHANNELS 1
diff --git a/include/asm-m68knommu/param.h b/include/asm-m68knommu/param.h
index 96c4510..6044397 100644
--- a/include/asm-m68knommu/param.h
+++ b/include/asm-m68knommu/param.h
@@ -1,13 +1,16 @@
#ifndef _M68KNOMMU_PARAM_H
#define _M68KNOMMU_PARAM_H
-#define HZ CONFIG_HZ
-
#ifdef __KERNEL__
+#define HZ CONFIG_HZ
#define USER_HZ HZ
#define CLOCKS_PER_SEC (USER_HZ)
#endif
+#ifndef HZ
+#define HZ 100
+#endif
+
#define EXEC_PAGESIZE 4096
#ifndef NOGROUP
diff --git a/include/asm-m68knommu/unaligned.h b/include/asm-m68knommu/unaligned.h
index 869e9dd..eb1ea4c 100644
--- a/include/asm-m68knommu/unaligned.h
+++ b/include/asm-m68knommu/unaligned.h
@@ -1,23 +1,25 @@
-#ifndef __M68K_UNALIGNED_H
-#define __M68K_UNALIGNED_H
+#ifndef _ASM_M68KNOMMU_UNALIGNED_H
+#define _ASM_M68KNOMMU_UNALIGNED_H
#ifdef CONFIG_COLDFIRE
+#include <linux/unaligned/be_struct.h>
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/generic.h>
-#include <asm-generic/unaligned.h>
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
#else
/*
* The m68k can do unaligned accesses itself.
- *
- * The strange macros are there to make sure these can't
- * be misused in a way that makes them not work on other
- * architectures where unaligned accesses aren't as simple.
*/
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
-#define get_unaligned(ptr) (*(ptr))
-#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
#endif
-#endif
+#endif /* _ASM_M68KNOMMU_UNALIGNED_H */
diff --git a/include/asm-mips/div64.h b/include/asm-mips/div64.h
index 716371b..d1d6991 100644
--- a/include/asm-mips/div64.h
+++ b/include/asm-mips/div64.h
@@ -82,7 +82,6 @@
(n) = __quot; \
__mod; })
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
#endif /* (_MIPS_SZLONG == 32) */
#if (_MIPS_SZLONG == 64)
@@ -106,11 +105,6 @@
(n) = __quot; \
__mod; })
-static inline uint64_t div64_64(uint64_t dividend, uint64_t divisor)
-{
- return dividend / divisor;
-}
-
#endif /* (_MIPS_SZLONG == 64) */
#endif /* _ASM_DIV64_H */
diff --git a/include/asm-mips/futex.h b/include/asm-mips/futex.h
index 17f082c..b9cce90 100644
--- a/include/asm-mips/futex.h
+++ b/include/asm-mips/futex.h
@@ -11,9 +11,9 @@
#ifdef __KERNEL__
#include <linux/futex.h>
+#include <linux/uaccess.h>
#include <asm/barrier.h>
#include <asm/errno.h>
-#include <asm/uaccess.h>
#include <asm/war.h>
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
diff --git a/include/asm-mips/unaligned.h b/include/asm-mips/unaligned.h
index 3249049..7924049 100644
--- a/include/asm-mips/unaligned.h
+++ b/include/asm-mips/unaligned.h
@@ -5,25 +5,24 @@
*
* Copyright (C) 2007 Ralf Baechle (ralf@linux-mips.org)
*/
-#ifndef __ASM_GENERIC_UNALIGNED_H
-#define __ASM_GENERIC_UNALIGNED_H
+#ifndef _ASM_MIPS_UNALIGNED_H
+#define _ASM_MIPS_UNALIGNED_H
#include <linux/compiler.h>
+#if defined(__MIPSEB__)
+# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/le_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_be
+# define put_unaligned __put_unaligned_be
+#elif defined(__MIPSEL__)
+# include <linux/unaligned/le_struct.h>
+# include <linux/unaligned/be_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_le
+# define put_unaligned __put_unaligned_le
+#else
+# error "MIPS, but neither __MIPSEB__, nor __MIPSEL__???"
+#endif
-#define get_unaligned(ptr) \
-({ \
- struct __packed { \
- typeof(*(ptr)) __v; \
- } *__p = (void *) (ptr); \
- __p->__v; \
-})
-
-#define put_unaligned(val, ptr) \
-do { \
- struct __packed { \
- typeof(*(ptr)) __v; \
- } *__p = (void *) (ptr); \
- __p->__v = (val); \
-} while(0)
-
-#endif /* __ASM_GENERIC_UNALIGNED_H */
+#endif /* _ASM_MIPS_UNALIGNED_H */
diff --git a/include/asm-mn10300/div64.h b/include/asm-mn10300/div64.h
index bf9c515..3a8329b 100644
--- a/include/asm-mn10300/div64.h
+++ b/include/asm-mn10300/div64.h
@@ -97,7 +97,4 @@
return result;
}
-extern __attribute__((const))
-uint64_t div64_64(uint64_t dividend, uint64_t divisor);
-
#endif /* _ASM_DIV64 */
diff --git a/include/asm-mn10300/unaligned.h b/include/asm-mn10300/unaligned.h
index cad3afb..0df6713 100644
--- a/include/asm-mn10300/unaligned.h
+++ b/include/asm-mn10300/unaligned.h
@@ -8,129 +8,13 @@
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
-#ifndef _ASM_UNALIGNED_H
-#define _ASM_UNALIGNED_H
+#ifndef _ASM_MN10300_UNALIGNED_H
+#define _ASM_MN10300_UNALIGNED_H
-#include <asm/types.h>
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
-#if 0
-extern int __bug_unaligned_x(void *ptr);
+#define get_unaligned __get_unaligned_le
+#define put_unaligned __put_unaligned_le
-/*
- * What is the most efficient way of loading/storing an unaligned value?
- *
- * That is the subject of this file. Efficiency here is defined as
- * minimum code size with minimum register usage for the common cases.
- * It is currently not believed that long longs are common, so we
- * trade efficiency for the chars, shorts and longs against the long
- * longs.
- *
- * Current stats with gcc 2.7.2.2 for these functions:
- *
- * ptrsize get: code regs put: code regs
- * 1 1 1 1 2
- * 2 3 2 3 2
- * 4 7 3 7 3
- * 8 20 6 16 6
- *
- * gcc 2.95.1 seems to code differently:
- *
- * ptrsize get: code regs put: code regs
- * 1 1 1 1 2
- * 2 3 2 3 2
- * 4 7 4 7 4
- * 8 19 8 15 6
- *
- * which may or may not be more efficient (depending upon whether
- * you can afford the extra registers). Hopefully the gcc 2.95
- * is inteligent enough to decide if it is better to use the
- * extra register, but evidence so far seems to suggest otherwise.
- *
- * Unfortunately, gcc is not able to optimise the high word
- * out of long long >> 32, or the low word from long long << 32
- */
-
-#define __get_unaligned_2(__p) \
- (__p[0] | __p[1] << 8)
-
-#define __get_unaligned_4(__p) \
- (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24)
-
-#define get_unaligned(ptr) \
-({ \
- unsigned int __v1, __v2; \
- __typeof__(*(ptr)) __v; \
- __u8 *__p = (__u8 *)(ptr); \
- \
- switch (sizeof(*(ptr))) { \
- case 1: __v = *(ptr); break; \
- case 2: __v = __get_unaligned_2(__p); break; \
- case 4: __v = __get_unaligned_4(__p); break; \
- case 8: \
- __v2 = __get_unaligned_4((__p+4)); \
- __v1 = __get_unaligned_4(__p); \
- __v = ((unsigned long long)__v2 << 32 | __v1); \
- break; \
- default: __v = __bug_unaligned_x(__p); break; \
- } \
- __v; \
-})
-
-
-static inline void __put_unaligned_2(__u32 __v, register __u8 *__p)
-{
- *__p++ = __v;
- *__p++ = __v >> 8;
-}
-
-static inline void __put_unaligned_4(__u32 __v, register __u8 *__p)
-{
- __put_unaligned_2(__v >> 16, __p + 2);
- __put_unaligned_2(__v, __p);
-}
-
-static inline void __put_unaligned_8(const unsigned long long __v, __u8 *__p)
-{
- /*
- * tradeoff: 8 bytes of stack for all unaligned puts (2
- * instructions), or an extra register in the long long
- * case - go for the extra register.
- */
- __put_unaligned_4(__v >> 32, __p + 4);
- __put_unaligned_4(__v, __p);
-}
-
-/*
- * Try to store an unaligned value as efficiently as possible.
- */
-#define put_unaligned(val, ptr) \
- ({ \
- switch (sizeof(*(ptr))) { \
- case 1: \
- *(ptr) = (val); \
- break; \
- case 2: \
- __put_unaligned_2((val), (__u8 *)(ptr)); \
- break; \
- case 4: \
- __put_unaligned_4((val), (__u8 *)(ptr)); \
- break; \
- case 8: \
- __put_unaligned_8((val), (__u8 *)(ptr)); \
- break; \
- default: \
- __bug_unaligned_x(ptr); \
- break; \
- } \
- (void) 0; \
- })
-
-
-#else
-
-#define get_unaligned(ptr) (*(ptr))
-#define put_unaligned(val, ptr) ({ *(ptr) = (val); (void) 0; })
-
-#endif
-
-#endif
+#endif /* _ASM_MN10300_UNALIGNED_H */
diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h
index fdc6d05..0c705c3 100644
--- a/include/asm-parisc/futex.h
+++ b/include/asm-parisc/futex.h
@@ -4,8 +4,8 @@
#ifdef __KERNEL__
#include <linux/futex.h>
+#include <linux/uaccess.h>
#include <asm/errno.h>
-#include <asm/uaccess.h>
static inline int
futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
diff --git a/include/asm-parisc/unaligned.h b/include/asm-parisc/unaligned.h
index 53c9058..dfc5d33 100644
--- a/include/asm-parisc/unaligned.h
+++ b/include/asm-parisc/unaligned.h
@@ -1,7 +1,11 @@
-#ifndef _ASM_PARISC_UNALIGNED_H_
-#define _ASM_PARISC_UNALIGNED_H_
+#ifndef _ASM_PARISC_UNALIGNED_H
+#define _ASM_PARISC_UNALIGNED_H
-#include <asm-generic/unaligned.h>
+#include <linux/unaligned/be_struct.h>
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/generic.h>
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
#ifdef __KERNEL__
struct pt_regs;
@@ -9,4 +13,4 @@
int check_unaligned(struct pt_regs *regs);
#endif
-#endif /* _ASM_PARISC_UNALIGNED_H_ */
+#endif /* _ASM_PARISC_UNALIGNED_H */
diff --git a/include/asm-powerpc/futex.h b/include/asm-powerpc/futex.h
index 3f3673f..6d406c5 100644
--- a/include/asm-powerpc/futex.h
+++ b/include/asm-powerpc/futex.h
@@ -4,9 +4,9 @@
#ifdef __KERNEL__
#include <linux/futex.h>
+#include <linux/uaccess.h>
#include <asm/errno.h>
#include <asm/synch.h>
-#include <asm/uaccess.h>
#include <asm/asm-compat.h>
#define __futex_atomic_op(insn, ret, oldval, uaddr, oparg) \
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index b5c0312..5089deb 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -619,8 +619,6 @@
#define __ARCH_HAS_DO_SOFTIRQ
-extern void __do_softirq(void);
-
#ifdef CONFIG_IRQSTACKS
/*
* Per-cpu stacks for handling hard and soft interrupts.
diff --git a/include/asm-powerpc/unaligned.h b/include/asm-powerpc/unaligned.h
index 6c95dfa..5f1b1e3 100644
--- a/include/asm-powerpc/unaligned.h
+++ b/include/asm-powerpc/unaligned.h
@@ -5,15 +5,12 @@
/*
* The PowerPC can do unaligned accesses itself in big endian mode.
- *
- * The strange macros are there to make sure these can't
- * be misused in a way that makes them not work on other
- * architectures where unaligned accesses aren't as simple.
*/
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
-#define get_unaligned(ptr) (*(ptr))
-
-#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
#endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_UNALIGNED_H */
diff --git a/include/asm-s390/ccwgroup.h b/include/asm-s390/ccwgroup.h
index 289053e..a27f689 100644
--- a/include/asm-s390/ccwgroup.h
+++ b/include/asm-s390/ccwgroup.h
@@ -57,10 +57,9 @@
extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver);
extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver);
-extern int ccwgroup_create (struct device *root,
- unsigned int creator_id,
- struct ccw_driver *gdrv,
- int argc, char *argv[]);
+int ccwgroup_create_from_string(struct device *root, unsigned int creator_id,
+ struct ccw_driver *cdrv, int num_devices,
+ const char *buf);
extern int ccwgroup_probe_ccwdev(struct ccw_device *cdev);
extern void ccwgroup_remove_ccwdev(struct ccw_device *cdev);
diff --git a/include/asm-s390/hugetlb.h b/include/asm-s390/hugetlb.h
new file mode 100644
index 0000000..600a776
--- /dev/null
+++ b/include/asm-s390/hugetlb.h
@@ -0,0 +1,183 @@
+/*
+ * IBM System z Huge TLB Page Support for Kernel.
+ *
+ * Copyright IBM Corp. 2008
+ * Author(s): Gerald Schaefer <gerald.schaefer@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_HUGETLB_H
+#define _ASM_S390_HUGETLB_H
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+
+#define is_hugepage_only_range(mm, addr, len) 0
+#define hugetlb_free_pgd_range free_pgd_range
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte);
+
+/*
+ * If the arch doesn't supply something else, assume that hugepage
+ * size aligned regions are ok without further preparation.
+ */
+static inline int prepare_hugepage_range(unsigned long addr, unsigned long len)
+{
+ if (len & ~HPAGE_MASK)
+ return -EINVAL;
+ if (addr & ~HPAGE_MASK)
+ return -EINVAL;
+ return 0;
+}
+
+#define hugetlb_prefault_arch_hook(mm) do { } while (0)
+
+int arch_prepare_hugepage(struct page *page);
+void arch_release_hugepage(struct page *page);
+
+static inline pte_t pte_mkhuge(pte_t pte)
+{
+ /*
+ * PROT_NONE needs to be remapped from the pte type to the ste type.
+ * The HW invalid bit is also different for pte and ste. The pte
+ * invalid bit happens to be the same as the ste _SEGMENT_ENTRY_LARGE
+ * bit, so we don't have to clear it.
+ */
+ if (pte_val(pte) & _PAGE_INVALID) {
+ if (pte_val(pte) & _PAGE_SWT)
+ pte_val(pte) |= _HPAGE_TYPE_NONE;
+ pte_val(pte) |= _SEGMENT_ENTRY_INV;
+ }
+ /*
+ * Clear SW pte bits SWT and SWX, there are no SW bits in a segment
+ * table entry.
+ */
+ pte_val(pte) &= ~(_PAGE_SWT | _PAGE_SWX);
+ /*
+ * Also set the change-override bit because we don't need dirty bit
+ * tracking for hugetlbfs pages.
+ */
+ pte_val(pte) |= (_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_CO);
+ return pte;
+}
+
+static inline pte_t huge_pte_wrprotect(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_RO;
+ return pte;
+}
+
+static inline int huge_pte_none(pte_t pte)
+{
+ return (pte_val(pte) & _SEGMENT_ENTRY_INV) &&
+ !(pte_val(pte) & _SEGMENT_ENTRY_RO);
+}
+
+static inline pte_t huge_ptep_get(pte_t *ptep)
+{
+ pte_t pte = *ptep;
+ unsigned long mask;
+
+ if (!MACHINE_HAS_HPAGE) {
+ ptep = (pte_t *) (pte_val(pte) & _SEGMENT_ENTRY_ORIGIN);
+ if (ptep) {
+ mask = pte_val(pte) &
+ (_SEGMENT_ENTRY_INV | _SEGMENT_ENTRY_RO);
+ pte = pte_mkhuge(*ptep);
+ pte_val(pte) |= mask;
+ }
+ }
+ return pte;
+}
+
+static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ pte_t pte = huge_ptep_get(ptep);
+
+ pmd_clear((pmd_t *) ptep);
+ return pte;
+}
+
+static inline void __pmd_csp(pmd_t *pmdp)
+{
+ register unsigned long reg2 asm("2") = pmd_val(*pmdp);
+ register unsigned long reg3 asm("3") = pmd_val(*pmdp) |
+ _SEGMENT_ENTRY_INV;
+ register unsigned long reg4 asm("4") = ((unsigned long) pmdp) + 5;
+
+ asm volatile(
+ " csp %1,%3"
+ : "=m" (*pmdp)
+ : "d" (reg2), "d" (reg3), "d" (reg4), "m" (*pmdp) : "cc");
+ pmd_val(*pmdp) = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY;
+}
+
+static inline void __pmd_idte(unsigned long address, pmd_t *pmdp)
+{
+ unsigned long sto = (unsigned long) pmdp -
+ pmd_index(address) * sizeof(pmd_t);
+
+ if (!(pmd_val(*pmdp) & _SEGMENT_ENTRY_INV)) {
+ asm volatile(
+ " .insn rrf,0xb98e0000,%2,%3,0,0"
+ : "=m" (*pmdp)
+ : "m" (*pmdp), "a" (sto),
+ "a" ((address & HPAGE_MASK))
+ );
+ }
+ pmd_val(*pmdp) = _SEGMENT_ENTRY_INV | _SEGMENT_ENTRY;
+}
+
+static inline void huge_ptep_invalidate(struct mm_struct *mm,
+ unsigned long address, pte_t *ptep)
+{
+ pmd_t *pmdp = (pmd_t *) ptep;
+
+ if (!MACHINE_HAS_IDTE) {
+ __pmd_csp(pmdp);
+ if (mm->context.noexec) {
+ pmdp = get_shadow_table(pmdp);
+ __pmd_csp(pmdp);
+ }
+ return;
+ }
+
+ __pmd_idte(address, pmdp);
+ if (mm->context.noexec) {
+ pmdp = get_shadow_table(pmdp);
+ __pmd_idte(address, pmdp);
+ }
+ return;
+}
+
+#define huge_ptep_set_access_flags(__vma, __addr, __ptep, __entry, __dirty) \
+({ \
+ int __changed = !pte_same(huge_ptep_get(__ptep), __entry); \
+ if (__changed) { \
+ huge_ptep_invalidate((__vma)->vm_mm, __addr, __ptep); \
+ set_huge_pte_at((__vma)->vm_mm, __addr, __ptep, __entry); \
+ } \
+ __changed; \
+})
+
+#define huge_ptep_set_wrprotect(__mm, __addr, __ptep) \
+({ \
+ pte_t __pte = huge_ptep_get(__ptep); \
+ if (pte_write(__pte)) { \
+ if (atomic_read(&(__mm)->mm_users) > 1 || \
+ (__mm) != current->active_mm) \
+ huge_ptep_invalidate(__mm, __addr, __ptep); \
+ set_huge_pte_at(__mm, __addr, __ptep, \
+ huge_pte_wrprotect(__pte)); \
+ } \
+})
+
+static inline void huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long address, pte_t *ptep)
+{
+ huge_ptep_invalidate(vma->vm_mm, address, ptep);
+}
+
+#endif /* _ASM_S390_HUGETLB_H */
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
index fe7f92b..f0f4579 100644
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -19,17 +19,34 @@
#define PAGE_DEFAULT_ACC 0
#define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4)
+#define HPAGE_SHIFT 20
+#define HPAGE_SIZE (1UL << HPAGE_SHIFT)
+#define HPAGE_MASK (~(HPAGE_SIZE - 1))
+#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
+
+#define ARCH_HAS_SETCLEAR_HUGE_PTE
+#define ARCH_HAS_HUGE_PTE_TYPE
+#define ARCH_HAS_PREPARE_HUGEPAGE
+#define ARCH_HAS_HUGEPAGE_CLEAR_FLUSH
+
#include <asm/setup.h>
#ifndef __ASSEMBLY__
static inline void clear_page(void *page)
{
- register unsigned long reg1 asm ("1") = 0;
- register void *reg2 asm ("2") = page;
- register unsigned long reg3 asm ("3") = 4096;
- asm volatile(
- " mvcl 2,0"
- : "+d" (reg2), "+d" (reg3) : "d" (reg1) : "memory", "cc");
+ if (MACHINE_HAS_PFMF) {
+ asm volatile(
+ " .insn rre,0xb9af0000,%0,%1"
+ : : "d" (0x10000), "a" (page) : "memory", "cc");
+ } else {
+ register unsigned long reg1 asm ("1") = 0;
+ register void *reg2 asm ("2") = page;
+ register unsigned long reg3 asm ("3") = 4096;
+ asm volatile(
+ " mvcl 2,0"
+ : "+d" (reg2), "+d" (reg3) : "d" (reg1)
+ : "memory", "cc");
+ }
}
static inline void copy_page(void *to, void *from)
@@ -108,26 +125,6 @@
return skey;
}
-extern unsigned long max_pfn;
-
-static inline int pfn_valid(unsigned long pfn)
-{
- unsigned long dummy;
- int ccode;
-
- if (pfn >= max_pfn)
- return 0;
-
- asm volatile(
- " lra %0,0(%2)\n"
- " ipm %1\n"
- " srl %1,28\n"
- : "=d" (dummy), "=d" (ccode)
- : "a" (pfn << PAGE_SHIFT)
- : "cc");
- return !ccode;
-}
-
#endif /* !__ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index f8347ce..c7f4f8e 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -129,7 +129,7 @@
#define VMEM_MAX_PAGES ((VMEM_MAP_END - VMALLOC_END) / sizeof(struct page))
#define VMEM_MAX_PFN min(VMALLOC_START >> PAGE_SHIFT, VMEM_MAX_PAGES)
#define VMEM_MAX_PHYS ((VMEM_MAX_PFN << PAGE_SHIFT) & ~((16 << 20) - 1))
-#define VMEM_MAP ((struct page *) VMALLOC_END)
+#define vmemmap ((struct page *) VMALLOC_END)
/*
* A 31 bit pagetable entry of S390 has following format:
@@ -234,6 +234,15 @@
#define _PAGE_TYPE_EX_RW 0x002
/*
+ * Only four types for huge pages, using the invalid bit and protection bit
+ * of a segment table entry.
+ */
+#define _HPAGE_TYPE_EMPTY 0x020 /* _SEGMENT_ENTRY_INV */
+#define _HPAGE_TYPE_NONE 0x220
+#define _HPAGE_TYPE_RO 0x200 /* _SEGMENT_ENTRY_RO */
+#define _HPAGE_TYPE_RW 0x000
+
+/*
* PTE type bits are rather complicated. handle_pte_fault uses pte_present,
* pte_none and pte_file to find out the pte type WITHOUT holding the page
* table lock. ptep_clear_flush on the other hand uses ptep_clear_flush to
@@ -325,6 +334,9 @@
#define _SEGMENT_ENTRY (0)
#define _SEGMENT_ENTRY_EMPTY (_SEGMENT_ENTRY_INV)
+#define _SEGMENT_ENTRY_LARGE 0x400 /* STE-format control, large page */
+#define _SEGMENT_ENTRY_CO 0x100 /* change-recording override */
+
#endif /* __s390x__ */
/*
@@ -1063,8 +1075,8 @@
#define kern_addr_valid(addr) (1)
-extern int add_shared_memory(unsigned long start, unsigned long size);
-extern int remove_shared_memory(unsigned long start, unsigned long size);
+extern int vmem_add_mapping(unsigned long start, unsigned long size);
+extern int vmem_remove_mapping(unsigned long start, unsigned long size);
extern int s390_enable_sie(void);
/*
@@ -1072,9 +1084,6 @@
*/
#define pgtable_cache_init() do { } while (0)
-#define __HAVE_ARCH_MEMMAP_INIT
-extern void memmap_init(unsigned long, int, unsigned long, unsigned long);
-
#include <asm-generic/pgtable.h>
#endif /* _S390_PAGE_H */
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index 8eaf343..a00f79d 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -172,16 +172,7 @@
*/
extern void task_show_regs(struct seq_file *m, struct task_struct *task);
-extern void show_registers(struct pt_regs *regs);
extern void show_code(struct pt_regs *regs);
-extern void show_trace(struct task_struct *task, unsigned long *sp);
-#ifdef CONFIG_64BIT
-extern void show_last_breaking_event(struct pt_regs *regs);
-#else
-static inline void show_last_breaking_event(struct pt_regs *regs)
-{
-}
-#endif
unsigned long get_wchan(struct task_struct *p);
#define task_pt_regs(tsk) ((struct pt_regs *) \
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
index 61f6952..441d7c2 100644
--- a/include/asm-s390/ptrace.h
+++ b/include/asm-s390/ptrace.h
@@ -463,8 +463,6 @@
};
#ifdef __KERNEL__
-#define __ARCH_SYS_PTRACE 1
-
/*
* These are defined as per linux/ptrace.h, which see.
*/
diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
index 4b8ff55..1124034 100644
--- a/include/asm-s390/qdio.h
+++ b/include/asm-s390/qdio.h
@@ -127,6 +127,7 @@
unsigned int qidx,unsigned int count,
struct qdio_buffer *buffers);
+extern int qdio_get_ssqd_pct(struct ccw_device*);
extern int qdio_synchronize(struct ccw_device*, unsigned int flags,
unsigned int queue_number);
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h
index aaf4b51..ba69674 100644
--- a/include/asm-s390/setup.h
+++ b/include/asm-s390/setup.h
@@ -59,23 +59,42 @@
*/
extern unsigned long machine_flags;
-#define MACHINE_IS_VM (machine_flags & 1)
-#define MACHINE_IS_P390 (machine_flags & 4)
-#define MACHINE_HAS_MVPG (machine_flags & 16)
-#define MACHINE_IS_KVM (machine_flags & 64)
-#define MACHINE_HAS_IDTE (machine_flags & 128)
-#define MACHINE_HAS_DIAG9C (machine_flags & 256)
+#define MACHINE_FLAG_VM (1UL << 0)
+#define MACHINE_FLAG_IEEE (1UL << 1)
+#define MACHINE_FLAG_P390 (1UL << 2)
+#define MACHINE_FLAG_CSP (1UL << 3)
+#define MACHINE_FLAG_MVPG (1UL << 4)
+#define MACHINE_FLAG_DIAG44 (1UL << 5)
+#define MACHINE_FLAG_IDTE (1UL << 6)
+#define MACHINE_FLAG_DIAG9C (1UL << 7)
+#define MACHINE_FLAG_MVCOS (1UL << 8)
+#define MACHINE_FLAG_KVM (1UL << 9)
+#define MACHINE_FLAG_HPAGE (1UL << 10)
+#define MACHINE_FLAG_PFMF (1UL << 11)
+
+#define MACHINE_IS_VM (machine_flags & MACHINE_FLAG_VM)
+#define MACHINE_IS_KVM (machine_flags & MACHINE_FLAG_KVM)
+#define MACHINE_IS_P390 (machine_flags & MACHINE_FLAG_P390)
+#define MACHINE_HAS_DIAG9C (machine_flags & MACHINE_FLAG_DIAG9C)
#ifndef __s390x__
-#define MACHINE_HAS_IEEE (machine_flags & 2)
-#define MACHINE_HAS_CSP (machine_flags & 8)
+#define MACHINE_HAS_IEEE (machine_flags & MACHINE_FLAG_IEEE)
+#define MACHINE_HAS_CSP (machine_flags & MACHINE_FLAG_CSP)
+#define MACHINE_HAS_IDTE (0)
#define MACHINE_HAS_DIAG44 (1)
+#define MACHINE_HAS_MVPG (machine_flags & MACHINE_FLAG_MVPG)
#define MACHINE_HAS_MVCOS (0)
+#define MACHINE_HAS_HPAGE (0)
+#define MACHINE_HAS_PFMF (0)
#else /* __s390x__ */
#define MACHINE_HAS_IEEE (1)
#define MACHINE_HAS_CSP (1)
-#define MACHINE_HAS_DIAG44 (machine_flags & 32)
-#define MACHINE_HAS_MVCOS (machine_flags & 512)
+#define MACHINE_HAS_IDTE (machine_flags & MACHINE_FLAG_IDTE)
+#define MACHINE_HAS_DIAG44 (machine_flags & MACHINE_FLAG_DIAG44)
+#define MACHINE_HAS_MVPG (1)
+#define MACHINE_HAS_MVCOS (machine_flags & MACHINE_FLAG_MVCOS)
+#define MACHINE_HAS_HPAGE (machine_flags & MACHINE_FLAG_HPAGE)
+#define MACHINE_HAS_PFMF (machine_flags & MACHINE_FLAG_PFMF)
#endif /* __s390x__ */
#define MACHINE_HAS_SCLP (!MACHINE_IS_P390)
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
index 6f3821a..ae89cf2 100644
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -19,6 +19,7 @@
#include <asm/lowcore.h>
#include <asm/sigp.h>
#include <asm/ptrace.h>
+#include <asm/system.h>
/*
s390 specific smp.c headers
@@ -53,10 +54,7 @@
static inline __u16 hard_smp_processor_id(void)
{
- __u16 cpu_address;
-
- asm volatile("stap %0" : "=m" (cpu_address));
- return cpu_address;
+ return stap();
}
/*
@@ -108,5 +106,11 @@
#define smp_cpu_not_running(cpu) 1
#endif
+#ifdef CONFIG_HOTPLUG_CPU
+extern int smp_rescan_cpus(void);
+#else
+static inline int smp_rescan_cpus(void) { return 0; }
+#endif
+
extern union save_area *zfcpdump_save_areas[NR_CPUS + 1];
#endif
diff --git a/include/asm-s390/sparsemem.h b/include/asm-s390/sparsemem.h
new file mode 100644
index 0000000..06dfdab
--- /dev/null
+++ b/include/asm-s390/sparsemem.h
@@ -0,0 +1,18 @@
+#ifndef _ASM_S390_SPARSEMEM_H
+#define _ASM_S390_SPARSEMEM_H
+
+#define SECTION_SIZE_BITS 25
+
+#ifdef CONFIG_64BIT
+
+#define MAX_PHYSADDR_BITS 42
+#define MAX_PHYSMEM_BITS 42
+
+#else
+
+#define MAX_PHYSADDR_BITS 31
+#define MAX_PHYSMEM_BITS 31
+
+#endif /* CONFIG_64BIT */
+
+#endif /* _ASM_S390_SPARSEMEM_H */
diff --git a/include/asm-s390/sysinfo.h b/include/asm-s390/sysinfo.h
index abe10ae..79d0134 100644
--- a/include/asm-s390/sysinfo.h
+++ b/include/asm-s390/sysinfo.h
@@ -11,6 +11,9 @@
* Christian Borntraeger <borntraeger@de.ibm.com>
*/
+#ifndef __ASM_S390_SYSINFO_H
+#define __ASM_S390_SYSINFO_H
+
struct sysinfo_1_1_1 {
char reserved_0[32];
char manufacturer[16];
@@ -114,3 +117,5 @@
: "cc", "memory");
return r0;
}
+
+#endif /* __ASM_S390_SYSINFO_H */
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index 92098df..c819ae2 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -16,6 +16,7 @@
#include <asm/ptrace.h>
#include <asm/setup.h>
#include <asm/processor.h>
+#include <asm/lowcore.h>
#ifdef __KERNEL__
@@ -422,6 +423,23 @@
#endif /* CONFIG_SMP */
+static inline unsigned int stfl(void)
+{
+ asm volatile(
+ " .insn s,0xb2b10000,0(0)\n" /* stfl */
+ "0:\n"
+ EX_TABLE(0b,0b));
+ return S390_lowcore.stfl_fac_list;
+}
+
+static inline unsigned short stap(void)
+{
+ unsigned short cpu_address;
+
+ asm volatile("stap %0" : "=m" (cpu_address));
+ return cpu_address;
+}
+
extern void (*_machine_restart)(char *command);
extern void (*_machine_halt)(void);
extern void (*_machine_power_off)(void);
diff --git a/include/asm-s390/thread_info.h b/include/asm-s390/thread_info.h
index 0a51891..99bbed9 100644
--- a/include/asm-s390/thread_info.h
+++ b/include/asm-s390/thread_info.h
@@ -89,7 +89,6 @@
* thread information flags bit numbers
*/
#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
-#define TIF_RESTORE_SIGMASK 1 /* restore signal mask in do_signal() */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
#define TIF_RESTART_SVC 4 /* restart svc with new svc number */
@@ -101,6 +100,7 @@
TIF_NEED_RESCHED */
#define TIF_31BIT 18 /* 32bit process */
#define TIF_MEMDIE 19
+#define TIF_RESTORE_SIGMASK 20 /* restore signal mask in do_signal() */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h
index 9e57a93..d60394b 100644
--- a/include/asm-s390/tlbflush.h
+++ b/include/asm-s390/tlbflush.h
@@ -2,6 +2,7 @@
#define _S390_TLBFLUSH_H
#include <linux/mm.h>
+#include <linux/sched.h>
#include <asm/processor.h>
#include <asm/pgalloc.h>
diff --git a/include/asm-s390/topology.h b/include/asm-s390/topology.h
index 8e97b06..d96c916 100644
--- a/include/asm-s390/topology.h
+++ b/include/asm-s390/topology.h
@@ -7,6 +7,10 @@
cpumask_t cpu_coregroup_map(unsigned int cpu);
+extern cpumask_t cpu_core_map[NR_CPUS];
+
+#define topology_core_siblings(cpu) (cpu_core_map[cpu])
+
int topology_set_cpu_management(int fc);
void topology_schedule_update(void);
diff --git a/include/asm-s390/unaligned.h b/include/asm-s390/unaligned.h
index 8ee86db..da9627a 100644
--- a/include/asm-s390/unaligned.h
+++ b/include/asm-s390/unaligned.h
@@ -1,24 +1,13 @@
-/*
- * include/asm-s390/unaligned.h
- *
- * S390 version
- *
- * Derived from "include/asm-i386/unaligned.h"
- */
-
-#ifndef __S390_UNALIGNED_H
-#define __S390_UNALIGNED_H
+#ifndef _ASM_S390_UNALIGNED_H
+#define _ASM_S390_UNALIGNED_H
/*
* The S390 can do unaligned accesses itself.
- *
- * The strange macros are there to make sure these can't
- * be misused in a way that makes them not work on other
- * architectures where unaligned accesses aren't as simple.
*/
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
-#define get_unaligned(ptr) (*(ptr))
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
-#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) ))
-
-#endif
+#endif /* _ASM_S390_UNALIGNED_H */
diff --git a/include/asm-sh/futex.h b/include/asm-sh/futex.h
index 74ed368..68256ec 100644
--- a/include/asm-sh/futex.h
+++ b/include/asm-sh/futex.h
@@ -4,8 +4,8 @@
#ifdef __KERNEL__
#include <linux/futex.h>
+#include <linux/uaccess.h>
#include <asm/errno.h>
-#include <asm/uaccess.h>
/* XXX: UP variants, fix for SH-4A and SMP.. */
#include <asm/futex-irq.h>
diff --git a/include/asm-sh/unaligned.h b/include/asm-sh/unaligned.h
index 5250e30..c1641a0 100644
--- a/include/asm-sh/unaligned.h
+++ b/include/asm-sh/unaligned.h
@@ -1,7 +1,19 @@
-#ifndef __ASM_SH_UNALIGNED_H
-#define __ASM_SH_UNALIGNED_H
+#ifndef _ASM_SH_UNALIGNED_H
+#define _ASM_SH_UNALIGNED_H
/* SH can't handle unaligned accesses. */
-#include <asm-generic/unaligned.h>
+#ifdef __LITTLE_ENDIAN__
+# include <linux/unaligned/le_struct.h>
+# include <linux/unaligned/be_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_le
+# define put_unaligned __put_unaligned_le
+#else
+# include <linux/unaligned/be_struct.h>
+# include <linux/unaligned/le_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_be
+# define put_unaligned __put_unaligned_be
+#endif
-#endif /* __ASM_SH_UNALIGNED_H */
+#endif /* _ASM_SH_UNALIGNED_H */
diff --git a/include/asm-sparc/head.h b/include/asm-sparc/head.h
index fcdba51..e6532c3 100644
--- a/include/asm-sparc/head.h
+++ b/include/asm-sparc/head.h
@@ -52,6 +52,17 @@
nop; \
nop;
+#ifdef CONFIG_KGDB
+#define KGDB_TRAP(num) \
+ b kgdb_trap_low; \
+ rd %psr,%l0; \
+ nop; \
+ nop;
+#else
+#define KGDB_TRAP(num) \
+ BAD_TRAP(num)
+#endif
+
/* The Get Condition Codes software trap for userland. */
#define GETCC_TRAP \
b getcc_trap_handler; mov %psr, %l0; nop; nop;
diff --git a/include/asm-sparc/kgdb.h b/include/asm-sparc/kgdb.h
index d120adf..b6ef301 100644
--- a/include/asm-sparc/kgdb.h
+++ b/include/asm-sparc/kgdb.h
@@ -1,94 +1,38 @@
-/* $Id: kgdb.h,v 1.8 1998/01/07 06:33:44 baccala Exp $
- * kgdb.h: Defines and declarations for serial line source level
- * remote debugging of the Linux kernel using gdb.
- *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
#ifndef _SPARC_KGDB_H
#define _SPARC_KGDB_H
-#ifndef __ASSEMBLY__
-/* To init the kgdb engine. */
-extern void set_debug_traps(void);
+#ifdef CONFIG_SPARC32
+#define BUFMAX 2048
+#else
+#define BUFMAX 4096
+#endif
-/* To enter the debugger explicitly. */
-extern void breakpoint(void);
-
-/* For convenience we define the format of a kgdb trap breakpoint
- * frame here also.
- */
-struct kgdb_frame {
- unsigned long globals[8];
- unsigned long outs[8];
- unsigned long locals[8];
- unsigned long ins[8];
- unsigned long fpregs[32];
- unsigned long y;
- unsigned long psr;
- unsigned long wim;
- unsigned long tbr;
- unsigned long pc;
- unsigned long npc;
- unsigned long fpsr;
- unsigned long cpsr;
+enum regnames {
+ GDB_G0, GDB_G1, GDB_G2, GDB_G3, GDB_G4, GDB_G5, GDB_G6, GDB_G7,
+ GDB_O0, GDB_O1, GDB_O2, GDB_O3, GDB_O4, GDB_O5, GDB_SP, GDB_O7,
+ GDB_L0, GDB_L1, GDB_L2, GDB_L3, GDB_L4, GDB_L5, GDB_L6, GDB_L7,
+ GDB_I0, GDB_I1, GDB_I2, GDB_I3, GDB_I4, GDB_I5, GDB_FP, GDB_I7,
+ GDB_F0,
+ GDB_F31 = GDB_F0 + 31,
+#ifdef CONFIG_SPARC32
+ GDB_Y, GDB_PSR, GDB_WIM, GDB_TBR, GDB_PC, GDB_NPC,
+ GDB_FSR, GDB_CSR,
+#else
+ GDB_F32 = GDB_F0 + 32,
+ GDB_F62 = GDB_F32 + 15,
+ GDB_PC, GDB_NPC, GDB_STATE, GDB_FSR, GDB_FPRS, GDB_Y,
+#endif
};
-#endif /* !(__ASSEMBLY__) */
-/* Macros for assembly usage of the kgdb breakpoint frame. */
-#define KGDB_G0 0x000
-#define KGDB_G1 0x004
-#define KGDB_G2 0x008
-#define KGDB_G4 0x010
-#define KGDB_G6 0x018
-#define KGDB_I0 0x020
-#define KGDB_I2 0x028
-#define KGDB_I4 0x030
-#define KGDB_I6 0x038
-#define KGDB_Y 0x100
-#define KGDB_PSR 0x104
-#define KGDB_WIM 0x108
-#define KGDB_TBR 0x10c
-#define KGDB_PC 0x110
-#define KGDB_NPC 0x114
+#ifdef CONFIG_SPARC32
+#define NUMREGBYTES ((GDB_CSR + 1) * 4)
+#else
+#define NUMREGBYTES ((GDB_Y + 1) * 8)
+#endif
-#define SAVE_KGDB_GLOBALS(reg) \
- std %g0, [%reg + STACKFRAME_SZ + KGDB_G0]; \
- std %g2, [%reg + STACKFRAME_SZ + KGDB_G2]; \
- std %g4, [%reg + STACKFRAME_SZ + KGDB_G4]; \
- std %g6, [%reg + STACKFRAME_SZ + KGDB_G6];
+extern void arch_kgdb_breakpoint(void);
-#define SAVE_KGDB_INS(reg) \
- std %i0, [%reg + STACKFRAME_SZ + KGDB_I0]; \
- std %i2, [%reg + STACKFRAME_SZ + KGDB_I2]; \
- std %i4, [%reg + STACKFRAME_SZ + KGDB_I4]; \
- std %i6, [%reg + STACKFRAME_SZ + KGDB_I6];
+#define BREAK_INSTR_SIZE 4
+#define CACHE_FLUSH_IS_SAFE 1
-#define SAVE_KGDB_SREGS(reg, reg_y, reg_psr, reg_wim, reg_tbr, reg_pc, reg_npc) \
- st %reg_y, [%reg + STACKFRAME_SZ + KGDB_Y]; \
- st %reg_psr, [%reg + STACKFRAME_SZ + KGDB_PSR]; \
- st %reg_wim, [%reg + STACKFRAME_SZ + KGDB_WIM]; \
- st %reg_tbr, [%reg + STACKFRAME_SZ + KGDB_TBR]; \
- st %reg_pc, [%reg + STACKFRAME_SZ + KGDB_PC]; \
- st %reg_npc, [%reg + STACKFRAME_SZ + KGDB_NPC];
-
-#define LOAD_KGDB_GLOBALS(reg) \
- ld [%reg + STACKFRAME_SZ + KGDB_G1], %g1; \
- ldd [%reg + STACKFRAME_SZ + KGDB_G2], %g2; \
- ldd [%reg + STACKFRAME_SZ + KGDB_G4], %g4; \
- ldd [%reg + STACKFRAME_SZ + KGDB_G6], %g6;
-
-#define LOAD_KGDB_INS(reg) \
- ldd [%reg + STACKFRAME_SZ + KGDB_I0], %i0; \
- ldd [%reg + STACKFRAME_SZ + KGDB_I2], %i2; \
- ldd [%reg + STACKFRAME_SZ + KGDB_I4], %i4; \
- ldd [%reg + STACKFRAME_SZ + KGDB_I6], %i6;
-
-#define LOAD_KGDB_SREGS(reg, reg_y, reg_psr, reg_wim, reg_tbr, reg_pc, reg_npc) \
- ld [%reg + STACKFRAME_SZ + KGDB_Y], %reg_y; \
- ld [%reg + STACKFRAME_SZ + KGDB_PSR], %reg_psr; \
- ld [%reg + STACKFRAME_SZ + KGDB_WIM], %reg_wim; \
- ld [%reg + STACKFRAME_SZ + KGDB_TBR], %reg_tbr; \
- ld [%reg + STACKFRAME_SZ + KGDB_PC], %reg_pc; \
- ld [%reg + STACKFRAME_SZ + KGDB_NPC], %reg_npc;
-
-#endif /* !(_SPARC_KGDB_H) */
+#endif /* _SPARC_KGDB_H */
diff --git a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h
index b3f4922..e6d5615 100644
--- a/include/asm-sparc/smp.h
+++ b/include/asm-sparc/smp.h
@@ -51,13 +51,11 @@
void smp_info(struct seq_file *);
BTFIXUPDEF_CALL(void, smp_cross_call, smpfunc_t, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long)
-BTFIXUPDEF_CALL(void, smp_message_pass, int, int, unsigned long, int)
BTFIXUPDEF_CALL(int, __hard_smp_processor_id, void)
BTFIXUPDEF_BLACKBOX(hard_smp_processor_id)
BTFIXUPDEF_BLACKBOX(load_current)
#define smp_cross_call(func,arg1,arg2,arg3,arg4,arg5) BTFIXUP_CALL(smp_cross_call)(func,arg1,arg2,arg3,arg4,arg5)
-#define smp_message_pass(target,msg,data,wait) BTFIXUP_CALL(smp_message_pass)(target,msg,data,wait)
static inline void xc0(smpfunc_t func) { smp_cross_call(func, 0, 0, 0, 0, 0); }
static inline void xc1(smpfunc_t func, unsigned long arg1)
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index 4e08210c..b4b0244 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -94,6 +94,8 @@
} while(0)
#endif
+extern void flushw_all(void);
+
/*
* Flush windows so that the VM switch which follows
* would not pull the stack from under us.
diff --git a/include/asm-sparc/unaligned.h b/include/asm-sparc/unaligned.h
index b6f8edd..11d2d5f 100644
--- a/include/asm-sparc/unaligned.h
+++ b/include/asm-sparc/unaligned.h
@@ -1,6 +1,10 @@
-#ifndef _ASM_SPARC_UNALIGNED_H_
-#define _ASM_SPARC_UNALIGNED_H_
+#ifndef _ASM_SPARC_UNALIGNED_H
+#define _ASM_SPARC_UNALIGNED_H
-#include <asm-generic/unaligned.h>
+#include <linux/unaligned/be_struct.h>
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/generic.h>
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
#endif /* _ASM_SPARC_UNALIGNED_H */
diff --git a/include/asm-sparc64/futex.h b/include/asm-sparc64/futex.h
index df1097d..d837893 100644
--- a/include/asm-sparc64/futex.h
+++ b/include/asm-sparc64/futex.h
@@ -2,9 +2,9 @@
#define _SPARC64_FUTEX_H
#include <linux/futex.h>
+#include <linux/uaccess.h>
#include <asm/errno.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
#define __futex_cas_op(insn, ret, oldval, uaddr, oparg) \
__asm__ __volatile__( \
diff --git a/include/asm-sparc64/kgdb.h b/include/asm-sparc64/kgdb.h
new file mode 100644
index 0000000..aa6532f
--- /dev/null
+++ b/include/asm-sparc64/kgdb.h
@@ -0,0 +1 @@
+#include <asm-sparc/kgdb.h>
diff --git a/include/asm-sparc64/pil.h b/include/asm-sparc64/pil.h
index 7292774..2f5d126 100644
--- a/include/asm-sparc64/pil.h
+++ b/include/asm-sparc64/pil.h
@@ -19,11 +19,4 @@
#define PIL_SMP_CTX_NEW_VERSION 4
#define PIL_DEVICE_IRQ 5
-#ifndef __ASSEMBLY__
-#define PIL_RESERVED(PIL) ((PIL) == PIL_SMP_CALL_FUNC || \
- (PIL) == PIL_SMP_RECEIVE_SIGNAL || \
- (PIL) == PIL_SMP_CAPTURE || \
- (PIL) == PIL_SMP_CTX_NEW_VERSION)
-#endif
-
#endif /* !(_SPARC64_PIL_H) */
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index 53eae091..6897ac3 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -180,12 +180,13 @@
"ldx [%%sp + 2047 + 0x70], %%i6\n\t" \
"ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
"ldx [%%g6 + %9], %%g4\n\t" \
- "brz,pt %%o7, 1f\n\t" \
+ "brz,pt %%o7, switch_to_pc\n\t" \
" mov %%g7, %0\n\t" \
"sethi %%hi(ret_from_syscall), %%g1\n\t" \
"jmpl %%g1 + %%lo(ret_from_syscall), %%g0\n\t" \
" nop\n\t" \
- "1:\n\t" \
+ ".globl switch_to_pc\n\t" \
+ "switch_to_pc:\n\t" \
: "=&r" (last), "=r" (current), "=r" (current_thread_info_reg), \
"=r" (__local_per_cpu_offset) \
: "0" (task_thread_info(next)), \
diff --git a/include/asm-sparc64/ttable.h b/include/asm-sparc64/ttable.h
index d3cc4ef..1b55538 100644
--- a/include/asm-sparc64/ttable.h
+++ b/include/asm-sparc64/ttable.h
@@ -175,6 +175,12 @@
#define KPROBES_TRAP(lvl) TRAP_ARG(bad_trap, lvl)
#endif
+#ifdef CONFIG_KGDB
+#define KGDB_TRAP(lvl) TRAP_IRQ(kgdb_trap, lvl)
+#else
+#define KGDB_TRAP(lvl) TRAP_ARG(bad_trap, lvl)
+#endif
+
#define SUN4V_ITSB_MISS \
ldxa [%g0] ASI_SCRATCHPAD, %g2; \
ldx [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4; \
diff --git a/include/asm-sparc64/unaligned.h b/include/asm-sparc64/unaligned.h
index 1ed3ba5..edcebb0 100644
--- a/include/asm-sparc64/unaligned.h
+++ b/include/asm-sparc64/unaligned.h
@@ -1,6 +1,10 @@
-#ifndef _ASM_SPARC64_UNALIGNED_H_
-#define _ASM_SPARC64_UNALIGNED_H_
+#ifndef _ASM_SPARC64_UNALIGNED_H
+#define _ASM_SPARC64_UNALIGNED_H
-#include <asm-generic/unaligned.h>
+#include <linux/unaligned/be_struct.h>
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/generic.h>
+#define get_unaligned __get_unaligned_be
+#define put_unaligned __put_unaligned_be
#endif /* _ASM_SPARC64_UNALIGNED_H */
diff --git a/include/asm-um/div64.h b/include/asm-um/div64.h
index 7b73b2c..1e17f74 100644
--- a/include/asm-um/div64.h
+++ b/include/asm-um/div64.h
@@ -3,5 +3,4 @@
#include "asm/arch/div64.h"
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
#endif
diff --git a/include/asm-um/unaligned.h b/include/asm-um/unaligned.h
index 1d2497c..a471969 100644
--- a/include/asm-um/unaligned.h
+++ b/include/asm-um/unaligned.h
@@ -1,6 +1,6 @@
-#ifndef __UM_UNALIGNED_H
-#define __UM_UNALIGNED_H
+#ifndef _ASM_UM_UNALIGNED_H
+#define _ASM_UM_UNALIGNED_H
#include "asm/arch/unaligned.h"
-#endif
+#endif /* _ASM_UM_UNALIGNED_H */
diff --git a/include/asm-v850/unaligned.h b/include/asm-v850/unaligned.h
index e30b186..53122b2 100644
--- a/include/asm-v850/unaligned.h
+++ b/include/asm-v850/unaligned.h
@@ -1,6 +1,4 @@
/*
- * include/asm-v850/unaligned.h -- Unaligned memory access
- *
* Copyright (C) 2001 NEC Corporation
* Copyright (C) 2001 Miles Bader <miles@gnu.org>
*
@@ -8,123 +6,17 @@
* Public License. See the file COPYING in the main directory of this
* archive for more details.
*
- * This file is a copy of the arm version, include/asm-arm/unaligned.h
- *
* Note that some v850 chips support unaligned access, but it seems too
* annoying to use.
*/
+#ifndef _ASM_V850_UNALIGNED_H
+#define _ASM_V850_UNALIGNED_H
-#ifndef __V850_UNALIGNED_H__
-#define __V850_UNALIGNED_H__
+#include <linux/unaligned/be_byteshift.h>
+#include <linux/unaligned/le_byteshift.h>
+#include <linux/unaligned/generic.h>
-#include <asm/types.h>
+#define get_unaligned __get_unaligned_le
+#define put_unaligned __put_unaligned_le
-extern int __bug_unaligned_x(void *ptr);
-
-/*
- * What is the most efficient way of loading/storing an unaligned value?
- *
- * That is the subject of this file. Efficiency here is defined as
- * minimum code size with minimum register usage for the common cases.
- * It is currently not believed that long longs are common, so we
- * trade efficiency for the chars, shorts and longs against the long
- * longs.
- *
- * Current stats with gcc 2.7.2.2 for these functions:
- *
- * ptrsize get: code regs put: code regs
- * 1 1 1 1 2
- * 2 3 2 3 2
- * 4 7 3 7 3
- * 8 20 6 16 6
- *
- * gcc 2.95.1 seems to code differently:
- *
- * ptrsize get: code regs put: code regs
- * 1 1 1 1 2
- * 2 3 2 3 2
- * 4 7 4 7 4
- * 8 19 8 15 6
- *
- * which may or may not be more efficient (depending upon whether
- * you can afford the extra registers). Hopefully the gcc 2.95
- * is inteligent enough to decide if it is better to use the
- * extra register, but evidence so far seems to suggest otherwise.
- *
- * Unfortunately, gcc is not able to optimise the high word
- * out of long long >> 32, or the low word from long long << 32
- */
-
-#define __get_unaligned_2(__p) \
- (__p[0] | __p[1] << 8)
-
-#define __get_unaligned_4(__p) \
- (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24)
-
-#define get_unaligned(ptr) \
- ({ \
- __typeof__(*(ptr)) __v; \
- __u8 *__p = (__u8 *)(ptr); \
- switch (sizeof(*(ptr))) { \
- case 1: __v = *(ptr); break; \
- case 2: __v = __get_unaligned_2(__p); break; \
- case 4: __v = __get_unaligned_4(__p); break; \
- case 8: { \
- unsigned int __v1, __v2; \
- __v2 = __get_unaligned_4((__p+4)); \
- __v1 = __get_unaligned_4(__p); \
- __v = ((unsigned long long)__v2 << 32 | __v1); \
- } \
- break; \
- default: __v = __bug_unaligned_x(__p); break; \
- } \
- __v; \
- })
-
-
-static inline void __put_unaligned_2(__u32 __v, register __u8 *__p)
-{
- *__p++ = __v;
- *__p++ = __v >> 8;
-}
-
-static inline void __put_unaligned_4(__u32 __v, register __u8 *__p)
-{
- __put_unaligned_2(__v >> 16, __p + 2);
- __put_unaligned_2(__v, __p);
-}
-
-static inline void __put_unaligned_8(const unsigned long long __v, register __u8 *__p)
-{
- /*
- * tradeoff: 8 bytes of stack for all unaligned puts (2
- * instructions), or an extra register in the long long
- * case - go for the extra register.
- */
- __put_unaligned_4(__v >> 32, __p+4);
- __put_unaligned_4(__v, __p);
-}
-
-/*
- * Try to store an unaligned value as efficiently as possible.
- */
-#define put_unaligned(val,ptr) \
- ({ \
- switch (sizeof(*(ptr))) { \
- case 1: \
- *(ptr) = (val); \
- break; \
- case 2: __put_unaligned_2((val),(__u8 *)(ptr)); \
- break; \
- case 4: __put_unaligned_4((val),(__u8 *)(ptr)); \
- break; \
- case 8: __put_unaligned_8((val),(__u8 *)(ptr)); \
- break; \
- default: __bug_unaligned_x(ptr); \
- break; \
- } \
- (void) 0; \
- })
-
-
-#endif /* __V850_UNALIGNED_H__ */
+#endif /* _ASM_V850_UNALIGNED_H */
diff --git a/include/asm-x86/div64.h b/include/asm-x86/div64.h
index 0dbf8bf..9a2d644 100644
--- a/include/asm-x86/div64.h
+++ b/include/asm-x86/div64.h
@@ -33,25 +33,25 @@
__mod; \
})
-/*
- * (long)X = ((long long)divs) / (long)div
- * (long)rem = ((long long)divs) % (long)div
- *
- * Warning, this will do an exception if X overflows.
- */
-#define div_long_long_rem(a, b, c) div_ll_X_l_rem(a, b, c)
-
-static inline long div_ll_X_l_rem(long long divs, long div, long *rem)
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
{
- long dum2;
- asm("divl %2":"=a"(dum2), "=d"(*rem)
- : "rm"(div), "A"(divs));
+ union {
+ u64 v64;
+ u32 v32[2];
+ } d = { dividend };
+ u32 upper;
- return dum2;
-
+ upper = d.v32[1];
+ d.v32[1] = 0;
+ if (upper >= divisor) {
+ d.v32[1] = upper / divisor;
+ upper %= divisor;
+ }
+ asm ("divl %2" : "=a" (d.v32[0]), "=d" (*remainder) :
+ "rm" (divisor), "0" (d.v32[0]), "1" (upper));
+ return d.v64;
}
-
-extern uint64_t div64_64(uint64_t dividend, uint64_t divisor);
+#define div_u64_rem div_u64_rem
#else
# include <asm-generic/div64.h>
diff --git a/include/asm-x86/dmi.h b/include/asm-x86/dmi.h
index 1241e6a..4edf751 100644
--- a/include/asm-x86/dmi.h
+++ b/include/asm-x86/dmi.h
@@ -27,6 +27,7 @@
#endif
+/* Use early IO mappings for DMI because it's initialized early */
#define dmi_ioremap early_ioremap
#define dmi_iounmap early_iounmap
diff --git a/include/asm-x86/futex.h b/include/asm-x86/futex.h
index ac0fbf2..e7a76b3 100644
--- a/include/asm-x86/futex.h
+++ b/include/asm-x86/futex.h
@@ -4,12 +4,12 @@
#ifdef __KERNEL__
#include <linux/futex.h>
+#include <linux/uaccess.h>
#include <asm/asm.h>
#include <asm/errno.h>
#include <asm/processor.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
asm volatile("1:\t" insn "\n" \
diff --git a/include/asm-x86/io_32.h b/include/asm-x86/io_32.h
index 6e73467..049e81e 100644
--- a/include/asm-x86/io_32.h
+++ b/include/asm-x86/io_32.h
@@ -133,11 +133,6 @@
extern void early_iounmap(void *addr, unsigned long size);
extern void __iomem *fix_ioremap(unsigned idx, unsigned long phys);
-/* Use early IO mappings for DMI because it's initialized early */
-#define dmi_ioremap early_ioremap
-#define dmi_iounmap early_iounmap
-#define dmi_alloc alloc_bootmem
-
/*
* ISA I/O bus memory addresses are 1:1 with the physical address.
*/
diff --git a/include/asm-x86/mach-default/mach_apic.h b/include/asm-x86/mach-default/mach_apic.h
index 0a6634f..21003b5 100644
--- a/include/asm-x86/mach-default/mach_apic.h
+++ b/include/asm-x86/mach-default/mach_apic.h
@@ -109,13 +109,8 @@
static inline int cpu_present_to_apicid(int mps_cpu)
{
-#ifdef CONFIG_X86_64
- if (cpu_present(mps_cpu))
+ if (mps_cpu < NR_CPUS && cpu_present(mps_cpu))
return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
-#else
- if (mps_cpu < get_physical_broadcast())
- return mps_cpu;
-#endif
else
return BAD_APICID;
}
diff --git a/include/asm-x86/olpc.h b/include/asm-x86/olpc.h
new file mode 100644
index 0000000..97d4713
--- /dev/null
+++ b/include/asm-x86/olpc.h
@@ -0,0 +1,132 @@
+/* OLPC machine specific definitions */
+
+#ifndef ASM_OLPC_H_
+#define ASM_OLPC_H_
+
+#include <asm/geode.h>
+
+struct olpc_platform_t {
+ int flags;
+ uint32_t boardrev;
+ int ecver;
+};
+
+#define OLPC_F_PRESENT 0x01
+#define OLPC_F_DCON 0x02
+#define OLPC_F_VSA 0x04
+
+#ifdef CONFIG_OLPC
+
+extern struct olpc_platform_t olpc_platform_info;
+
+/*
+ * OLPC board IDs contain the major build number within the mask 0x0ff0,
+ * and the minor build number withing 0x000f. Pre-builds have a minor
+ * number less than 8, and normal builds start at 8. For example, 0x0B10
+ * is a PreB1, and 0x0C18 is a C1.
+ */
+
+static inline uint32_t olpc_board(uint8_t id)
+{
+ return (id << 4) | 0x8;
+}
+
+static inline uint32_t olpc_board_pre(uint8_t id)
+{
+ return id << 4;
+}
+
+static inline int machine_is_olpc(void)
+{
+ return (olpc_platform_info.flags & OLPC_F_PRESENT) ? 1 : 0;
+}
+
+/*
+ * The DCON is OLPC's Display Controller. It has a number of unique
+ * features that we might want to take advantage of..
+ */
+static inline int olpc_has_dcon(void)
+{
+ return (olpc_platform_info.flags & OLPC_F_DCON) ? 1 : 0;
+}
+
+/*
+ * The VSA is software from AMD that typical Geode bioses will include.
+ * It is used to emulate the PCI bus, VGA, etc. OLPC's Open Firmware does
+ * not include the VSA; instead, PCI is emulated by the kernel.
+ *
+ * The VSA is described further in arch/x86/pci/olpc.c.
+ */
+static inline int olpc_has_vsa(void)
+{
+ return (olpc_platform_info.flags & OLPC_F_VSA) ? 1 : 0;
+}
+
+/*
+ * The "Mass Production" version of OLPC's XO is identified as being model
+ * C2. During the prototype phase, the following models (in chronological
+ * order) were created: A1, B1, B2, B3, B4, C1. The A1 through B2 models
+ * were based on Geode GX CPUs, and models after that were based upon
+ * Geode LX CPUs. There were also some hand-assembled models floating
+ * around, referred to as PreB1, PreB2, etc.
+ */
+static inline int olpc_board_at_least(uint32_t rev)
+{
+ return olpc_platform_info.boardrev >= rev;
+}
+
+#else
+
+static inline int machine_is_olpc(void)
+{
+ return 0;
+}
+
+static inline int olpc_has_dcon(void)
+{
+ return 0;
+}
+
+static inline int olpc_has_vsa(void)
+{
+ return 0;
+}
+
+#endif
+
+/* EC related functions */
+
+extern int olpc_ec_cmd(unsigned char cmd, unsigned char *inbuf, size_t inlen,
+ unsigned char *outbuf, size_t outlen);
+
+extern int olpc_ec_mask_set(uint8_t bits);
+extern int olpc_ec_mask_unset(uint8_t bits);
+
+/* EC commands */
+
+#define EC_FIRMWARE_REV 0x08
+
+/* SCI source values */
+
+#define EC_SCI_SRC_EMPTY 0x00
+#define EC_SCI_SRC_GAME 0x01
+#define EC_SCI_SRC_BATTERY 0x02
+#define EC_SCI_SRC_BATSOC 0x04
+#define EC_SCI_SRC_BATERR 0x08
+#define EC_SCI_SRC_EBOOK 0x10
+#define EC_SCI_SRC_WLAN 0x20
+#define EC_SCI_SRC_ACPWR 0x40
+#define EC_SCI_SRC_ALL 0x7F
+
+/* GPIO assignments */
+
+#define OLPC_GPIO_MIC_AC geode_gpio(1)
+#define OLPC_GPIO_DCON_IRQ geode_gpio(7)
+#define OLPC_GPIO_THRM_ALRM geode_gpio(10)
+#define OLPC_GPIO_SMB_CLK geode_gpio(14)
+#define OLPC_GPIO_SMB_DATA geode_gpio(15)
+#define OLPC_GPIO_WORKAUX geode_gpio(24)
+#define OLPC_GPIO_LID geode_gpio(26)
+#define OLPC_GPIO_ECSCI geode_gpio(27)
+
+#endif
diff --git a/include/asm-x86/pci.h b/include/asm-x86/pci.h
index ddd8e24..30bbde0 100644
--- a/include/asm-x86/pci.h
+++ b/include/asm-x86/pci.h
@@ -19,6 +19,8 @@
};
/* scan a bus after allocating a pci_sysdata for it */
+extern struct pci_bus *pci_scan_bus_on_node(int busno, struct pci_ops *ops,
+ int node);
extern struct pci_bus *pci_scan_bus_with_sysdata(int busno);
static inline int pci_domain_nr(struct pci_bus *bus)
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
index 2e7974e..5591052 100644
--- a/include/asm-x86/processor.h
+++ b/include/asm-x86/processor.h
@@ -3,9 +3,6 @@
#include <asm/processor-flags.h>
-/* migration helper, for KVM - will be removed in 2.6.25: */
-#define Xgt_desc_struct desc_ptr
-
/* Forward declaration, a strange C thing */
struct task_struct;
struct mm_struct;
diff --git a/include/asm-x86/proto.h b/include/asm-x86/proto.h
index 1e17bcc..6c8b41b 100644
--- a/include/asm-x86/proto.h
+++ b/include/asm-x86/proto.h
@@ -20,7 +20,11 @@
extern void check_efer(void);
+#ifdef CONFIG_X86_BIOS_REBOOT
extern int reboot_force;
+#else
+static const int reboot_force = 0;
+#endif
long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
diff --git a/include/asm-x86/thread_info_32.h b/include/asm-x86/thread_info_32.h
index 5318599..b633882 100644
--- a/include/asm-x86/thread_info_32.h
+++ b/include/asm-x86/thread_info_32.h
@@ -131,7 +131,6 @@
#define TIF_SYSCALL_EMU 5 /* syscall emulation active */
#define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */
#define TIF_SECCOMP 7 /* secure computing */
-#define TIF_RESTORE_SIGMASK 8 /* restore signal mask in do_signal() */
#define TIF_HRTICK_RESCHED 9 /* reprogram hrtick timer */
#define TIF_MEMDIE 16
#define TIF_DEBUG 17 /* uses debug registers */
@@ -151,7 +150,6 @@
#define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_HRTICK_RESCHED (1 << TIF_HRTICK_RESCHED)
#define _TIF_DEBUG (1 << TIF_DEBUG)
#define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP)
@@ -188,9 +186,20 @@
this quantum (SMP) */
#define TS_POLLING 0x0002 /* True if in idle loop
and not sleeping */
+#define TS_RESTORE_SIGMASK 0x0004 /* restore signal mask in do_signal() */
#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+ struct thread_info *ti = current_thread_info();
+ ti->status |= TS_RESTORE_SIGMASK;
+ set_bit(TIF_SIGPENDING, &ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
+
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
diff --git a/include/asm-x86/thread_info_64.h b/include/asm-x86/thread_info_64.h
index ed664e8..cb69f70 100644
--- a/include/asm-x86/thread_info_64.h
+++ b/include/asm-x86/thread_info_64.h
@@ -109,7 +109,6 @@
#define TIF_IRET 5 /* force IRET */
#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
#define TIF_SECCOMP 8 /* secure computing */
-#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal */
#define TIF_MCE_NOTIFY 10 /* notify userspace of an MCE */
#define TIF_HRTICK_RESCHED 11 /* reprogram hrtick timer */
/* 16 free */
@@ -133,7 +132,6 @@
#define _TIF_IRET (1 << TIF_IRET)
#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
#define _TIF_SECCOMP (1 << TIF_SECCOMP)
-#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
#define _TIF_MCE_NOTIFY (1 << TIF_MCE_NOTIFY)
#define _TIF_HRTICK_RESCHED (1 << TIF_HRTICK_RESCHED)
#define _TIF_IA32 (1 << TIF_IA32)
@@ -178,9 +176,20 @@
#define TS_COMPAT 0x0002 /* 32bit syscall active */
#define TS_POLLING 0x0004 /* true if in idle loop
and not sleeping */
+#define TS_RESTORE_SIGMASK 0x0008 /* restore signal mask in do_signal() */
#define tsk_is_polling(t) (task_thread_info(t)->status & TS_POLLING)
+#ifndef __ASSEMBLY__
+#define HAVE_SET_RESTORE_SIGMASK 1
+static inline void set_restore_sigmask(void)
+{
+ struct thread_info *ti = current_thread_info();
+ ti->status |= TS_RESTORE_SIGMASK;
+ set_bit(TIF_SIGPENDING, &ti->flags);
+}
+#endif /* !__ASSEMBLY__ */
+
#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
diff --git a/include/asm-x86/time.h b/include/asm-x86/time.h
index 68779b0..bce72d7 100644
--- a/include/asm-x86/time.h
+++ b/include/asm-x86/time.h
@@ -1,7 +1,6 @@
#ifndef _ASMX86_TIME_H
#define _ASMX86_TIME_H
-extern void (*late_time_init)(void);
extern void hpet_time_init(void);
#include <asm/mc146818rtc.h>
diff --git a/include/asm-x86/topology.h b/include/asm-x86/topology.h
index 2207326..4f35a0f 100644
--- a/include/asm-x86/topology.h
+++ b/include/asm-x86/topology.h
@@ -193,9 +193,29 @@
#define topology_thread_siblings(cpu) (per_cpu(cpu_sibling_map, cpu))
#endif
+static inline void arch_fix_phys_package_id(int num, u32 slot)
+{
+}
+
+struct pci_bus;
+void set_pci_bus_resources_arch_default(struct pci_bus *b);
+
#ifdef CONFIG_SMP
#define mc_capable() (boot_cpu_data.x86_max_cores > 1)
#define smt_capable() (smp_num_siblings > 1)
#endif
+#ifdef CONFIG_NUMA
+extern int get_mp_bus_to_node(int busnum);
+extern void set_mp_bus_to_node(int busnum, int node);
+#else
+static inline int get_mp_bus_to_node(int busnum)
+{
+ return 0;
+}
+static inline void set_mp_bus_to_node(int busnum, int node)
+{
+}
+#endif
+
#endif
diff --git a/include/asm-x86/tsc.h b/include/asm-x86/tsc.h
index d2d8eb5..548873a 100644
--- a/include/asm-x86/tsc.h
+++ b/include/asm-x86/tsc.h
@@ -32,7 +32,7 @@
return ret;
}
-static inline cycles_t vget_cycles(void)
+static __always_inline cycles_t vget_cycles(void)
{
/*
* We only do VDSOs on TSC capable CPUs, so this shouldnt
diff --git a/include/asm-x86/unaligned.h b/include/asm-x86/unaligned.h
index d270ffe..a7bd416 100644
--- a/include/asm-x86/unaligned.h
+++ b/include/asm-x86/unaligned.h
@@ -3,35 +3,12 @@
/*
* The x86 can do unaligned accesses itself.
- *
- * The strange macros are there to make sure these can't
- * be misused in a way that makes them not work on other
- * architectures where unaligned accesses aren't as simple.
*/
-/**
- * get_unaligned - get value from possibly mis-aligned location
- * @ptr: pointer to value
- *
- * This macro should be used for accessing values larger in size than
- * single bytes at locations that are expected to be improperly aligned,
- * e.g. retrieving a u16 value from a location not u16-aligned.
- *
- * Note that unaligned accesses can be very expensive on some architectures.
- */
-#define get_unaligned(ptr) (*(ptr))
+#include <linux/unaligned/access_ok.h>
+#include <linux/unaligned/generic.h>
-/**
- * put_unaligned - put value to a possibly mis-aligned location
- * @val: value to place
- * @ptr: pointer to location
- *
- * This macro should be used for placing values larger in size than
- * single bytes at locations that are expected to be improperly aligned,
- * e.g. writing a u16 value to a location not u16-aligned.
- *
- * Note that unaligned accesses can be very expensive on some architectures.
- */
-#define put_unaligned(val, ptr) ((void)(*(ptr) = (val)))
+#define get_unaligned __get_unaligned_le
+#define put_unaligned __put_unaligned_le
#endif /* _ASM_X86_UNALIGNED_H */
diff --git a/include/asm-xtensa/unaligned.h b/include/asm-xtensa/unaligned.h
index 2822089..8f3424f 100644
--- a/include/asm-xtensa/unaligned.h
+++ b/include/asm-xtensa/unaligned.h
@@ -1,6 +1,4 @@
/*
- * include/asm-xtensa/unaligned.h
- *
* Xtensa doesn't handle unaligned accesses efficiently.
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -9,20 +7,23 @@
*
* Copyright (C) 2001 - 2005 Tensilica Inc.
*/
+#ifndef _ASM_XTENSA_UNALIGNED_H
+#define _ASM_XTENSA_UNALIGNED_H
-#ifndef _XTENSA_UNALIGNED_H
-#define _XTENSA_UNALIGNED_H
+#ifdef __XTENSA_EL__
+# include <linux/unaligned/le_memmove.h>
+# include <linux/unaligned/be_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_le
+# define put_unaligned __put_unaligned_le
+#elif defined(__XTENSA_EB__)
+# include <linux/unaligned/be_memmove.h>
+# include <linux/unaligned/le_byteshift.h>
+# include <linux/unaligned/generic.h>
+# define get_unaligned __get_unaligned_be
+# define put_unaligned __put_unaligned_be
+#else
+# error processor byte order undefined!
+#endif
-#include <linux/string.h>
-
-/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
-
-#define get_unaligned(ptr) \
- ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
-
-#define put_unaligned(val, ptr) \
- ({ __typeof__(*(ptr)) __tmp = (val); \
- memmove((ptr), &__tmp, sizeof(*(ptr))); \
- (void)0; })
-
-#endif /* _XTENSA_UNALIGNED_H */
+#endif /* _ASM_XTENSA_UNALIGNED_H */
diff --git a/include/crypto/scatterwalk.h b/include/crypto/scatterwalk.h
index 224658b..833d208 100644
--- a/include/crypto/scatterwalk.h
+++ b/include/crypto/scatterwalk.h
@@ -57,10 +57,14 @@
struct scatterlist *sg2)
{
sg_set_page(&sg1[num - 1], (void *)sg2, 0, 0);
+ sg1[num - 1].page_link &= ~0x02;
}
static inline struct scatterlist *scatterwalk_sg_next(struct scatterlist *sg)
{
+ if (sg_is_last(sg))
+ return NULL;
+
return (++sg)->length ? sg : (void *)sg_page(sg);
}
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index bda6f04..b7d81b2 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -20,6 +20,7 @@
header-y += aio_abi.h
header-y += arcfb.h
header-y += atmapi.h
+header-y += atmarp.h
header-y += atmbr2684.h
header-y += atmclip.h
header-y += atm_eni.h
@@ -48,6 +49,7 @@
header-y += comstats.h
header-y += const.h
header-y += cgroupstats.h
+header-y += cramfs_fs.h
header-y += cycx_cfm.h
header-y += dlmconstants.h
header-y += dlm_device.h
@@ -70,10 +72,12 @@
header-y += fuse.h
header-y += genetlink.h
header-y += gen_stats.h
+header-y += gfs2_ondisk.h
header-y += gigaset_dev.h
header-y += hysdn_if.h
header-y += i2o-dev.h
header-y += i8k.h
+header-y += if_addrlabel.h
header-y += if_arcnet.h
header-y += if_bonding.h
header-y += if_cablemodem.h
@@ -91,6 +95,7 @@
header-y += in6.h
header-y += in_route.h
header-y += ioctl.h
+header-y += ip6_tunnel.h
header-y += ipmi_msgdefs.h
header-y += ipsec.h
header-y += ipx.h
@@ -117,7 +122,6 @@
header-y += nfs4_mount.h
header-y += nfs_mount.h
header-y += nl80211.h
-header-y += oom.h
header-y += param.h
header-y += pci_regs.h
header-y += pfkeyv2.h
@@ -166,7 +170,6 @@
unifdef-y += agpgart.h
unifdef-y += apm_bios.h
unifdef-y += atalk.h
-unifdef-y += atmarp.h
unifdef-y += atmdev.h
unifdef-y += atm.h
unifdef-y += atm_tcp.h
@@ -182,7 +185,6 @@
unifdef-y += cn_proc.h
unifdef-y += coda.h
unifdef-y += connector.h
-unifdef-y += cramfs_fs.h
unifdef-y += cuda.h
unifdef-y += cyclades.h
unifdef-y += dccp.h
@@ -205,7 +207,6 @@
unifdef-y += fs.h
unifdef-y += gameport.h
unifdef-y += generic_serial.h
-unifdef-y += gfs2_ondisk.h
unifdef-y += hayesesp.h
unifdef-y += hdlcdrv.h
unifdef-y += hdlc.h
@@ -219,7 +220,6 @@
unifdef-y += icmp.h
unifdef-y += icmpv6.h
unifdef-y += if_addr.h
-unifdef-y += if_addrlabel.h
unifdef-y += if_arp.h
unifdef-y += if_bridge.h
unifdef-y += if_ec.h
@@ -243,7 +243,6 @@
unifdef-y += ipmi.h
unifdef-y += ipv6.h
unifdef-y += ipv6_route.h
-unifdef-y += ip6_tunnel.h
unifdef-y += isdn.h
unifdef-y += isdnif.h
unifdef-y += isdn_divertif.h
@@ -347,6 +346,11 @@
unifdef-y += virtio_config.h
unifdef-y += virtio_blk.h
unifdef-y += virtio_net.h
+unifdef-y += virtio_9p.h
+unifdef-y += virtio_balloon.h
+unifdef-y += virtio_console.h
+unifdef-y += virtio_pci.h
+unifdef-y += virtio_ring.h
unifdef-y += vt.h
unifdef-y += wait.h
unifdef-y += wanrouter.h
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 2c7e003..41f7ce7 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -79,6 +79,7 @@
typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
+int early_acpi_boot_init(void);
int acpi_boot_init (void);
int acpi_boot_table_init (void);
int acpi_numa_init (void);
@@ -235,6 +236,10 @@
#else /* CONFIG_ACPI */
+static inline int early_acpi_boot_init(void)
+{
+ return 0;
+}
static inline int acpi_boot_init(void)
{
return 0;
diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h
index 03e3454..661d90d 100644
--- a/include/linux/agp_backend.h
+++ b/include/linux/agp_backend.h
@@ -30,8 +30,6 @@
#ifndef _AGP_BACKEND_H
#define _AGP_BACKEND_H 1
-#ifdef __KERNEL__
-
#ifndef TRUE
#define TRUE 1
#endif
@@ -111,5 +109,4 @@
extern void agp_backend_release(struct agp_bridge_data *);
extern void agp_flush_chipset(struct agp_bridge_data *);
-#endif /* __KERNEL__ */
#endif /* _AGP_BACKEND_H */
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 0d0b7f6..b51ddd2 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -209,27 +209,8 @@
extern int aio_put_req(struct kiocb *iocb);
extern void kick_iocb(struct kiocb *iocb);
extern int aio_complete(struct kiocb *iocb, long res, long res2);
-extern void __put_ioctx(struct kioctx *ctx);
struct mm_struct;
extern void exit_aio(struct mm_struct *mm);
-extern struct kioctx *lookup_ioctx(unsigned long ctx_id);
-extern int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
- struct iocb *iocb);
-
-/* semi private, but used by the 32bit emulations: */
-struct kioctx *lookup_ioctx(unsigned long ctx_id);
-int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
- struct iocb *iocb);
-
-#define get_ioctx(kioctx) do { \
- BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
- atomic_inc(&(kioctx)->users); \
-} while (0)
-#define put_ioctx(kioctx) do { \
- BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
- if (unlikely(atomic_dec_and_test(&(kioctx)->users))) \
- __put_ioctx(kioctx); \
-} while (0)
#define io_wait_to_kiocb(wait) container_of(wait, struct kiocb, ki_wait)
diff --git a/include/linux/anon_inodes.h b/include/linux/anon_inodes.h
index b2e1ba3..6129e58 100644
--- a/include/linux/anon_inodes.h
+++ b/include/linux/anon_inodes.h
@@ -8,8 +8,7 @@
#ifndef _LINUX_ANON_INODES_H
#define _LINUX_ANON_INODES_H
-int anon_inode_getfd(int *pfd, struct inode **pinode, struct file **pfile,
- const char *name, const struct file_operations *fops,
+int anon_inode_getfd(const char *name, const struct file_operations *fops,
void *priv);
#endif /* _LINUX_ANON_INODES_H */
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 4ccb048..63c3bb9 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -146,7 +146,7 @@
/* Rule structure sizes -- if these change, different AUDIT_ADD and
* AUDIT_LIST commands must be implemented. */
#define AUDIT_MAX_FIELDS 64
-#define AUDIT_MAX_KEY_LEN 32
+#define AUDIT_MAX_KEY_LEN 256
#define AUDIT_BITMASK_SIZE 64
#define AUDIT_WORD(nr) ((__u32)((nr)/32))
#define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32))
@@ -209,6 +209,7 @@
#define AUDIT_WATCH 105
#define AUDIT_PERM 106
#define AUDIT_DIR 107
+#define AUDIT_FILETYPE 108
#define AUDIT_ARG0 200
#define AUDIT_ARG1 (AUDIT_ARG0+1)
@@ -549,16 +550,20 @@
const char *fmt, ...)
__attribute__((format(printf,2,3)));
extern void audit_log_end(struct audit_buffer *ab);
-extern void audit_log_hex(struct audit_buffer *ab,
- const unsigned char *buf,
- size_t len);
extern int audit_string_contains_control(const char *string,
size_t len);
+extern void audit_log_n_hex(struct audit_buffer *ab,
+ const unsigned char *buf,
+ size_t len);
+extern void audit_log_n_string(struct audit_buffer *ab,
+ const char *buf,
+ size_t n);
+#define audit_log_string(a,b) audit_log_n_string(a, b, strlen(b));
+extern void audit_log_n_untrustedstring(struct audit_buffer *ab,
+ const char *string,
+ size_t n);
extern void audit_log_untrustedstring(struct audit_buffer *ab,
const char *string);
-extern void audit_log_n_untrustedstring(struct audit_buffer *ab,
- size_t n,
- const char *string);
extern void audit_log_d_path(struct audit_buffer *ab,
const char *prefix,
struct path *path);
@@ -569,7 +574,8 @@
extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
extern int audit_filter_type(int type);
extern int audit_receive_filter(int type, int pid, int uid, int seq,
- void *data, size_t datasz, uid_t loginuid, u32 sid);
+ void *data, size_t datasz, uid_t loginuid,
+ u32 sessionid, u32 sid);
extern int audit_enabled;
#else
#define audit_log(c,g,t,f,...) do { ; } while (0)
@@ -577,9 +583,11 @@
#define audit_log_vformat(b,f,a) do { ; } while (0)
#define audit_log_format(b,f,...) do { ; } while (0)
#define audit_log_end(b) do { ; } while (0)
-#define audit_log_hex(a,b,l) do { ; } while (0)
-#define audit_log_untrustedstring(a,s) do { ; } while (0)
+#define audit_log_n_hex(a,b,l) do { ; } while (0)
+#define audit_log_n_string(a,c,l) do { ; } while (0)
+#define audit_log_string(a,c) do { ; } while (0)
#define audit_log_n_untrustedstring(a,n,s) do { ; } while (0)
+#define audit_log_untrustedstring(a,s) do { ; } while (0)
#define audit_log_d_path(b, p, d) do { ; } while (0)
#define audit_enabled 0
#endif
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 48a62ba..0a24d55 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -11,9 +11,13 @@
#include <linux/percpu_counter.h>
#include <linux/log2.h>
#include <linux/proportions.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
#include <asm/atomic.h>
struct page;
+struct device;
+struct dentry;
/*
* Bits in backing_dev_info.state
@@ -48,11 +52,26 @@
struct prop_local_percpu completions;
int dirty_exceeded;
+
+ unsigned int min_ratio;
+ unsigned int max_ratio, max_prop_frac;
+
+ struct device *dev;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debug_dir;
+ struct dentry *debug_stats;
+#endif
};
int bdi_init(struct backing_dev_info *bdi);
void bdi_destroy(struct backing_dev_info *bdi);
+int bdi_register(struct backing_dev_info *bdi, struct device *parent,
+ const char *fmt, ...);
+int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev);
+void bdi_unregister(struct backing_dev_info *bdi);
+
static inline void __add_bdi_stat(struct backing_dev_info *bdi,
enum bdi_stat_item item, s64 amount)
{
@@ -116,6 +135,8 @@
return sum;
}
+extern void bdi_writeout_inc(struct backing_dev_info *bdi);
+
/*
* maximal error of a stat counter.
*/
@@ -128,24 +149,48 @@
#endif
}
+int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio);
+int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned int max_ratio);
+
/*
* Flags in backing_dev_info::capability
- * - The first two flags control whether dirty pages will contribute to the
- * VM's accounting and whether writepages() should be called for dirty pages
- * (something that would not, for example, be appropriate for ramfs)
- * - These flags let !MMU mmap() govern direct device mapping vs immediate
- * copying more easily for MAP_PRIVATE, especially for ROM filesystems
+ *
+ * The first three flags control whether dirty pages will contribute to the
+ * VM's accounting and whether writepages() should be called for dirty pages
+ * (something that would not, for example, be appropriate for ramfs)
+ *
+ * WARNING: these flags are closely related and should not normally be
+ * used separately. The BDI_CAP_NO_ACCT_AND_WRITEBACK combines these
+ * three flags into a single convenience macro.
+ *
+ * BDI_CAP_NO_ACCT_DIRTY: Dirty pages shouldn't contribute to accounting
+ * BDI_CAP_NO_WRITEBACK: Don't write pages back
+ * BDI_CAP_NO_ACCT_WB: Don't automatically account writeback pages
+ *
+ * These flags let !MMU mmap() govern direct device mapping vs immediate
+ * copying more easily for MAP_PRIVATE, especially for ROM filesystems.
+ *
+ * BDI_CAP_MAP_COPY: Copy can be mapped (MAP_PRIVATE)
+ * BDI_CAP_MAP_DIRECT: Can be mapped directly (MAP_SHARED)
+ * BDI_CAP_READ_MAP: Can be mapped for reading
+ * BDI_CAP_WRITE_MAP: Can be mapped for writing
+ * BDI_CAP_EXEC_MAP: Can be mapped for execution
*/
-#define BDI_CAP_NO_ACCT_DIRTY 0x00000001 /* Dirty pages shouldn't contribute to accounting */
-#define BDI_CAP_NO_WRITEBACK 0x00000002 /* Don't write pages back */
-#define BDI_CAP_MAP_COPY 0x00000004 /* Copy can be mapped (MAP_PRIVATE) */
-#define BDI_CAP_MAP_DIRECT 0x00000008 /* Can be mapped directly (MAP_SHARED) */
-#define BDI_CAP_READ_MAP 0x00000010 /* Can be mapped for reading */
-#define BDI_CAP_WRITE_MAP 0x00000020 /* Can be mapped for writing */
-#define BDI_CAP_EXEC_MAP 0x00000040 /* Can be mapped for execution */
+#define BDI_CAP_NO_ACCT_DIRTY 0x00000001
+#define BDI_CAP_NO_WRITEBACK 0x00000002
+#define BDI_CAP_MAP_COPY 0x00000004
+#define BDI_CAP_MAP_DIRECT 0x00000008
+#define BDI_CAP_READ_MAP 0x00000010
+#define BDI_CAP_WRITE_MAP 0x00000020
+#define BDI_CAP_EXEC_MAP 0x00000040
+#define BDI_CAP_NO_ACCT_WB 0x00000080
+
#define BDI_CAP_VMFLAGS \
(BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP)
+#define BDI_CAP_NO_ACCT_AND_WRITEBACK \
+ (BDI_CAP_NO_WRITEBACK | BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_ACCT_WB)
+
#if defined(VM_MAYREAD) && \
(BDI_CAP_READ_MAP != VM_MAYREAD || \
BDI_CAP_WRITE_MAP != VM_MAYWRITE || \
@@ -156,9 +201,7 @@
extern struct backing_dev_info default_backing_dev_info;
void default_unplug_io_fn(struct backing_dev_info *bdi, struct page *page);
-int writeback_acquire(struct backing_dev_info *bdi);
int writeback_in_progress(struct backing_dev_info *bdi);
-void writeback_release(struct backing_dev_info *bdi);
static inline int bdi_congested(struct backing_dev_info *bdi, int bdi_bits)
{
@@ -187,17 +230,32 @@
void set_bdi_congested(struct backing_dev_info *bdi, int rw);
long congestion_wait(int rw, long timeout);
-#define bdi_cap_writeback_dirty(bdi) \
- (!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK))
-#define bdi_cap_account_dirty(bdi) \
- (!((bdi)->capabilities & BDI_CAP_NO_ACCT_DIRTY))
+static inline bool bdi_cap_writeback_dirty(struct backing_dev_info *bdi)
+{
+ return !(bdi->capabilities & BDI_CAP_NO_WRITEBACK);
+}
-#define mapping_cap_writeback_dirty(mapping) \
- bdi_cap_writeback_dirty((mapping)->backing_dev_info)
+static inline bool bdi_cap_account_dirty(struct backing_dev_info *bdi)
+{
+ return !(bdi->capabilities & BDI_CAP_NO_ACCT_DIRTY);
+}
-#define mapping_cap_account_dirty(mapping) \
- bdi_cap_account_dirty((mapping)->backing_dev_info)
+static inline bool bdi_cap_account_writeback(struct backing_dev_info *bdi)
+{
+ /* Paranoia: BDI_CAP_NO_WRITEBACK implies BDI_CAP_NO_ACCT_WB */
+ return !(bdi->capabilities & (BDI_CAP_NO_ACCT_WB |
+ BDI_CAP_NO_WRITEBACK));
+}
+static inline bool mapping_cap_writeback_dirty(struct address_space *mapping)
+{
+ return bdi_cap_writeback_dirty(mapping->backing_dev_info);
+}
+
+static inline bool mapping_cap_account_dirty(struct address_space *mapping)
+{
+ return bdi_cap_account_dirty(mapping->backing_dev_info);
+}
#endif /* _LINUX_BACKING_DEV_H */
diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h
index b7fc55e..b512e48 100644
--- a/include/linux/binfmts.h
+++ b/include/linux/binfmts.h
@@ -34,7 +34,8 @@
#endif
struct mm_struct *mm;
unsigned long p; /* current top of mem */
- int sh_bang;
+ unsigned int sh_bang:1,
+ misc_bang:1;
struct file * file;
int e_uid, e_gid;
kernel_cap_t cap_inheritable, cap_permitted;
@@ -48,7 +49,6 @@
unsigned interp_flags;
unsigned interp_data;
unsigned long loader, exec;
- unsigned long argv_len;
};
#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
diff --git a/include/linux/bio.h b/include/linux/bio.h
index d259690..61c15ea 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -324,6 +324,8 @@
extern void bio_unmap_user(struct bio *);
extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int,
gfp_t);
+extern struct bio *bio_copy_kern(struct request_queue *, void *, unsigned int,
+ gfp_t, 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/bitops.h b/include/linux/bitops.h
index 48bde60..024f2b0 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -6,8 +6,8 @@
#define BIT(nr) (1UL << (nr))
#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
-#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG)
#define BITS_PER_BYTE 8
+#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
#endif
/*
@@ -114,8 +114,6 @@
#ifdef __KERNEL__
#ifdef CONFIG_GENERIC_FIND_FIRST_BIT
-extern unsigned long __find_first_bit(const unsigned long *addr,
- unsigned long size);
/**
* find_first_bit - find the first set bit in a memory region
@@ -124,28 +122,8 @@
*
* Returns the bit number of the first set bit.
*/
-static __always_inline unsigned long
-find_first_bit(const unsigned long *addr, unsigned long size)
-{
- /* Avoid a function call if the bitmap size is a constant */
- /* and not bigger than BITS_PER_LONG. */
-
- /* insert a sentinel so that __ffs returns size if there */
- /* are no set bits in the bitmap */
- if (__builtin_constant_p(size) && (size < BITS_PER_LONG))
- return __ffs((*addr) | (1ul << size));
-
- /* the result of __ffs(0) is undefined, so it needs to be */
- /* handled separately */
- if (__builtin_constant_p(size) && (size == BITS_PER_LONG))
- return ((*addr) == 0) ? BITS_PER_LONG : __ffs(*addr);
-
- /* size is not constant or too big */
- return __find_first_bit(addr, size);
-}
-
-extern unsigned long __find_first_zero_bit(const unsigned long *addr,
- unsigned long size);
+extern unsigned long find_first_bit(const unsigned long *addr,
+ unsigned long size);
/**
* find_first_zero_bit - find the first cleared bit in a memory region
@@ -154,31 +132,12 @@
*
* Returns the bit number of the first cleared bit.
*/
-static __always_inline unsigned long
-find_first_zero_bit(const unsigned long *addr, unsigned long size)
-{
- /* Avoid a function call if the bitmap size is a constant */
- /* and not bigger than BITS_PER_LONG. */
+extern unsigned long find_first_zero_bit(const unsigned long *addr,
+ unsigned long size);
- /* insert a sentinel so that __ffs returns size if there */
- /* are no set bits in the bitmap */
- if (__builtin_constant_p(size) && (size < BITS_PER_LONG)) {
- return __ffs(~(*addr) | (1ul << size));
- }
-
- /* the result of __ffs(0) is undefined, so it needs to be */
- /* handled separately */
- if (__builtin_constant_p(size) && (size == BITS_PER_LONG))
- return (~(*addr) == 0) ? BITS_PER_LONG : __ffs(~(*addr));
-
- /* size is not constant or too big */
- return __find_first_zero_bit(addr, size);
-}
#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
#ifdef CONFIG_GENERIC_FIND_NEXT_BIT
-extern unsigned long __find_next_bit(const unsigned long *addr,
- unsigned long size, unsigned long offset);
/**
* find_next_bit - find the next set bit in a memory region
@@ -186,36 +145,8 @@
* @offset: The bitnumber to start searching at
* @size: The bitmap size in bits
*/
-static __always_inline unsigned long
-find_next_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
-{
- unsigned long value;
-
- /* Avoid a function call if the bitmap size is a constant */
- /* and not bigger than BITS_PER_LONG. */
-
- /* insert a sentinel so that __ffs returns size if there */
- /* are no set bits in the bitmap */
- if (__builtin_constant_p(size) && (size < BITS_PER_LONG)) {
- value = (*addr) & ((~0ul) << offset);
- value |= (1ul << size);
- return __ffs(value);
- }
-
- /* the result of __ffs(0) is undefined, so it needs to be */
- /* handled separately */
- if (__builtin_constant_p(size) && (size == BITS_PER_LONG)) {
- value = (*addr) & ((~0ul) << offset);
- return (value == 0) ? BITS_PER_LONG : __ffs(value);
- }
-
- /* size is not constant or too big */
- return __find_next_bit(addr, size, offset);
-}
-
-extern unsigned long __find_next_zero_bit(const unsigned long *addr,
- unsigned long size, unsigned long offset);
+extern unsigned long find_next_bit(const unsigned long *addr,
+ unsigned long size, unsigned long offset);
/**
* find_next_zero_bit - find the next cleared bit in a memory region
@@ -223,33 +154,11 @@
* @offset: The bitnumber to start searching at
* @size: The bitmap size in bits
*/
-static __always_inline unsigned long
-find_next_zero_bit(const unsigned long *addr, unsigned long size,
- unsigned long offset)
-{
- unsigned long value;
- /* Avoid a function call if the bitmap size is a constant */
- /* and not bigger than BITS_PER_LONG. */
+extern unsigned long find_next_zero_bit(const unsigned long *addr,
+ unsigned long size,
+ unsigned long offset);
- /* insert a sentinel so that __ffs returns size if there */
- /* are no set bits in the bitmap */
- if (__builtin_constant_p(size) && (size < BITS_PER_LONG)) {
- value = (~(*addr)) & ((~0ul) << offset);
- value |= (1ul << size);
- return __ffs(value);
- }
-
- /* the result of __ffs(0) is undefined, so it needs to be */
- /* handled separately */
- if (__builtin_constant_p(size) && (size == BITS_PER_LONG)) {
- value = (~(*addr)) & ((~0ul) << offset);
- return (value == 0) ? BITS_PER_LONG : __ffs(value);
- }
-
- /* size is not constant or too big */
- return __find_next_zero_bit(addr, size, offset);
-}
#endif /* CONFIG_GENERIC_FIND_NEXT_BIT */
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index c5065e3..d2a1b71 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -215,8 +215,9 @@
/*
* when request is used as a packet command carrier
*/
- unsigned int cmd_len;
- unsigned char cmd[BLK_MAX_CDB];
+ unsigned short cmd_len;
+ unsigned char __cmd[BLK_MAX_CDB];
+ unsigned char *cmd;
unsigned int data_len;
unsigned int extra_len; /* length of alignment and padding */
@@ -407,6 +408,41 @@
#define QUEUE_FLAG_PLUGGED 7 /* queue is plugged */
#define QUEUE_FLAG_ELVSWITCH 8 /* don't use elevator, just do FIFO */
#define QUEUE_FLAG_BIDI 9 /* queue supports bidi requests */
+#define QUEUE_FLAG_NOMERGES 10 /* disable merge attempts */
+
+static inline int queue_is_locked(struct request_queue *q)
+{
+#ifdef CONFIG_SMP
+ spinlock_t *lock = q->queue_lock;
+ return lock && spin_is_locked(lock);
+#else
+ return 1;
+#endif
+}
+
+static inline void queue_flag_set_unlocked(unsigned int flag,
+ struct request_queue *q)
+{
+ __set_bit(flag, &q->queue_flags);
+}
+
+static inline void queue_flag_set(unsigned int flag, struct request_queue *q)
+{
+ WARN_ON_ONCE(!queue_is_locked(q));
+ __set_bit(flag, &q->queue_flags);
+}
+
+static inline void queue_flag_clear_unlocked(unsigned int flag,
+ struct request_queue *q)
+{
+ __clear_bit(flag, &q->queue_flags);
+}
+
+static inline void queue_flag_clear(unsigned int flag, struct request_queue *q)
+{
+ WARN_ON_ONCE(!queue_is_locked(q));
+ __clear_bit(flag, &q->queue_flags);
+}
enum {
/*
@@ -451,6 +487,7 @@
#define blk_queue_plugged(q) test_bit(QUEUE_FLAG_PLUGGED, &(q)->queue_flags)
#define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags)
#define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
+#define blk_queue_nomerges(q) test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags)
#define blk_queue_flushing(q) ((q)->ordseq)
#define blk_fs_request(rq) ((rq)->cmd_type == REQ_TYPE_FS)
@@ -496,17 +533,17 @@
static inline void blk_set_queue_full(struct request_queue *q, int rw)
{
if (rw == READ)
- set_bit(QUEUE_FLAG_READFULL, &q->queue_flags);
+ queue_flag_set(QUEUE_FLAG_READFULL, q);
else
- set_bit(QUEUE_FLAG_WRITEFULL, &q->queue_flags);
+ queue_flag_set(QUEUE_FLAG_WRITEFULL, q);
}
static inline void blk_clear_queue_full(struct request_queue *q, int rw)
{
if (rw == READ)
- clear_bit(QUEUE_FLAG_READFULL, &q->queue_flags);
+ queue_flag_clear(QUEUE_FLAG_READFULL, q);
else
- clear_bit(QUEUE_FLAG_WRITEFULL, &q->queue_flags);
+ queue_flag_clear(QUEUE_FLAG_WRITEFULL, q);
}
@@ -583,6 +620,7 @@
extern void blk_unregister_queue(struct gendisk *disk);
extern void register_disk(struct gendisk *dev);
extern void generic_make_request(struct bio *bio);
+extern void blk_rq_init(struct request_queue *q, struct request *rq);
extern void blk_put_request(struct request *);
extern void __blk_put_request(struct request_queue *, struct request *);
extern void blk_end_sync_rq(struct request *rq, int error);
@@ -626,6 +664,7 @@
extern void blk_stop_queue(struct request_queue *q);
extern void blk_sync_queue(struct request_queue *q);
extern void __blk_stop_queue(struct request_queue *q);
+extern void __blk_run_queue(struct request_queue *);
extern void blk_run_queue(struct request_queue *);
extern void blk_start_queueing(struct request_queue *);
extern int blk_rq_map_user(struct request_queue *, struct request *, void __user *, unsigned long);
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 932eb02..82aa36c 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -225,7 +225,6 @@
get_block_t get_block);
void block_sync_page(struct page *);
sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *);
-int generic_commit_write(struct file *, struct page *, unsigned, unsigned);
int block_truncate_page(struct address_space *, loff_t, get_block_t *);
int file_fsync(struct file *, struct dentry *, int);
int nobh_write_begin(struct file *, struct address_space *,
diff --git a/include/linux/byteorder/Kbuild b/include/linux/byteorder/Kbuild
index 79beddd..1133d5f 100644
--- a/include/linux/byteorder/Kbuild
+++ b/include/linux/byteorder/Kbuild
@@ -1,5 +1,3 @@
-header-y += big_endian.h
-header-y += little_endian.h
-
-unifdef-y += generic.h
+unifdef-y += big_endian.h
+unifdef-y += little_endian.h
unifdef-y += swab.h
diff --git a/include/linux/byteorder/big_endian.h b/include/linux/byteorder/big_endian.h
index bef8789..961ed4b 100644
--- a/include/linux/byteorder/big_endian.h
+++ b/include/linux/byteorder/big_endian.h
@@ -101,6 +101,8 @@
#define __cpu_to_be16s(x) do {} while (0)
#define __be16_to_cpus(x) do {} while (0)
+#ifdef __KERNEL__
#include <linux/byteorder/generic.h>
+#endif
#endif /* _LINUX_BYTEORDER_BIG_ENDIAN_H */
diff --git a/include/linux/byteorder/generic.h b/include/linux/byteorder/generic.h
index d377155..0846e6b 100644
--- a/include/linux/byteorder/generic.h
+++ b/include/linux/byteorder/generic.h
@@ -82,12 +82,6 @@
*
*/
-
-#if defined(__KERNEL__)
-/*
- * inside the kernel, we can use nicknames;
- * outside of it, we must avoid POSIX namespace pollution...
- */
#define cpu_to_le64 __cpu_to_le64
#define le64_to_cpu __le64_to_cpu
#define cpu_to_le32 __cpu_to_le32
@@ -176,6 +170,4 @@
*var = cpu_to_be64(be64_to_cpu(*var) + val);
}
-#endif /* KERNEL */
-
#endif /* _LINUX_BYTEORDER_GENERIC_H */
diff --git a/include/linux/byteorder/little_endian.h b/include/linux/byteorder/little_endian.h
index 86e62b7..05dc7c3 100644
--- a/include/linux/byteorder/little_endian.h
+++ b/include/linux/byteorder/little_endian.h
@@ -101,6 +101,8 @@
#define __cpu_to_be16s(x) __swab16s((x))
#define __be16_to_cpus(x) __swab16s((x))
+#ifdef __KERNEL__
#include <linux/byteorder/generic.h>
+#endif
#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */
diff --git a/include/linux/calc64.h b/include/linux/calc64.h
deleted file mode 100644
index ebf4b8f..0000000
--- a/include/linux/calc64.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef _LINUX_CALC64_H
-#define _LINUX_CALC64_H
-
-#include <linux/types.h>
-#include <asm/div64.h>
-
-/*
- * This is a generic macro which is used when the architecture
- * specific div64.h does not provide a optimized one.
- *
- * The 64bit dividend is divided by the divisor (data type long), the
- * result is returned and the remainder stored in the variable
- * referenced by remainder (data type long *). In contrast to the
- * do_div macro the dividend is kept intact.
- */
-#ifndef div_long_long_rem
-#define div_long_long_rem(dividend, divisor, remainder) \
- do_div_llr((dividend), divisor, remainder)
-
-static inline unsigned long do_div_llr(const long long dividend,
- const long divisor, long *remainder)
-{
- u64 result = dividend;
-
- *(remainder) = do_div(result, divisor);
- return (unsigned long) result;
-}
-#endif
-
-/*
- * Sign aware variation of the above. On some architectures a
- * negative dividend leads to an divide overflow exception, which
- * is avoided by the sign check.
- */
-static inline long div_long_long_rem_signed(const long long dividend,
- const long divisor, long *remainder)
-{
- long res;
-
- if (unlikely(dividend < 0)) {
- res = -div_long_long_rem(-dividend, divisor, remainder);
- *remainder = -(*remainder);
- } else
- res = div_long_long_rem(dividend, divisor, remainder);
-
- return res;
-}
-
-#endif
diff --git a/include/linux/capability.h b/include/linux/capability.h
index eaab759..f4ea0dd9a 100644
--- a/include/linux/capability.h
+++ b/include/linux/capability.h
@@ -365,12 +365,12 @@
# error Fix up hand-coded capability macro initializers
#else /* HAND-CODED capability initializers */
-# define CAP_EMPTY_SET {{ 0, 0 }}
-# define CAP_FULL_SET {{ ~0, ~0 }}
-# define CAP_INIT_EFF_SET {{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }}
-# define CAP_FS_SET {{ CAP_FS_MASK_B0, CAP_FS_MASK_B1 } }
-# define CAP_NFSD_SET {{ CAP_FS_MASK_B0|CAP_TO_MASK(CAP_SYS_RESOURCE), \
- CAP_FS_MASK_B1 } }
+# define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }})
+# define CAP_FULL_SET ((kernel_cap_t){{ ~0, ~0 }})
+# define CAP_INIT_EFF_SET ((kernel_cap_t){{ ~CAP_TO_MASK(CAP_SETPCAP), ~0 }})
+# define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0, CAP_FS_MASK_B1 } })
+# define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0|CAP_TO_MASK(CAP_SYS_RESOURCE), \
+ CAP_FS_MASK_B1 } })
#endif /* _LINUX_CAPABILITY_U32S != 2 */
diff --git a/include/linux/cdev.h b/include/linux/cdev.h
index 1e29b13..fb45919 100644
--- a/include/linux/cdev.h
+++ b/include/linux/cdev.h
@@ -1,6 +1,5 @@
#ifndef _LINUX_CDEV_H
#define _LINUX_CDEV_H
-#ifdef __KERNEL__
#include <linux/kobject.h>
#include <linux/kdev_t.h>
@@ -34,4 +33,3 @@
extern struct backing_dev_info directly_mappable_cdev_bdi;
#endif
-#endif
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index a6a6035..e155aa7 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -88,6 +88,17 @@
__css_put(css);
}
+/* bits in struct cgroup flags field */
+enum {
+ /* Control Group is dead */
+ CGRP_REMOVED,
+ /* Control Group has previously had a child cgroup or a task,
+ * but no longer (only if CGRP_NOTIFY_ON_RELEASE is set) */
+ CGRP_RELEASABLE,
+ /* Control Group requires release notifications to userspace */
+ CGRP_NOTIFY_ON_RELEASE,
+};
+
struct cgroup {
unsigned long flags; /* "unsigned long" so bitops work */
@@ -139,10 +150,10 @@
struct kref ref;
/*
- * List running through all cgroup groups. Protected by
- * css_set_lock
+ * List running through all cgroup groups in the same hash
+ * slot. Protected by css_set_lock
*/
- struct list_head list;
+ struct hlist_node hlist;
/*
* List running through all tasks using this cgroup
@@ -163,7 +174,16 @@
* during subsystem registration (at boot time).
*/
struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
+};
+/*
+ * cgroup_map_cb is an abstract callback API for reporting map-valued
+ * control files
+ */
+
+struct cgroup_map_cb {
+ int (*fill)(struct cgroup_map_cb *cb, const char *key, u64 value);
+ void *state;
};
/* struct cftype:
@@ -190,20 +210,51 @@
struct file *file,
char __user *buf, size_t nbytes, loff_t *ppos);
/*
- * read_uint() is a shortcut for the common case of returning a
+ * read_u64() is a shortcut for the common case of returning a
* single integer. Use it in place of read()
*/
- u64 (*read_uint) (struct cgroup *cgrp, struct cftype *cft);
+ u64 (*read_u64) (struct cgroup *cgrp, struct cftype *cft);
+ /*
+ * read_s64() is a signed version of read_u64()
+ */
+ s64 (*read_s64) (struct cgroup *cgrp, struct cftype *cft);
+ /*
+ * read_map() is used for defining a map of key/value
+ * pairs. It should call cb->fill(cb, key, value) for each
+ * entry. The key/value pairs (and their ordering) should not
+ * change between reboots.
+ */
+ int (*read_map) (struct cgroup *cont, struct cftype *cft,
+ struct cgroup_map_cb *cb);
+ /*
+ * read_seq_string() is used for outputting a simple sequence
+ * using seqfile.
+ */
+ int (*read_seq_string) (struct cgroup *cont, struct cftype *cft,
+ struct seq_file *m);
+
ssize_t (*write) (struct cgroup *cgrp, struct cftype *cft,
struct file *file,
const char __user *buf, size_t nbytes, loff_t *ppos);
/*
- * write_uint() is a shortcut for the common case of accepting
+ * write_u64() is a shortcut for the common case of accepting
* a single integer (as parsed by simple_strtoull) from
* userspace. Use in place of write(); return 0 or error.
*/
- int (*write_uint) (struct cgroup *cgrp, struct cftype *cft, u64 val);
+ int (*write_u64) (struct cgroup *cgrp, struct cftype *cft, u64 val);
+ /*
+ * write_s64() is a signed version of write_u64()
+ */
+ int (*write_s64) (struct cgroup *cgrp, struct cftype *cft, s64 val);
+
+ /*
+ * trigger() callback can be used to get some kick from the
+ * userspace, when the actual string written is not important
+ * at all. The private field can be used to determine the
+ * kick type for multiplexing.
+ */
+ int (*trigger)(struct cgroup *cgrp, unsigned int event);
int (*release) (struct inode *inode, struct file *file);
};
@@ -254,6 +305,12 @@
struct cgroup *cgrp);
void (*post_clone)(struct cgroup_subsys *ss, struct cgroup *cgrp);
void (*bind)(struct cgroup_subsys *ss, struct cgroup *root);
+ /*
+ * This routine is called with the task_lock of mm->owner held
+ */
+ void (*mm_owner_changed)(struct cgroup_subsys *ss,
+ struct cgroup *old,
+ struct cgroup *new);
int subsys_id;
int active;
int disabled;
@@ -339,4 +396,13 @@
#endif /* !CONFIG_CGROUPS */
+#ifdef CONFIG_MM_OWNER
+extern void
+cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new);
+#else /* !CONFIG_MM_OWNER */
+static inline void
+cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new)
+{
+}
+#endif /* CONFIG_MM_OWNER */
#endif /* _LINUX_CGROUP_H */
diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h
index 1ddebfc..e287745 100644
--- a/include/linux/cgroup_subsys.h
+++ b/include/linux/cgroup_subsys.h
@@ -42,3 +42,9 @@
#endif
/* */
+
+#ifdef CONFIG_CGROUP_DEVICE
+SUBSYS(devices)
+#endif
+
+/* */
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 3509447..55e434f 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -93,6 +93,8 @@
#endif
};
+extern struct clocksource *clock; /* current clocksource */
+
/*
* Clock source flags bits::
*/
diff --git a/include/linux/coda_fs_i.h b/include/linux/coda_fs_i.h
index 424fe9c..b3ef0c4 100644
--- a/include/linux/coda_fs_i.h
+++ b/include/linux/coda_fs_i.h
@@ -8,7 +8,6 @@
#ifndef _LINUX_CODA_FS_I
#define _LINUX_CODA_FS_I
-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/list.h>
#include <linux/coda.h>
@@ -52,4 +51,3 @@
void coda_replace_fid(struct inode *, struct CodaFid *, struct CodaFid *);
#endif
-#endif
diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h
index 1c47a34..31b7531 100644
--- a/include/linux/coda_linux.h
+++ b/include/linux/coda_linux.h
@@ -43,9 +43,6 @@
int coda_setattr(struct dentry *, struct iattr *);
/* this file: heloers */
-static __inline__ struct CodaFid *coda_i2f(struct inode *);
-static __inline__ char *coda_i2s(struct inode *);
-static __inline__ void coda_flag_inode(struct inode *, int flag);
char *coda_f2s(struct CodaFid *f);
int coda_isroot(struct inode *i);
int coda_iscontrol(const char *name, size_t length);
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 8fa7857..cf8d11c 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -65,10 +65,11 @@
compat_long_t calcnt;
compat_long_t errcnt;
compat_long_t stbcnt;
+ compat_int_t tai;
compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
- compat_int_t :32; compat_int_t :32; compat_int_t :32; compat_int_t :32;
+ compat_int_t :32; compat_int_t :32; compat_int_t :32;
};
#define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW)
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
index b2fd754..5c8351b 100644
--- a/include/linux/compiler-gcc.h
+++ b/include/linux/compiler-gcc.h
@@ -29,10 +29,11 @@
BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
/*
- * Force always-inline if the user requests it so via the .config:
+ * Force always-inline if the user requests it so via the .config,
+ * or if gcc is too old:
*/
#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \
- !defined(CONFIG_OPTIMIZE_INLINING) && (__GNUC__ >= 4)
+ !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
# define inline inline __attribute__((always_inline))
# define __inline__ __inline__ __attribute__((always_inline))
# define __inline __inline __attribute__((always_inline))
diff --git a/include/linux/concap.h b/include/linux/concap.h
index 2730465..977acb3 100644
--- a/include/linux/concap.h
+++ b/include/linux/concap.h
@@ -8,7 +8,7 @@
#ifndef _LINUX_CONCAP_H
#define _LINUX_CONCAP_H
-#ifdef __KERNEL__
+
#include <linux/skbuff.h>
#include <linux/netdevice.h>
@@ -110,4 +110,3 @@
*/
extern int concap_drop_skb(struct concap_proto *cprot, struct sk_buff *skb);
#endif
-#endif
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index 4b287ad..3ae65b1 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -35,8 +35,6 @@
#ifndef _CONFIGFS_H_
#define _CONFIGFS_H_
-#ifdef __KERNEL__
-
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/list.h>
@@ -194,6 +192,4 @@
int configfs_depend_item(struct configfs_subsystem *subsys, struct config_item *target);
void configfs_undepend_item(struct configfs_subsystem *subsys, struct config_item *target);
-#endif /* __KERNEL__ */
-
#endif /* _CONFIGFS_H_ */
diff --git a/include/linux/console.h b/include/linux/console.h
index a5f88a6..a4f27fb 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -91,6 +91,7 @@
#define CON_ENABLED (4)
#define CON_BOOT (8)
#define CON_ANYTIME (16) /* Safe to call when cpu is offline */
+#define CON_BRL (32) /* Used for a braille device */
struct console {
char name[16];
@@ -121,6 +122,9 @@
extern void console_stop(struct console *);
extern void console_start(struct console *);
extern int is_console_locked(void);
+extern int braille_register_console(struct console *, int index,
+ char *console_options, char *braille_options);
+extern int braille_unregister_console(struct console *);
extern int console_suspend_enabled;
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index d71f7c0..b03f80a 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -53,6 +53,7 @@
unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
struct console_font vc_font; /* Current VC font set */
unsigned short vc_video_erase_char; /* Background erase character */
+ unsigned short vc_scrl_erase_char; /* Erase character for scroll */
/* VT terminal data */
unsigned int vc_state; /* Escape sequence parser state */
unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index f212fa9..7464ba3 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -108,7 +108,7 @@
extern void get_online_cpus(void);
extern void put_online_cpus(void);
#define hotcpu_notifier(fn, pri) { \
- static struct notifier_block fn##_nb = \
+ static struct notifier_block fn##_nb __cpuinitdata = \
{ .notifier_call = fn, .priority = pri }; \
register_cpu_notifier(&fn##_nb); \
}
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index ddd8652..e7e91db 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -83,7 +83,8 @@
};
struct cpufreq_policy {
- cpumask_t cpus; /* affected CPUs */
+ cpumask_t cpus; /* CPUs requiring sw coordination */
+ cpumask_t related_cpus; /* CPUs with any coordination */
unsigned int shared_type; /* ANY or ALL affected CPUs
should set cpufreq */
unsigned int cpu; /* cpu nr of registered CPU */
@@ -307,6 +308,9 @@
#endif
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE
#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_performance)
+#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE)
+extern struct cpufreq_governor cpufreq_gov_powersave;
+#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_powersave)
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE)
extern struct cpufreq_governor cpufreq_gov_userspace;
#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_userspace)
diff --git a/include/linux/crc-ccitt.h b/include/linux/crc-ccitt.h
index 9003761..f52696a 100644
--- a/include/linux/crc-ccitt.h
+++ b/include/linux/crc-ccitt.h
@@ -1,6 +1,5 @@
#ifndef _LINUX_CRC_CCITT_H
#define _LINUX_CRC_CCITT_H
-#ifdef __KERNEL__
#include <linux/types.h>
@@ -13,5 +12,4 @@
return (crc >> 8) ^ crc_ccitt_table[(crc ^ c) & 0xff];
}
-#endif /* __KERNEL__ */
#endif /* _LINUX_CRC_CCITT_H */
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index cfb1627..2a66394 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -1,8 +1,6 @@
#ifndef __LINUX_DCACHE_H
#define __LINUX_DCACHE_H
-#ifdef __KERNEL__
-
#include <asm/atomic.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -365,6 +363,4 @@
extern int sysctl_vfs_cache_pressure;
-#endif /* __KERNEL__ */
-
#endif /* __LINUX_DCACHE_H */
diff --git a/include/linux/debugobjects.h b/include/linux/debugobjects.h
new file mode 100644
index 0000000..8c243aa
--- /dev/null
+++ b/include/linux/debugobjects.h
@@ -0,0 +1,90 @@
+#ifndef _LINUX_DEBUGOBJECTS_H
+#define _LINUX_DEBUGOBJECTS_H
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+enum debug_obj_state {
+ ODEBUG_STATE_NONE,
+ ODEBUG_STATE_INIT,
+ ODEBUG_STATE_INACTIVE,
+ ODEBUG_STATE_ACTIVE,
+ ODEBUG_STATE_DESTROYED,
+ ODEBUG_STATE_NOTAVAILABLE,
+ ODEBUG_STATE_MAX,
+};
+
+struct debug_obj_descr;
+
+/**
+ * struct debug_obj - representaion of an tracked object
+ * @node: hlist node to link the object into the tracker list
+ * @state: tracked object state
+ * @object: pointer to the real object
+ * @descr: pointer to an object type specific debug description structure
+ */
+struct debug_obj {
+ struct hlist_node node;
+ enum debug_obj_state state;
+ void *object;
+ struct debug_obj_descr *descr;
+};
+
+/**
+ * struct debug_obj_descr - object type specific debug description structure
+ * @name: name of the object typee
+ * @fixup_init: fixup function, which is called when the init check
+ * fails
+ * @fixup_activate: fixup function, which is called when the activate check
+ * fails
+ * @fixup_destroy: fixup function, which is called when the destroy check
+ * fails
+ * @fixup_free: fixup function, which is called when the free check
+ * fails
+ */
+struct debug_obj_descr {
+ const char *name;
+
+ int (*fixup_init) (void *addr, enum debug_obj_state state);
+ int (*fixup_activate) (void *addr, enum debug_obj_state state);
+ int (*fixup_destroy) (void *addr, enum debug_obj_state state);
+ int (*fixup_free) (void *addr, enum debug_obj_state state);
+};
+
+#ifdef CONFIG_DEBUG_OBJECTS
+extern void debug_object_init (void *addr, struct debug_obj_descr *descr);
+extern void
+debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr);
+extern void debug_object_activate (void *addr, struct debug_obj_descr *descr);
+extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr);
+extern void debug_object_destroy (void *addr, struct debug_obj_descr *descr);
+extern void debug_object_free (void *addr, struct debug_obj_descr *descr);
+
+extern void debug_objects_early_init(void);
+extern void debug_objects_mem_init(void);
+#else
+static inline void
+debug_object_init (void *addr, struct debug_obj_descr *descr) { }
+static inline void
+debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) { }
+static inline void
+debug_object_activate (void *addr, struct debug_obj_descr *descr) { }
+static inline void
+debug_object_deactivate(void *addr, struct debug_obj_descr *descr) { }
+static inline void
+debug_object_destroy (void *addr, struct debug_obj_descr *descr) { }
+static inline void
+debug_object_free (void *addr, struct debug_obj_descr *descr) { }
+
+static inline void debug_objects_early_init(void) { }
+static inline void debug_objects_mem_init(void) { }
+#endif
+
+#ifdef CONFIG_DEBUG_OBJECTS_FREE
+extern void debug_check_no_obj_freed(const void *address, unsigned long size);
+#else
+static inline void
+debug_check_no_obj_freed(const void *address, unsigned long size) { }
+#endif
+
+#endif
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index ad3b787..0d8d419 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -8,8 +8,6 @@
#ifndef _LINUX_DEVICE_MAPPER_H
#define _LINUX_DEVICE_MAPPER_H
-#ifdef __KERNEL__
-
#include <linux/bio.h>
struct dm_target;
@@ -344,5 +342,4 @@
return (n << SECTOR_SHIFT);
}
-#endif /* __KERNEL__ */
#endif /* _LINUX_DEVICE_MAPPER_H */
diff --git a/include/linux/device.h b/include/linux/device.h
index 1a06026..8c23e3d 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -35,7 +35,6 @@
struct device_driver;
struct driver_private;
struct class;
-struct class_device;
struct bus_type;
struct bus_type_private;
@@ -190,13 +189,10 @@
struct kset class_dirs;
struct semaphore sem; /* locks children, devices, interfaces */
struct class_attribute *class_attrs;
- struct class_device_attribute *class_dev_attrs;
struct device_attribute *dev_attrs;
- int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
- void (*release)(struct class_device *dev);
void (*class_release)(struct class *class);
void (*dev_release)(struct device *dev);
@@ -210,9 +206,6 @@
int (*fn)(struct device *dev, void *data));
extern struct device *class_find_device(struct class *class, void *data,
int (*match)(struct device *, void *));
-extern struct class_device *class_find_child(struct class *class, void *data,
- int (*match)(struct class_device *, void *));
-
struct class_attribute {
struct attribute attr;
@@ -228,92 +221,10 @@
extern void class_remove_file(struct class *class,
const struct class_attribute *attr);
-struct class_device_attribute {
- struct attribute attr;
- ssize_t (*show)(struct class_device *, char *buf);
- ssize_t (*store)(struct class_device *, const char *buf, size_t count);
-};
-
-#define CLASS_DEVICE_ATTR(_name, _mode, _show, _store) \
-struct class_device_attribute class_device_attr_##_name = \
- __ATTR(_name, _mode, _show, _store)
-
-extern int __must_check class_device_create_file(struct class_device *,
- const struct class_device_attribute *);
-
-/**
- * struct class_device - class devices
- * @class: pointer to the parent class for this class device. This is required.
- * @devt: for internal use by the driver core only.
- * @node: for internal use by the driver core only.
- * @kobj: for internal use by the driver core only.
- * @groups: optional additional groups to be created
- * @dev: if set, a symlink to the struct device is created in the sysfs
- * directory for this struct class device.
- * @class_data: pointer to whatever you want to store here for this struct
- * class_device. Use class_get_devdata() and class_set_devdata() to get and
- * set this pointer.
- * @parent: pointer to a struct class_device that is the parent of this struct
- * class_device. If NULL, this class_device will show up at the root of the
- * struct class in sysfs (which is probably what you want to have happen.)
- * @release: pointer to a release function for this struct class_device. If
- * set, this will be called instead of the class specific release function.
- * Only use this if you want to override the default release function, like
- * when you are nesting class_device structures.
- * @uevent: pointer to a uevent function for this struct class_device. If
- * set, this will be called instead of the class specific uevent function.
- * Only use this if you want to override the default uevent function, like
- * when you are nesting class_device structures.
- */
-struct class_device {
- struct list_head node;
-
- struct kobject kobj;
- struct class *class;
- dev_t devt;
- struct device *dev;
- void *class_data;
- struct class_device *parent;
- struct attribute_group **groups;
-
- void (*release)(struct class_device *dev);
- int (*uevent)(struct class_device *dev, struct kobj_uevent_env *env);
- char class_id[BUS_ID_SIZE];
-};
-
-static inline void *class_get_devdata(struct class_device *dev)
-{
- return dev->class_data;
-}
-
-static inline void class_set_devdata(struct class_device *dev, void *data)
-{
- dev->class_data = data;
-}
-
-
-extern int __must_check class_device_register(struct class_device *);
-extern void class_device_unregister(struct class_device *);
-extern void class_device_initialize(struct class_device *);
-extern int __must_check class_device_add(struct class_device *);
-extern void class_device_del(struct class_device *);
-
-extern struct class_device *class_device_get(struct class_device *);
-extern void class_device_put(struct class_device *);
-
-extern void class_device_remove_file(struct class_device *,
- const struct class_device_attribute *);
-extern int __must_check class_device_create_bin_file(struct class_device *,
- struct bin_attribute *);
-extern void class_device_remove_bin_file(struct class_device *,
- struct bin_attribute *);
-
struct class_interface {
struct list_head node;
struct class *class;
- int (*add) (struct class_device *, struct class_interface *);
- void (*remove) (struct class_device *, struct class_interface *);
int (*add_dev) (struct device *, struct class_interface *);
void (*remove_dev) (struct device *, struct class_interface *);
};
@@ -323,13 +234,6 @@
extern struct class *class_create(struct module *owner, const char *name);
extern void class_destroy(struct class *cls);
-extern struct class_device *class_device_create(struct class *cls,
- struct class_device *parent,
- dev_t devt,
- struct device *device,
- const char *fmt, ...)
- __attribute__((format(printf, 5, 6)));
-extern void class_device_destroy(struct class *cls, dev_t devt);
/*
* The type of device, "struct device" is embedded in. A class
@@ -465,7 +369,6 @@
spinlock_t devres_lock;
struct list_head devres_head;
- /* class_device migration path */
struct list_head node;
struct class *class;
dev_t devt; /* dev_t, creates the sysfs "dev" */
@@ -477,6 +380,12 @@
/* Get the wakeup routines, which depend on struct device */
#include <linux/pm_wakeup.h>
+static inline const char *dev_name(struct device *dev)
+{
+ /* will be changed into kobject_name(&dev->kobj) in the near future */
+ return dev->bus_id;
+}
+
#ifdef CONFIG_NUMA
static inline int dev_to_node(struct device *dev)
{
@@ -575,7 +484,7 @@
extern const char *dev_driver_string(struct device *dev);
#define dev_printk(level, dev, format, arg...) \
printk(level "%s %s: " format , dev_driver_string(dev) , \
- (dev)->bus_id , ## arg)
+ dev_name(dev) , ## arg)
#define dev_emerg(dev, format, arg...) \
dev_printk(KERN_EMERG , dev , format , ## arg)
diff --git a/include/linux/device_cgroup.h b/include/linux/device_cgroup.h
new file mode 100644
index 0000000..0b0d9c3
--- /dev/null
+++ b/include/linux/device_cgroup.h
@@ -0,0 +1,12 @@
+#include <linux/module.h>
+#include <linux/fs.h>
+
+#ifdef CONFIG_CGROUP_DEVICE
+extern int devcgroup_inode_permission(struct inode *inode, int mask);
+extern int devcgroup_inode_mknod(int mode, dev_t dev);
+#else
+static inline int devcgroup_inode_permission(struct inode *inode, int mask)
+{ return 0; }
+static inline int devcgroup_inode_mknod(int mode, dev_t dev)
+{ return 0; }
+#endif
diff --git a/include/linux/devpts_fs.h b/include/linux/devpts_fs.h
index b672ddc..154769c 100644
--- a/include/linux/devpts_fs.h
+++ b/include/linux/devpts_fs.h
@@ -17,6 +17,8 @@
#ifdef CONFIG_UNIX98_PTYS
+int devpts_new_index(void);
+void devpts_kill_index(int idx);
int devpts_pty_new(struct tty_struct *tty); /* mknod in devpts */
struct tty_struct *devpts_get_tty(int number); /* get tty structure */
void devpts_pty_kill(int number); /* unlink */
@@ -24,6 +26,8 @@
#else
/* Dummy stubs in the no-pty case */
+static inline int devpts_new_index(void) { return -EINVAL; }
+static inline void devpts_kill_index(int idx) { }
static inline int devpts_pty_new(struct tty_struct *tty) { return -EINVAL; }
static inline struct tty_struct *devpts_get_tty(int number) { return NULL; }
static inline void devpts_pty_kill(int number) { }
diff --git a/include/linux/dma-attrs.h b/include/linux/dma-attrs.h
new file mode 100644
index 0000000..1677e2b
--- /dev/null
+++ b/include/linux/dma-attrs.h
@@ -0,0 +1,74 @@
+#ifndef _DMA_ATTR_H
+#define _DMA_ATTR_H
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
+
+/**
+ * an enum dma_attr represents an attribute associated with a DMA
+ * mapping. The semantics of each attribute should be defined in
+ * Documentation/DMA-attributes.txt.
+ */
+enum dma_attr {
+ DMA_ATTR_WRITE_BARRIER,
+ DMA_ATTR_MAX,
+};
+
+#define __DMA_ATTRS_LONGS BITS_TO_LONGS(DMA_ATTR_MAX)
+
+/**
+ * struct dma_attrs - an opaque container for DMA attributes
+ * @flags - bitmask representing a collection of enum dma_attr
+ */
+struct dma_attrs {
+ unsigned long flags[__DMA_ATTRS_LONGS];
+};
+
+#define DEFINE_DMA_ATTRS(x) \
+ struct dma_attrs x = { \
+ .flags = { [0 ... __DMA_ATTRS_LONGS-1] = 0 }, \
+ }
+
+static inline void init_dma_attrs(struct dma_attrs *attrs)
+{
+ bitmap_zero(attrs->flags, __DMA_ATTRS_LONGS);
+}
+
+#ifdef CONFIG_HAVE_DMA_ATTRS
+/**
+ * dma_set_attr - set a specific attribute
+ * @attr: attribute to set
+ * @attrs: struct dma_attrs (may be NULL)
+ */
+static inline void dma_set_attr(enum dma_attr attr, struct dma_attrs *attrs)
+{
+ if (attrs == NULL)
+ return;
+ BUG_ON(attr >= DMA_ATTR_MAX);
+ __set_bit(attr, attrs->flags);
+}
+
+/**
+ * dma_get_attr - check for a specific attribute
+ * @attr: attribute to set
+ * @attrs: struct dma_attrs (may be NULL)
+ */
+static inline int dma_get_attr(enum dma_attr attr, struct dma_attrs *attrs)
+{
+ if (attrs == NULL)
+ return 0;
+ BUG_ON(attr >= DMA_ATTR_MAX);
+ return test_bit(attr, attrs->flags);
+}
+#else /* !CONFIG_HAVE_DMA_ATTRS */
+static inline void dma_set_attr(enum dma_attr attr, struct dma_attrs *attrs)
+{
+}
+
+static inline int dma_get_attr(enum dma_attr attr, struct dma_attrs *attrs)
+{
+ return 0;
+}
+#endif /* CONFIG_HAVE_DMA_ATTRS */
+#endif /* _DMA_ATTR_H */
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 3320307..952e0f8 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -146,4 +146,21 @@
}
#endif /* ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY */
+#ifndef CONFIG_HAVE_DMA_ATTRS
+struct dma_attrs;
+
+#define dma_map_single_attrs(dev, cpu_addr, size, dir, attrs) \
+ dma_map_single(dev, cpu_addr, size, dir)
+
+#define dma_unmap_single_attrs(dev, dma_addr, size, dir, attrs) \
+ dma_unmap_single(dev, dma_addr, size, dir)
+
+#define dma_map_sg_attrs(dev, sgl, nents, dir, attrs) \
+ dma_map_sg(dev, sgl, nents, dir)
+
+#define dma_unmap_sg_attrs(dev, sgl, nents, dir, attrs) \
+ dma_unmap_sg(dev, sgl, nents, dir)
+
+#endif /* CONFIG_HAVE_DMA_ATTRS */
+
#endif
diff --git a/include/linux/edac.h b/include/linux/edac.h
index eab451e..7cf92e8 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -3,7 +3,7 @@
*
* Author: Dave Jiang <djiang@mvista.com>
*
- * 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
+ * 2006-2008 (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.
@@ -26,4 +26,16 @@
extern int edac_handler_set(void);
extern void edac_atomic_assert_error(void);
+static inline void opstate_init(void)
+{
+ switch (edac_op_state) {
+ case EDAC_OPSTATE_POLL:
+ case EDAC_OPSTATE_NMI:
+ break;
+ default:
+ edac_op_state = EDAC_OPSTATE_POLL;
+ }
+ return;
+}
+
#endif
diff --git a/include/linux/elf.h b/include/linux/elf.h
index bad1b16..ff9fbed 100644
--- a/include/linux/elf.h
+++ b/include/linux/elf.h
@@ -208,7 +208,7 @@
} Elf32_Ehdr;
typedef struct elf64_hdr {
- unsigned char e_ident[16]; /* ELF "magic number" */
+ unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
diff --git a/include/linux/eventfd.h b/include/linux/eventfd.h
index b489fc6..a701399 100644
--- a/include/linux/eventfd.h
+++ b/include/linux/eventfd.h
@@ -8,9 +8,6 @@
#ifndef _LINUX_EVENTFD_H
#define _LINUX_EVENTFD_H
-
-#ifdef __KERNEL__
-
#ifdef CONFIG_EVENTFD
struct file *eventfd_fget(int fd);
@@ -24,7 +21,5 @@
#endif /* CONFIG_EVENTFD */
-#endif /* __KERNEL__ */
-
#endif /* _LINUX_EVENTFD_H */
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
new file mode 100644
index 0000000..a118f3c
--- /dev/null
+++ b/include/linux/fdtable.h
@@ -0,0 +1,99 @@
+/*
+ * descriptor table internals; you almost certainly want file.h instead.
+ */
+
+#ifndef __LINUX_FDTABLE_H
+#define __LINUX_FDTABLE_H
+
+#include <asm/atomic.h>
+#include <linux/posix_types.h>
+#include <linux/compiler.h>
+#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
+#include <linux/types.h>
+
+/*
+ * The default fd array needs to be at least BITS_PER_LONG,
+ * as this is the granularity returned by copy_fdset().
+ */
+#define NR_OPEN_DEFAULT BITS_PER_LONG
+
+/*
+ * The embedded_fd_set is a small fd_set,
+ * suitable for most tasks (which open <= BITS_PER_LONG files)
+ */
+struct embedded_fd_set {
+ unsigned long fds_bits[1];
+};
+
+struct fdtable {
+ unsigned int max_fds;
+ struct file ** fd; /* current fd array */
+ fd_set *close_on_exec;
+ fd_set *open_fds;
+ struct rcu_head rcu;
+ struct fdtable *next;
+};
+
+/*
+ * Open file table structure
+ */
+struct files_struct {
+ /*
+ * read mostly part
+ */
+ atomic_t count;
+ struct fdtable *fdt;
+ struct fdtable fdtab;
+ /*
+ * written part on a separate cache line in SMP
+ */
+ spinlock_t file_lock ____cacheline_aligned_in_smp;
+ int next_fd;
+ struct embedded_fd_set close_on_exec_init;
+ struct embedded_fd_set open_fds_init;
+ struct file * fd_array[NR_OPEN_DEFAULT];
+};
+
+#define files_fdtable(files) (rcu_dereference((files)->fdt))
+
+extern struct kmem_cache *filp_cachep;
+
+struct file_operations;
+struct vfsmount;
+struct dentry;
+
+extern int expand_files(struct files_struct *, int nr);
+extern void free_fdtable_rcu(struct rcu_head *rcu);
+extern void __init files_defer_init(void);
+
+static inline void free_fdtable(struct fdtable *fdt)
+{
+ call_rcu(&fdt->rcu, free_fdtable_rcu);
+}
+
+static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
+{
+ struct file * file = NULL;
+ struct fdtable *fdt = files_fdtable(files);
+
+ if (fd < fdt->max_fds)
+ file = rcu_dereference(fdt->fd[fd]);
+ return file;
+}
+
+/*
+ * Check whether the specified fd has an open file.
+ */
+#define fcheck(fd) fcheck_files(current->files, fd)
+
+struct task_struct;
+
+struct files_struct *get_files_struct(struct task_struct *);
+void put_files_struct(struct files_struct *fs);
+void reset_files_struct(struct files_struct *);
+int unshare_files(struct files_struct **);
+
+extern struct kmem_cache *files_cachep;
+
+#endif /* __LINUX_FDTABLE_H */
diff --git a/include/linux/file.h b/include/linux/file.h
index 69baf5a4..27c64bd 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -5,59 +5,11 @@
#ifndef __LINUX_FILE_H
#define __LINUX_FILE_H
-#include <asm/atomic.h>
-#include <linux/posix_types.h>
#include <linux/compiler.h>
-#include <linux/spinlock.h>
-#include <linux/rcupdate.h>
#include <linux/types.h>
+#include <linux/posix_types.h>
-/*
- * The default fd array needs to be at least BITS_PER_LONG,
- * as this is the granularity returned by copy_fdset().
- */
-#define NR_OPEN_DEFAULT BITS_PER_LONG
-
-/*
- * The embedded_fd_set is a small fd_set,
- * suitable for most tasks (which open <= BITS_PER_LONG files)
- */
-struct embedded_fd_set {
- unsigned long fds_bits[1];
-};
-
-struct fdtable {
- unsigned int max_fds;
- struct file ** fd; /* current fd array */
- fd_set *close_on_exec;
- fd_set *open_fds;
- struct rcu_head rcu;
- struct fdtable *next;
-};
-
-/*
- * Open file table structure
- */
-struct files_struct {
- /*
- * read mostly part
- */
- atomic_t count;
- struct fdtable *fdt;
- struct fdtable fdtab;
- /*
- * written part on a separate cache line in SMP
- */
- spinlock_t file_lock ____cacheline_aligned_in_smp;
- int next_fd;
- struct embedded_fd_set close_on_exec_init;
- struct embedded_fd_set open_fds_init;
- struct file * fd_array[NR_OPEN_DEFAULT];
-};
-
-#define files_fdtable(files) (rcu_dereference((files)->fdt))
-
-extern struct kmem_cache *filp_cachep;
+struct file;
extern void __fput(struct file *);
extern void fput(struct file *);
@@ -85,41 +37,7 @@
extern int get_unused_fd(void);
extern int get_unused_fd_flags(int flags);
extern void put_unused_fd(unsigned int fd);
-struct kmem_cache;
-
-extern int expand_files(struct files_struct *, int nr);
-extern void free_fdtable_rcu(struct rcu_head *rcu);
-extern void __init files_defer_init(void);
-
-static inline void free_fdtable(struct fdtable *fdt)
-{
- call_rcu(&fdt->rcu, free_fdtable_rcu);
-}
-
-static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
-{
- struct file * file = NULL;
- struct fdtable *fdt = files_fdtable(files);
-
- if (fd < fdt->max_fds)
- file = rcu_dereference(fdt->fd[fd]);
- return file;
-}
-
-/*
- * Check whether the specified fd has an open file.
- */
-#define fcheck(fd) fcheck_files(current->files, fd)
extern void fd_install(unsigned int fd, struct file *file);
-struct task_struct;
-
-struct files_struct *get_files_struct(struct task_struct *);
-void put_files_struct(struct files_struct *fs);
-void reset_files_struct(struct files_struct *);
-int unshare_files(struct files_struct **);
-
-extern struct kmem_cache *files_cachep;
-
#endif /* __LINUX_FILE_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2c92574..a1ba005 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1521,7 +1521,6 @@
const struct super_operations *ops, unsigned long,
struct vfsmount *mnt);
extern int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
-int __put_super(struct super_block *sb);
int __put_super_and_need_restart(struct super_block *sb);
void unnamed_dev_init(void);
@@ -1965,7 +1964,6 @@
extern int vfs_lstat_fd(int dfd, char __user *, struct kstat *);
extern int vfs_fstat(unsigned int, struct kstat *);
-extern long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
unsigned long arg);
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 2cad5c6..c415a49 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -14,7 +14,6 @@
* option) any later version.
*/
-#ifdef __KERNEL__
#ifndef _FSL_DEVICE_H_
#define _FSL_DEVICE_H_
@@ -127,4 +126,3 @@
};
#endif /* _FSL_DEVICE_H_ */
-#endif /* __KERNEL__ */
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index d4b7c4a..a895131 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -11,8 +11,6 @@
* (C) Copyright 2005 Robert Love
*/
-#ifdef __KERNEL__
-
#include <linux/dnotify.h>
#include <linux/inotify.h>
#include <linux/audit.h>
@@ -296,6 +294,4 @@
#endif /* ! CONFIG_INOTIFY */
-#endif /* __KERNEL__ */
-
#endif /* _LINUX_FS_NOTIFY_H */
diff --git a/include/linux/generic_serial.h b/include/linux/generic_serial.h
index 5412da2..1108336 100644
--- a/include/linux/generic_serial.h
+++ b/include/linux/generic_serial.h
@@ -78,7 +78,7 @@
#define GS_DEBUG_WRITE 0x00000040
#ifdef __KERNEL__
-void gs_put_char(struct tty_struct *tty, unsigned char ch);
+int gs_put_char(struct tty_struct *tty, unsigned char ch);
int gs_write(struct tty_struct *tty,
const unsigned char *buf, int count);
int gs_write_room(struct tty_struct *tty);
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index c37653b..b414be3 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -40,9 +40,9 @@
#define __GFP_FS ((__force gfp_t)0x80u) /* Can call down to low-level FS? */
#define __GFP_COLD ((__force gfp_t)0x100u) /* Cache-cold page required */
#define __GFP_NOWARN ((__force gfp_t)0x200u) /* Suppress page allocation failure warning */
-#define __GFP_REPEAT ((__force gfp_t)0x400u) /* Retry the allocation. Might fail */
-#define __GFP_NOFAIL ((__force gfp_t)0x800u) /* Retry for ever. Cannot fail */
-#define __GFP_NORETRY ((__force gfp_t)0x1000u)/* Do not retry. Might fail */
+#define __GFP_REPEAT ((__force gfp_t)0x400u) /* See above */
+#define __GFP_NOFAIL ((__force gfp_t)0x800u) /* See above */
+#define __GFP_NORETRY ((__force gfp_t)0x1000u)/* See above */
#define __GFP_COMP ((__force gfp_t)0x4000u)/* Add compound page metadata */
#define __GFP_ZERO ((__force gfp_t)0x8000u)/* Return zeroed page on success */
#define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 56f3236..31a4d65 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -266,6 +266,21 @@
extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock,
enum hrtimer_mode mode);
+#ifdef CONFIG_DEBUG_OBJECTS_TIMERS
+extern void hrtimer_init_on_stack(struct hrtimer *timer, clockid_t which_clock,
+ enum hrtimer_mode mode);
+
+extern void destroy_hrtimer_on_stack(struct hrtimer *timer);
+#else
+static inline void hrtimer_init_on_stack(struct hrtimer *timer,
+ clockid_t which_clock,
+ enum hrtimer_mode mode)
+{
+ hrtimer_init(timer, which_clock, mode);
+}
+static inline void destroy_hrtimer_on_stack(struct hrtimer *timer) { }
+#endif
+
/* Basic timer operations: */
extern int hrtimer_start(struct hrtimer *timer, ktime_t tim,
const enum hrtimer_mode mode);
diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h
index 85d1191..7244456 100644
--- a/include/linux/hw_random.h
+++ b/include/linux/hw_random.h
@@ -11,7 +11,6 @@
#ifndef LINUX_HWRANDOM_H_
#define LINUX_HWRANDOM_H_
-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/list.h>
@@ -46,5 +45,4 @@
/** Unregister a Hardware Random Number Generator driver. */
extern void hwrng_unregister(struct hwrng *rng);
-#endif /* __KERNEL__ */
#endif /* LINUX_HWRANDOM_H_ */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 32eb8bb..580acc9 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -79,12 +79,9 @@
#define I2C_DRIVERID_UPD64031A 79 /* upd64031a video processor */
#define I2C_DRIVERID_SAA717X 80 /* saa717x video encoder */
#define I2C_DRIVERID_DS1672 81 /* Dallas/Maxim DS1672 RTC */
-#define I2C_DRIVERID_X1205 82 /* Xicor/Intersil X1205 RTC */
-#define I2C_DRIVERID_PCF8563 83 /* Philips PCF8563 RTC */
#define I2C_DRIVERID_BT866 85 /* Conexant bt866 video encoder */
#define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */
#define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */
-#define I2C_DRIVERID_ISL1208 88 /* Intersil ISL1208 RTC */
#define I2C_DRIVERID_WM8731 89 /* Wolfson WM8731 audio codec */
#define I2C_DRIVERID_WM8750 90 /* Wolfson WM8750 audio codec */
#define I2C_DRIVERID_WM8753 91 /* Wolfson WM8753 audio codec */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 365e0df..cb63da5 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -126,7 +126,7 @@
* With the driver model, device enumeration is NEVER done by drivers;
* it's done by infrastructure. (NEW STYLE DRIVERS ONLY)
*/
- int (*probe)(struct i2c_client *);
+ int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration */
@@ -140,11 +140,10 @@
int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
struct device_driver driver;
+ const struct i2c_device_id *id_table;
};
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
-#define I2C_NAME_SIZE 20
-
/**
* struct i2c_client - represent an I2C slave device
* @flags: I2C_CLIENT_TEN indicates the device uses a ten bit chip address;
@@ -230,17 +229,17 @@
};
/**
- * I2C_BOARD_INFO - macro used to list an i2c device and its driver
- * @driver: identifies the driver to use with the device
+ * I2C_BOARD_INFO - macro used to list an i2c device and its address
+ * @dev_type: identifies the device type
* @dev_addr: the device's address on the bus.
*
* This macro initializes essential fields of a struct i2c_board_info,
* declaring what has been provided on a particular board. Optional
- * fields (such as the chip type, its associated irq, or device-specific
- * platform_data) are provided using conventional syntax.
+ * fields (such as associated irq, or device-specific platform_data)
+ * are provided using conventional syntax.
*/
-#define I2C_BOARD_INFO(driver,dev_addr) \
- .driver_name = (driver), .addr = (dev_addr)
+#define I2C_BOARD_INFO(dev_type,dev_addr) \
+ .type = (dev_type), .addr = (dev_addr)
/* Add-on boards should register/unregister their devices; e.g. a board
diff --git a/include/linux/i2o.h b/include/linux/i2o.h
index f65e58a..7d51cbc 100644
--- a/include/linux/i2o.h
+++ b/include/linux/i2o.h
@@ -18,8 +18,6 @@
#ifndef _I2O_H
#define _I2O_H
-#ifdef __KERNEL__ /* This file to be included by kernel only */
-
#include <linux/i2o-dev.h>
/* How many different OSM's are we allowing */
@@ -1255,5 +1253,4 @@
extern void i2o_dump_hrt(struct i2o_controller *c);
extern void i2o_debug_state(struct i2o_controller *c);
-#endif /* __KERNEL__ */
#endif /* _I2O_H */
diff --git a/include/linux/idr.h b/include/linux/idr.h
index 0edda41..9a2d762 100644
--- a/include/linux/idr.h
+++ b/include/linux/idr.h
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/bitops.h>
+#include <linux/init.h>
#if BITS_PER_LONG == 32
# define IDR_BITS 5
@@ -115,4 +116,6 @@
void ida_destroy(struct ida *ida);
void ida_init(struct ida *ida);
+void __init idr_init_cache(void);
+
#endif /* __IDR_H__ */
diff --git a/include/linux/if_macvlan.h b/include/linux/if_macvlan.h
index 0d9d7ea..5f200ba 100644
--- a/include/linux/if_macvlan.h
+++ b/include/linux/if_macvlan.h
@@ -1,9 +1,6 @@
#ifndef _LINUX_IF_MACVLAN_H
#define _LINUX_IF_MACVLAN_H
-#ifdef __KERNEL__
-
extern struct sk_buff *(*macvlan_handle_frame_hook)(struct sk_buff *);
-#endif /* __KERNEL__ */
#endif /* _LINUX_IF_MACVLAN_H */
diff --git a/include/linux/inet.h b/include/linux/inet.h
index 675a7db..1354080 100644
--- a/include/linux/inet.h
+++ b/include/linux/inet.h
@@ -42,11 +42,9 @@
#ifndef _LINUX_INET_H
#define _LINUX_INET_H
-#ifdef __KERNEL__
#include <linux/types.h>
extern __be32 in_aton(const char *str);
extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end);
extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end);
-#endif
#endif /* _LINUX_INET_H */
diff --git a/include/linux/init.h b/include/linux/init.h
index fb58c04..21d658c 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -147,6 +147,8 @@
void setup_arch(char **);
void prepare_namespace(void);
+extern void (*late_time_init)(void);
+
#endif
#ifndef MODULE
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index bf6b8a6..b24c287 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -1,7 +1,7 @@
#ifndef _LINUX__INIT_TASK_H
#define _LINUX__INIT_TASK_H
-#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/rcupdate.h>
#include <linux/irqflags.h>
#include <linux/utsname.h>
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index b5fef13..f1fc747 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -289,6 +289,7 @@
};
asmlinkage void do_softirq(void);
+asmlinkage void __do_softirq(void);
extern void open_softirq(int nr, void (*action)(struct softirq_action*), void *data);
extern void softirq_init(void);
#define __raise_softirq_irqoff(nr) do { or_softirq_pending(1UL << (nr)); } while (0)
diff --git a/include/linux/io.h b/include/linux/io.h
index e3b2dda..3a03a36 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -58,9 +58,9 @@
}
#endif
-void __iomem * devm_ioremap(struct device *dev, unsigned long offset,
+void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
unsigned long size);
-void __iomem * devm_ioremap_nocache(struct device *dev, unsigned long offset,
+void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
unsigned long size);
void devm_iounmap(struct device *dev, void __iomem *addr);
int check_signature(const volatile void __iomem *io_addr,
diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h
index e4451d1..ea6c18a 100644
--- a/include/linux/ipc_namespace.h
+++ b/include/linux/ipc_namespace.h
@@ -4,6 +4,17 @@
#include <linux/err.h>
#include <linux/idr.h>
#include <linux/rwsem.h>
+#include <linux/notifier.h>
+
+/*
+ * ipc namespace events
+ */
+#define IPCNS_MEMCHANGED 0x00000001 /* Notify lowmem size changed */
+#define IPCNS_CREATED 0x00000002 /* Notify new ipc namespace created */
+#define IPCNS_REMOVED 0x00000003 /* Notify ipc namespace removed */
+
+#define IPCNS_CALLBACK_PRI 0
+
struct ipc_ids {
int in_use;
@@ -30,15 +41,24 @@
size_t shm_ctlall;
int shm_ctlmni;
int shm_tot;
+
+ struct notifier_block ipcns_nb;
};
extern struct ipc_namespace init_ipc_ns;
+extern atomic_t nr_ipc_ns;
#ifdef CONFIG_SYSVIPC
#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
-#else
+
+extern int register_ipcns_notifier(struct ipc_namespace *);
+extern int cond_register_ipcns_notifier(struct ipc_namespace *);
+extern int unregister_ipcns_notifier(struct ipc_namespace *);
+extern int ipcns_notify(unsigned long);
+
+#else /* CONFIG_SYSVIPC */
#define INIT_IPC_NS(ns)
-#endif
+#endif /* CONFIG_SYSVIPC */
#if defined(CONFIG_SYSVIPC) && defined(CONFIG_IPC_NS)
extern void free_ipc_ns(struct kref *kref);
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index c5bd28b..7ebdb4f 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -64,7 +64,7 @@
* applications and another for userland applications. The
* capabilities are basically the same for both interface, although
* the interfaces are somewhat different. The stuff in the
- * #ifdef KERNEL below is the in-kernel interface. The userland
+ * #ifdef __KERNEL__ below is the in-kernel interface. The userland
* interface is defined later in the file. */
@@ -75,8 +75,7 @@
* work for sockets.
*/
#define IPMI_MAX_ADDR_SIZE 32
-struct ipmi_addr
-{
+struct ipmi_addr {
/* Try to take these from the "Channel Medium Type" table
in section 6.5 of the IPMI 1.5 manual. */
int addr_type;
@@ -90,8 +89,7 @@
* 0), or IPMC_BMC_CHANNEL if communicating directly with the BMC.
*/
#define IPMI_SYSTEM_INTERFACE_ADDR_TYPE 0x0c
-struct ipmi_system_interface_addr
-{
+struct ipmi_system_interface_addr {
int addr_type;
short channel;
unsigned char lun;
@@ -100,10 +98,9 @@
/* An IPMB Address. */
#define IPMI_IPMB_ADDR_TYPE 0x01
/* Used for broadcast get device id as described in section 17.9 of the
- IPMI 1.5 manual. */
+ IPMI 1.5 manual. */
#define IPMI_IPMB_BROADCAST_ADDR_TYPE 0x41
-struct ipmi_ipmb_addr
-{
+struct ipmi_ipmb_addr {
int addr_type;
short channel;
unsigned char slave_addr;
@@ -128,8 +125,7 @@
* message is a little weird, but this is required.
*/
#define IPMI_LAN_ADDR_TYPE 0x04
-struct ipmi_lan_addr
-{
+struct ipmi_lan_addr {
int addr_type;
short channel;
unsigned char privilege;
@@ -162,16 +158,14 @@
* byte of data in the response (as the spec shows the messages laid
* out).
*/
-struct ipmi_msg
-{
+struct ipmi_msg {
unsigned char netfn;
unsigned char cmd;
unsigned short data_len;
unsigned char __user *data;
};
-struct kernel_ipmi_msg
-{
+struct kernel_ipmi_msg {
unsigned char netfn;
unsigned char cmd;
unsigned short data_len;
@@ -239,12 +233,11 @@
* used after the message is delivered, so the upper layer may use the
* link to build a linked list, if it likes.
*/
-struct ipmi_recv_msg
-{
+struct ipmi_recv_msg {
struct list_head link;
/* The type of message as defined in the "Receive Types"
- defines above. */
+ defines above. */
int recv_type;
ipmi_user_t user;
@@ -271,9 +264,8 @@
/* Allocate and free the receive message. */
void ipmi_free_recv_msg(struct ipmi_recv_msg *msg);
-struct ipmi_user_hndl
-{
- /* Routine type to call when a message needs to be routed to
+struct ipmi_user_hndl {
+ /* Routine type to call when a message needs to be routed to
the upper layer. This will be called with some locks held,
the only IPMI routines that can be called are ipmi_request
and the alloc/free operations. The handler_data is the
@@ -368,9 +360,8 @@
* Poll the IPMI interface for the user. This causes the IPMI code to
* do an immediate check for information from the driver and handle
* anything that is immediately pending. This will not block in any
- * way. This is useful if you need to implement polling from the user
- * for things like modifying the watchdog timeout when a panic occurs
- * or disabling the watchdog timer on a reboot.
+ * way. This is useful if you need to spin waiting for something to
+ * happen in the IPMI driver.
*/
void ipmi_poll_interface(ipmi_user_t user);
@@ -422,12 +413,6 @@
int ipmi_set_maintenance_mode(ipmi_user_t user, int mode);
/*
- * Allow run-to-completion mode to be set for the interface of
- * a specific user.
- */
-void ipmi_user_set_run_to_completion(ipmi_user_t user, int val);
-
-/*
* When the user is created, it will not receive IPMI events by
* default. The user must set this to TRUE to get incoming events.
* The first user that sets this to TRUE will receive all events that
@@ -440,8 +425,7 @@
* every existing interface when a new watcher is registered with
* ipmi_smi_watcher_register().
*/
-struct ipmi_smi_watcher
-{
+struct ipmi_smi_watcher {
struct list_head link;
/* You must set the owner to the current module, if you are in
@@ -512,8 +496,7 @@
/* Messages sent to the interface are this format. */
-struct ipmi_req
-{
+struct ipmi_req {
unsigned char __user *addr; /* Address to send the message to. */
unsigned int addr_len;
@@ -538,12 +521,11 @@
/* Messages sent to the interface with timing parameters are this
format. */
-struct ipmi_req_settime
-{
+struct ipmi_req_settime {
struct ipmi_req req;
/* See ipmi_request_settime() above for details on these
- values. */
+ values. */
int retries;
unsigned int retry_time_ms;
};
@@ -560,8 +542,7 @@
struct ipmi_req_settime)
/* Messages received from the interface are this format. */
-struct ipmi_recv
-{
+struct ipmi_recv {
int recv_type; /* Is this a command, response or an
asyncronous event. */
@@ -607,13 +588,12 @@
struct ipmi_recv)
/* Register to get commands from other entities on this interface. */
-struct ipmi_cmdspec
-{
+struct ipmi_cmdspec {
unsigned char netfn;
unsigned char cmd;
};
-/*
+/*
* Register to receive a specific command. error values:
* - EFAULT - an address supplied was invalid.
* - EBUSY - The netfn/cmd supplied was already in use.
@@ -636,8 +616,7 @@
* else. The chans field is a bitmask, (1 << channel) for each channel.
* It may be IPMI_CHAN_ALL for all channels.
*/
-struct ipmi_cmdspec_chans
-{
+struct ipmi_cmdspec_chans {
unsigned int netfn;
unsigned int cmd;
unsigned int chans;
@@ -659,7 +638,7 @@
#define IPMICTL_UNREGISTER_FOR_CMD_CHANS _IOR(IPMI_IOC_MAGIC, 29, \
struct ipmi_cmdspec_chans)
-/*
+/*
* Set whether this interface receives events. Note that the first
* user registered for events will get all pending events for the
* interface. error values:
@@ -675,15 +654,18 @@
* 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
-{
+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)
+#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)
@@ -694,8 +676,7 @@
* Get/set the default timing values for an interface. You shouldn't
* generally mess with these.
*/
-struct ipmi_timing_parms
-{
+struct ipmi_timing_parms {
int retries;
unsigned int retry_time_ms;
};
diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h
index 6e8cec5..62b7366 100644
--- a/include/linux/ipmi_smi.h
+++ b/include/linux/ipmi_smi.h
@@ -60,8 +60,7 @@
* asynchronous data and messages and request them from the
* interface.
*/
-struct ipmi_smi_msg
-{
+struct ipmi_smi_msg {
struct list_head link;
long msgid;
@@ -74,12 +73,11 @@
unsigned char rsp[IPMI_MAX_MSG_LENGTH];
/* Will be called when the system is done with the message
- (presumably to free it). */
+ (presumably to free it). */
void (*done)(struct ipmi_smi_msg *msg);
};
-struct ipmi_smi_handlers
-{
+struct ipmi_smi_handlers {
struct module *owner;
/* The low-level interface cannot start sending messages to
@@ -231,7 +229,7 @@
directory for this interface. Note that the entry will
automatically be dstroyed when the interface is destroyed. */
int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
- read_proc_t *read_proc, write_proc_t *write_proc,
+ read_proc_t *read_proc,
void *data, struct module *owner);
#endif /* __LINUX_IPMI_SMI_H */
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 1883a85..552e0ec 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -61,6 +61,7 @@
#define IRQ_WAKEUP 0x00100000 /* IRQ triggers system wakeup */
#define IRQ_MOVE_PENDING 0x00200000 /* need to re-target IRQ destination */
#define IRQ_NO_BALANCING 0x00400000 /* IRQ is excluded from balancing */
+#define IRQ_SPURIOUS_DISABLED 0x00800000 /* IRQ was disabled by the spurious trap */
#ifdef CONFIG_IRQ_PER_CPU
# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU)
diff --git a/include/linux/isapnp.h b/include/linux/isapnp.h
index 1e8728a..cd5a269 100644
--- a/include/linux/isapnp.h
+++ b/include/linux/isapnp.h
@@ -26,16 +26,6 @@
#include <linux/pnp.h>
/*
- * Configuration registers (TODO: change by specification)
- */
-
-#define ISAPNP_CFG_ACTIVATE 0x30 /* byte */
-#define ISAPNP_CFG_MEM 0x40 /* 4 * dword */
-#define ISAPNP_CFG_PORT 0x60 /* 8 * word */
-#define ISAPNP_CFG_IRQ 0x70 /* 2 * word */
-#define ISAPNP_CFG_DMA 0x74 /* 2 * byte */
-
-/*
*
*/
diff --git a/include/linux/isicom.h b/include/linux/isicom.h
index 8f4c717..bbd4219 100644
--- a/include/linux/isicom.h
+++ b/include/linux/isicom.h
@@ -1,11 +1,6 @@
#ifndef _LINUX_ISICOM_H
#define _LINUX_ISICOM_H
-/*#define ISICOM_DEBUG*/
-/*#define ISICOM_DEBUG_DTR_RTS*/
-
-#ifdef __KERNEL__
-
#define YES 1
#define NO 0
@@ -85,6 +80,4 @@
#define ISI_TXOK 0x0001
-#endif /* __KERNEL__ */
-
#endif /* ISICOM_H */
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index 33ef710..abb6ac6 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -1,7 +1,7 @@
#ifndef _LINUX_JIFFIES_H
#define _LINUX_JIFFIES_H
-#include <linux/calc64.h>
+#include <linux/math64.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/time.h>
diff --git a/include/linux/kbuild.h b/include/linux/kbuild.h
new file mode 100644
index 0000000..22a7219
--- /dev/null
+++ b/include/linux/kbuild.h
@@ -0,0 +1,15 @@
+#ifndef __LINUX_KBUILD_H
+#define __LINUX_KBUILD_H
+
+#define DEFINE(sym, val) \
+ asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+#define OFFSET(sym, str, mem) \
+ DEFINE(sym, offsetof(struct str, mem))
+
+#define COMMENT(x) \
+ asm volatile("\n->#" x)
+
+#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index cd6d02c..4d46e29 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -20,6 +20,9 @@
extern const char linux_banner[];
extern const char linux_proc_banner[];
+#define USHORT_MAX ((u16)(~0U))
+#define SHORT_MAX ((s16)(USHORT_MAX>>1))
+#define SHORT_MIN (-SHORT_MAX - 1)
#define INT_MAX ((int)(~0U>>1))
#define INT_MIN (-INT_MAX - 1)
#define UINT_MAX (~0U)
@@ -188,6 +191,7 @@
extern int printk_ratelimit_jiffies;
extern int printk_ratelimit_burst;
extern int printk_ratelimit(void);
+extern int __ratelimit(int ratelimit_jiffies, int ratelimit_burst);
extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst);
extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
unsigned int interval_msec);
@@ -255,6 +259,7 @@
#define TAINT_USER (1<<6)
#define TAINT_DIE (1<<7)
#define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8)
+#define TAINT_WARN (1<<9)
extern void dump_stack(void) __cold;
@@ -333,33 +338,90 @@
#endif /* __LITTLE_ENDIAN */
/*
- * min()/max() macros that also do
+ * min()/max()/clamp() macros that also do
* strict type-checking.. See the
* "unnecessary" pointer comparison.
*/
-#define min(x,y) ({ \
- typeof(x) _x = (x); \
- typeof(y) _y = (y); \
- (void) (&_x == &_y); \
- _x < _y ? _x : _y; })
+#define min(x, y) ({ \
+ typeof(x) _min1 = (x); \
+ typeof(y) _min2 = (y); \
+ (void) (&_min1 == &_min2); \
+ _min1 < _min2 ? _min1 : _min2; })
-#define max(x,y) ({ \
- typeof(x) _x = (x); \
- typeof(y) _y = (y); \
- (void) (&_x == &_y); \
- _x > _y ? _x : _y; })
+#define max(x, y) ({ \
+ typeof(x) _max1 = (x); \
+ typeof(y) _max2 = (y); \
+ (void) (&_max1 == &_max2); \
+ _max1 > _max2 ? _max1 : _max2; })
+
+/**
+ * clamp - return a value clamped to a given range with strict typechecking
+ * @val: current value
+ * @min: minimum allowable value
+ * @max: maximum allowable value
+ *
+ * This macro does strict typechecking of min/max to make sure they are of the
+ * same type as val. See the unnecessary pointer comparisons.
+ */
+#define clamp(val, min, max) ({ \
+ typeof(val) __val = (val); \
+ typeof(min) __min = (min); \
+ typeof(max) __max = (max); \
+ (void) (&__val == &__min); \
+ (void) (&__val == &__max); \
+ __val = __val < __min ? __min: __val; \
+ __val > __max ? __max: __val; })
/*
* ..and if you can't take the strict
* types, you can specify one yourself.
*
- * Or not use min/max at all, of course.
+ * Or not use min/max/clamp at all, of course.
*/
-#define min_t(type,x,y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-#define max_t(type,x,y) \
- ({ type __x = (x); type __y = (y); __x > __y ? __x: __y; })
+#define min_t(type, x, y) ({ \
+ type __min1 = (x); \
+ type __min2 = (y); \
+ __min1 < __min2 ? __min1: __min2; })
+#define max_t(type, x, y) ({ \
+ type __max1 = (x); \
+ type __max2 = (y); \
+ __max1 > __max2 ? __max1: __max2; })
+
+/**
+ * clamp_t - return a value clamped to a given range using a given type
+ * @type: the type of variable to use
+ * @val: current value
+ * @min: minimum allowable value
+ * @max: maximum allowable value
+ *
+ * This macro does no typechecking and uses temporary variables of type
+ * 'type' to make all the comparisons.
+ */
+#define clamp_t(type, val, min, max) ({ \
+ type __val = (val); \
+ type __min = (min); \
+ type __max = (max); \
+ __val = __val < __min ? __min: __val; \
+ __val > __max ? __max: __val; })
+
+/**
+ * clamp_val - return a value clamped to a given range using val's type
+ * @val: current value
+ * @min: minimum allowable value
+ * @max: maximum allowable value
+ *
+ * This macro does no typechecking and uses temporary variables of whatever
+ * type the input argument 'val' is. This is useful when val is an unsigned
+ * type and min and max are literals that will otherwise be assigned a signed
+ * integer type.
+ */
+#define clamp_val(val, min, max) ({ \
+ typeof(val) __val = (val); \
+ typeof(val) __min = (min); \
+ typeof(val) __max = (max); \
+ __val = __val < __min ? __min: __val; \
+ __val > __max ? __max: __val; })
/**
* container_of - cast a member of a structure out to the containing structure
diff --git a/include/linux/key.h b/include/linux/key.h
index a70b8a8..c45c962 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -19,6 +19,7 @@
#include <linux/list.h>
#include <linux/rbtree.h>
#include <linux/rcupdate.h>
+#include <linux/sysctl.h>
#include <asm/atomic.h>
#ifdef __KERNEL__
@@ -67,6 +68,8 @@
#define KEY_OTH_SETATTR 0x00000020
#define KEY_OTH_ALL 0x0000003f
+#define KEY_PERM_UNDEF 0xffffffff
+
struct seq_file;
struct user_struct;
struct signal_struct;
@@ -208,16 +211,19 @@
extern struct key *request_key_with_auxdata(struct key_type *type,
const char *description,
- const char *callout_info,
+ const void *callout_info,
+ size_t callout_len,
void *aux);
extern struct key *request_key_async(struct key_type *type,
const char *description,
- const char *callout_info);
+ const void *callout_info,
+ size_t callout_len);
extern struct key *request_key_async_with_auxdata(struct key_type *type,
const char *description,
- const char *callout_info,
+ const void *callout_info,
+ size_t callout_len,
void *aux);
extern int wait_for_key_construction(struct key *key, bool intr);
@@ -229,6 +235,7 @@
const char *description,
const void *payload,
size_t plen,
+ key_perm_t perm,
unsigned long flags);
extern int key_update(key_ref_t key,
@@ -257,14 +264,18 @@
extern struct key *key_lookup(key_serial_t id);
-#define key_serial(key) ((key) ? (key)->serial : 0)
+static inline key_serial_t key_serial(struct key *key)
+{
+ return key ? key->serial : 0;
+}
+
+#ifdef CONFIG_SYSCTL
+extern ctl_table key_sysctls[];
+#endif
/*
* the userspace interface
*/
-extern struct key root_user_keyring, root_session_keyring;
-extern int alloc_uid_keyring(struct user_struct *user,
- struct task_struct *ctx);
extern void switch_uid_keyring(struct user_struct *new_user);
extern int copy_keys(unsigned long clone_flags, struct task_struct *tsk);
extern int copy_thread_group_keys(struct task_struct *tsk);
@@ -293,7 +304,6 @@
#define make_key_ref(k, p) ({ NULL; })
#define key_ref_to_ptr(k) ({ NULL; })
#define is_key_possessed(k) 0
-#define alloc_uid_keyring(u,c) 0
#define switch_uid_keyring(u) do { } while(0)
#define __install_session_keyring(t, k) ({ NULL; })
#define copy_keys(f,t) 0
@@ -306,10 +316,6 @@
#define key_fsgid_changed(t) do { } while(0)
#define key_init() do { } while(0)
-/* Initial keyrings */
-extern struct key root_user_keyring;
-extern struct key root_session_keyring;
-
#endif /* CONFIG_KEYS */
#endif /* __KERNEL__ */
#endif /* _LINUX_KEY_H */
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h
index 3365945..656ee6b 100644
--- a/include/linux/keyctl.h
+++ b/include/linux/keyctl.h
@@ -49,5 +49,6 @@
#define KEYCTL_SET_REQKEY_KEYRING 14 /* set default request-key keyring */
#define KEYCTL_SET_TIMEOUT 15 /* set key timeout */
#define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */
+#define KEYCTL_GET_SECURITY 17 /* get key security label */
#endif /* _LINUX_KEYCTL_H */
diff --git a/include/linux/kfifo.h b/include/linux/kfifo.h
index 404f446..29f62e1 100644
--- a/include/linux/kfifo.h
+++ b/include/linux/kfifo.h
@@ -21,8 +21,6 @@
#ifndef _LINUX_KFIFO_H
#define _LINUX_KFIFO_H
-#ifdef __KERNEL__
-
#include <linux/kernel.h>
#include <linux/spinlock.h>
@@ -151,7 +149,4 @@
return ret;
}
-#else
-#warning "don't include kernel headers in userspace"
-#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/klist.h b/include/linux/klist.h
index 7407125..06c338e 100644
--- a/include/linux/klist.h
+++ b/include/linux/klist.h
@@ -25,37 +25,47 @@
void (*put)(struct klist_node *);
};
+#define KLIST_INIT(_name, _get, _put) \
+ { .k_lock = __SPIN_LOCK_UNLOCKED(_name.k_lock), \
+ .k_list = LIST_HEAD_INIT(_name.k_list), \
+ .get = _get, \
+ .put = _put, }
-extern void klist_init(struct klist * k, void (*get)(struct klist_node *),
+#define DEFINE_KLIST(_name, _get, _put) \
+ struct klist _name = KLIST_INIT(_name, _get, _put)
+
+extern void klist_init(struct klist *k, void (*get)(struct klist_node *),
void (*put)(struct klist_node *));
struct klist_node {
- struct klist * n_klist;
+ struct klist *n_klist;
struct list_head n_node;
struct kref n_ref;
struct completion n_removed;
};
-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_add_tail(struct klist_node *n, struct klist *k);
+extern void klist_add_head(struct klist_node *n, struct klist *k);
+extern void klist_add_after(struct klist_node *n, struct klist_node *pos);
+extern void klist_add_before(struct klist_node *n, struct klist_node *pos);
-extern void klist_del(struct klist_node * n);
-extern void klist_remove(struct klist_node * n);
+extern void klist_del(struct klist_node *n);
+extern void klist_remove(struct klist_node *n);
-extern int klist_node_attached(struct klist_node * n);
+extern int klist_node_attached(struct klist_node *n);
struct klist_iter {
- struct klist * i_klist;
- struct list_head * i_head;
- struct klist_node * i_cur;
+ struct klist *i_klist;
+ struct list_head *i_head;
+ struct klist_node *i_cur;
};
-extern void klist_iter_init(struct klist * k, struct klist_iter * i);
-extern void klist_iter_init_node(struct klist * k, struct klist_iter * i,
- struct klist_node * n);
-extern void klist_iter_exit(struct klist_iter * i);
-extern struct klist_node * klist_next(struct klist_iter * i);
+extern void klist_iter_init(struct klist *k, struct klist_iter *i);
+extern void klist_iter_init_node(struct klist *k, struct klist_iter *i,
+ struct klist_node *n);
+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/kobj_map.h b/include/linux/kobj_map.h
index bafe178..73717ed 100644
--- a/include/linux/kobj_map.h
+++ b/include/linux/kobj_map.h
@@ -1,5 +1,3 @@
-#ifdef __KERNEL__
-
#include <linux/mutex.h>
typedef struct kobject *kobj_probe_t(dev_t, int *, void *);
@@ -10,5 +8,3 @@
void kobj_unmap(struct kobj_map *, dev_t, unsigned long);
struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *);
struct kobj_map *kobj_map_init(kobj_probe_t *, struct mutex *);
-
-#endif
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index caa3f41..39e709f 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -16,8 +16,6 @@
#ifndef _KOBJECT_H_
#define _KOBJECT_H_
-#ifdef __KERNEL__
-
#include <linux/types.h>
#include <linux/list.h>
#include <linux/sysfs.h>
@@ -224,5 +222,4 @@
{ return -EINVAL; }
#endif
-#endif /* __KERNEL__ */
#endif /* _KOBJECT_H_ */
diff --git a/include/linux/kref.h b/include/linux/kref.h
index 5d18563..0cef6ba 100644
--- a/include/linux/kref.h
+++ b/include/linux/kref.h
@@ -15,8 +15,6 @@
#ifndef _KREF_H_
#define _KREF_H_
-#ifdef __KERNEL__
-
#include <linux/types.h>
#include <asm/atomic.h>
@@ -29,5 +27,4 @@
void kref_get(struct kref *kref);
int kref_put(struct kref *kref, void (*release) (struct kref *kref));
-#endif /* __KERNEL__ */
#endif /* _KREF_H_ */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 395a523..d1dfe87 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -548,11 +548,6 @@
u64 n_sectors; /* size of device, if ATA */
unsigned int class; /* ATA_DEV_xxx */
- union {
- u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
- u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
- };
-
u8 pio_mode;
u8 dma_mode;
u8 xfer_mode;
@@ -574,8 +569,13 @@
u16 sectors; /* Number of sectors per track */
/* error history */
- struct ata_ering ering;
int spdn_cnt;
+ struct ata_ering ering;
+
+ union {
+ u16 id[ATA_ID_WORDS]; /* IDENTIFY xxx DEVICE data */
+ u32 gscr[SATA_PMP_GSCR_DWORDS]; /* PMP GSCR block */
+ };
};
/* Offset into struct ata_device. Fields above it are maintained
diff --git a/include/linux/list.h b/include/linux/list.h
index b4a939b..08cf4f6 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -1,8 +1,6 @@
#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H
-#ifdef __KERNEL__
-
#include <linux/stddef.h>
#include <linux/poison.h>
#include <linux/prefetch.h>
@@ -328,7 +326,7 @@
return !list_empty(head) && (head->next == head->prev);
}
-static inline void __list_splice(struct list_head *list,
+static inline void __list_splice(const struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
@@ -347,7 +345,8 @@
* @list: the new list to add.
* @head: the place to add it in the first list.
*/
-static inline void list_splice(struct list_head *list, struct list_head *head)
+static inline void list_splice(const struct list_head *list,
+ struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
@@ -982,7 +981,4 @@
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
pos = rcu_dereference(pos->next))
-#else
-#warning "don't include kernel headers in userspace"
-#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/math64.h b/include/linux/math64.h
new file mode 100644
index 0000000..c1a5f81
--- /dev/null
+++ b/include/linux/math64.h
@@ -0,0 +1,84 @@
+#ifndef _LINUX_MATH64_H
+#define _LINUX_MATH64_H
+
+#include <linux/types.h>
+#include <asm/div64.h>
+
+#if BITS_PER_LONG == 64
+
+/**
+ * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder
+ *
+ * This is commonly provided by 32bit archs to provide an optimized 64bit
+ * divide.
+ */
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+ *remainder = dividend % divisor;
+ return dividend / divisor;
+}
+
+/**
+ * div_s64_rem - signed 64bit divide with 32bit divisor with remainder
+ */
+static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
+{
+ *remainder = dividend % divisor;
+ return dividend / divisor;
+}
+
+/**
+ * div64_u64 - unsigned 64bit divide with 64bit divisor
+ */
+static inline u64 div64_u64(u64 dividend, u64 divisor)
+{
+ return dividend / divisor;
+}
+
+#elif BITS_PER_LONG == 32
+
+#ifndef div_u64_rem
+static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder)
+{
+ *remainder = do_div(dividend, divisor);
+ return dividend;
+}
+#endif
+
+#ifndef div_s64_rem
+extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder);
+#endif
+
+#ifndef div64_u64
+extern u64 div64_u64(u64 dividend, u64 divisor);
+#endif
+
+#endif /* BITS_PER_LONG */
+
+/**
+ * div_u64 - unsigned 64bit divide with 32bit divisor
+ *
+ * This is the most common 64bit divide and should be used if possible,
+ * as many 32bit archs can optimize this variant better than a full 64bit
+ * divide.
+ */
+#ifndef div_u64
+static inline u64 div_u64(u64 dividend, u32 divisor)
+{
+ u32 remainder;
+ return div_u64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+/**
+ * div_s64 - signed 64bit divide with 32bit divisor
+ */
+#ifndef div_s64
+static inline s64 div_s64(s64 dividend, s32 divisor)
+{
+ s32 remainder;
+ return div_s64_rem(dividend, divisor, &remainder);
+}
+#endif
+
+#endif /* _LINUX_MATH64_H */
diff --git a/include/linux/mca-legacy.h b/include/linux/mca-legacy.h
index f2bb770..7a3aea8 100644
--- a/include/linux/mca-legacy.h
+++ b/include/linux/mca-legacy.h
@@ -34,7 +34,6 @@
extern int mca_find_adapter(int id, int start);
extern int mca_find_unused_adapter(int id, int start);
-extern int mca_is_adapter_used(int slot);
extern int mca_mark_as_used(int slot);
extern void mca_mark_as_unused(int slot);
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 8b1c429..e660877 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -27,9 +27,6 @@
#ifdef CONFIG_CGROUP_MEM_RES_CTLR
-extern void mm_init_cgroup(struct mm_struct *mm, struct task_struct *p);
-extern void mm_free_cgroup(struct mm_struct *mm);
-
#define page_reset_bad_cgroup(page) ((page)->page_cgroup = 0)
extern struct page_cgroup *page_get_page_cgroup(struct page *page);
@@ -48,8 +45,10 @@
extern void mem_cgroup_out_of_memory(struct mem_cgroup *mem, gfp_t gfp_mask);
int task_in_mem_cgroup(struct task_struct *task, const struct mem_cgroup *mem);
+extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
+
#define mm_match_cgroup(mm, cgroup) \
- ((cgroup) == rcu_dereference((mm)->mem_cgroup))
+ ((cgroup) == mem_cgroup_from_task((mm)->owner))
extern int mem_cgroup_prepare_migration(struct page *page);
extern void mem_cgroup_end_migration(struct page *page);
@@ -73,15 +72,6 @@
struct zone *zone, int priority);
#else /* CONFIG_CGROUP_MEM_RES_CTLR */
-static inline void mm_init_cgroup(struct mm_struct *mm,
- struct task_struct *p)
-{
-}
-
-static inline void mm_free_cgroup(struct mm_struct *mm)
-{
-}
-
static inline void page_reset_bad_cgroup(struct page *page)
{
}
diff --git a/include/linux/memory.h b/include/linux/memory.h
index f80e0e3..2f5f8a5 100644
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -53,6 +53,13 @@
struct notifier_block;
struct mem_section;
+/*
+ * Priorities for the hotplug memory callback routines (stored in decreasing
+ * order in the callback chain)
+ */
+#define SLAB_CALLBACK_PRI 1
+#define IPC_CALLBACK_PRI 10
+
#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE
static inline int memory_dev_init(void)
{
diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h
index 9fa1a80..a744383 100644
--- a/include/linux/mlx4/device.h
+++ b/include/linux/mlx4/device.h
@@ -382,7 +382,8 @@
int size);
int mlx4_cq_alloc(struct mlx4_dev *dev, int nent, struct mlx4_mtt *mtt,
- struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq);
+ struct mlx4_uar *uar, u64 db_rec, struct mlx4_cq *cq,
+ int collapsed);
void mlx4_cq_free(struct mlx4_dev *dev, struct mlx4_cq *cq);
int mlx4_qp_alloc(struct mlx4_dev *dev, int sqpn, struct mlx4_qp *qp);
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 8b7f4a5..c31a9cd 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1066,6 +1066,19 @@
extern struct vm_area_struct *copy_vma(struct vm_area_struct **,
unsigned long addr, unsigned long len, pgoff_t pgoff);
extern void exit_mmap(struct mm_struct *);
+
+#ifdef CONFIG_PROC_FS
+/* From fs/proc/base.c. callers must _not_ hold the mm's exe_file_lock */
+extern void added_exe_file_vma(struct mm_struct *mm);
+extern void removed_exe_file_vma(struct mm_struct *mm);
+#else
+static inline void added_exe_file_vma(struct mm_struct *mm)
+{}
+
+static inline void removed_exe_file_vma(struct mm_struct *mm)
+{}
+#endif /* CONFIG_PROC_FS */
+
extern int may_expand_vm(struct mm_struct *mm, unsigned long npages);
extern int install_special_mapping(struct mm_struct *mm,
unsigned long addr, unsigned long len,
@@ -1230,8 +1243,6 @@
void __user *, size_t *, loff_t *);
unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
unsigned long lru_pages);
-void drop_pagecache(void);
-void drop_slab(void);
#ifndef CONFIG_MMU
#define randomize_va_space 0
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index e2bae8d..eb7c16c 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -225,8 +225,15 @@
/* aio bits */
rwlock_t ioctx_list_lock; /* aio lock */
struct kioctx *ioctx_list;
-#ifdef CONFIG_CGROUP_MEM_RES_CTLR
- struct mem_cgroup *mem_cgroup;
+#ifdef CONFIG_MM_OWNER
+ struct task_struct *owner; /* The thread group leader that */
+ /* owns the mm_struct. */
+#endif
+
+#ifdef CONFIG_PROC_FS
+ /* store ref to file /proc/<pid>/exe symlink points to */
+ struct file *exe_file;
+ unsigned long num_exe_file_vmas;
#endif
};
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index aad9800..c463cd8 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -1,7 +1,6 @@
#ifndef _LINUX_MMZONE_H
#define _LINUX_MMZONE_H
-#ifdef __KERNEL__
#ifndef __ASSEMBLY__
#ifndef __GENERATING_BOUNDS_H
@@ -97,6 +96,7 @@
NR_UNSTABLE_NFS, /* NFS unstable pages */
NR_BOUNCE,
NR_VMSCAN_WRITE,
+ NR_WRITEBACK_TEMP, /* Writeback using temporary buffers */
#ifdef CONFIG_NUMA
NUMA_HIT, /* allocated in intended node */
NUMA_MISS, /* allocated in non intended node */
@@ -1004,5 +1004,4 @@
#endif /* !__GENERATING_BOUNDS.H */
#endif /* !__ASSEMBLY__ */
-#endif /* __KERNEL__ */
#endif /* _LINUX_MMZONE_H */
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 139d49d..d73ecea 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -368,4 +368,15 @@
};
#define VIRTIO_DEV_ANY_ID 0xffffffff
+/* i2c */
+
+#define I2C_NAME_SIZE 20
+#define I2C_MODULE_PREFIX "i2c:"
+
+struct i2c_device_id {
+ char name[I2C_NAME_SIZE];
+ kernel_ulong_t driver_data; /* Data private to the driver */
+};
+
+
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/module.h b/include/linux/module.h
index 819c4e8..3e03b1a 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -190,7 +190,7 @@
extern typeof(sym) sym; \
__CRC_SYMBOL(sym, sec) \
static const char __kstrtab_##sym[] \
- __attribute__((section("__ksymtab_strings"))) \
+ __attribute__((section("__ksymtab_strings"), aligned(1))) \
= MODULE_SYMBOL_PREFIX #sym; \
static const struct kernel_symbol __ksymtab_##sym \
__used \
@@ -229,23 +229,6 @@
MODULE_STATE_GOING,
};
-/* Similar stuff for section attributes. */
-struct module_sect_attr
-{
- struct module_attribute mattr;
- char *name;
- unsigned long address;
-};
-
-struct module_sect_attrs
-{
- struct attribute_group grp;
- int nsections;
- struct module_sect_attr attrs[0];
-};
-
-struct module_param_attrs;
-
struct module
{
enum module_state state;
diff --git a/include/linux/mount.h b/include/linux/mount.h
index b4836d5..4374d1a 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -10,7 +10,6 @@
*/
#ifndef _LINUX_MOUNT_H
#define _LINUX_MOUNT_H
-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/list.h>
@@ -114,5 +113,4 @@
extern spinlock_t vfsmount_lock;
extern dev_t name_to_dev_t(char *name);
-#endif
#endif /* _LINUX_MOUNT_H */
diff --git a/include/linux/msg.h b/include/linux/msg.h
index 10a3d5a..6f3b8e7 100644
--- a/include/linux/msg.h
+++ b/include/linux/msg.h
@@ -49,16 +49,26 @@
unsigned short msgseg;
};
+/*
+ * Scaling factor to compute msgmni:
+ * the memory dedicated to msg queues (msgmni * msgmnb) should occupy
+ * at most 1/MSG_MEM_SCALE of the lowmem (see the formula in ipc/msg.c):
+ * up to 8MB : msgmni = 16 (MSGMNI)
+ * 4 GB : msgmni = 8K
+ * more than 16 GB : msgmni = 32K (IPCMNI)
+ */
+#define MSG_MEM_SCALE 32
+
#define MSGMNI 16 /* <= IPCMNI */ /* max # of msg queue identifiers */
#define MSGMAX 8192 /* <= INT_MAX */ /* max size of message (bytes) */
#define MSGMNB 16384 /* <= INT_MAX */ /* default max size of a message queue */
/* unused */
-#define MSGPOOL (MSGMNI*MSGMNB/1024) /* size in kilobytes of message pool */
+#define MSGPOOL (MSGMNI * MSGMNB) /* size in bytes of message pool */
#define MSGTQL MSGMNB /* number of system message headers */
#define MSGMAP MSGMNB /* number of entries in message map */
#define MSGSSZ 16 /* message segment size */
-#define __MSGSEG ((MSGPOOL*1024)/ MSGSSZ) /* max no. of segments */
+#define __MSGSEG (MSGPOOL / MSGSSZ) /* max no. of segments */
#define MSGSEG (__MSGSEG <= 0xffff ? __MSGSEG : 0xffff)
#ifdef __KERNEL__
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 94bb46d..8f29392 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -22,6 +22,7 @@
__u8 masked : 1;
__u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */
__u8 pos; /* Location of the msi capability */
+ __u32 maskbits_mask; /* mask bits mask */
__u16 entry_nr; /* specific enabled entry */
unsigned default_irq; /* default pre-assigned irq */
}msi_attrib;
diff --git a/include/linux/mtd/jedec.h b/include/linux/mtd/jedec.h
deleted file mode 100644
index 9006feb..0000000
--- a/include/linux/mtd/jedec.h
+++ /dev/null
@@ -1,66 +0,0 @@
-
-/* JEDEC Flash Interface.
- * This is an older type of interface for self programming flash. It is
- * commonly use in older AMD chips and is obsolete compared with CFI.
- * It is called JEDEC because the JEDEC association distributes the ID codes
- * for the chips.
- *
- * See the AMD flash databook for information on how to operate the interface.
- *
- * $Id: jedec.h,v 1.4 2005/11/07 11:14:54 gleixner Exp $
- */
-
-#ifndef __LINUX_MTD_JEDEC_H__
-#define __LINUX_MTD_JEDEC_H__
-
-#include <linux/types.h>
-
-#define MAX_JEDEC_CHIPS 16
-
-// Listing of all supported chips and their information
-struct JEDECTable
-{
- __u16 jedec;
- char *name;
- unsigned long size;
- unsigned long sectorsize;
- __u32 capabilities;
-};
-
-// JEDEC being 0 is the end of the chip array
-struct jedec_flash_chip
-{
- __u16 jedec;
- unsigned long size;
- unsigned long sectorsize;
-
- // *(__u8*)(base + (adder << addrshift)) = data << datashift
- // Address size = size << addrshift
- unsigned long base; // Byte 0 of the flash, will be unaligned
- unsigned int datashift; // Useful for 32bit/16bit accesses
- unsigned int addrshift;
- unsigned long offset; // linerized start. base==offset for unbanked, uninterleaved flash
-
- __u32 capabilities;
-
- // These markers are filled in by the flash_chip_scan function
- unsigned long start;
- unsigned long length;
-};
-
-struct jedec_private
-{
- unsigned long size; // Total size of all the devices
-
- /* Bank handling. If sum(bank_fill) == size then this is linear flash.
- Otherwise the mapping has holes in it. bank_fill may be used to
- find the holes, but in the common symetric case
- bank_fill[0] == bank_fill[*], thus addresses may be computed
- mathmatically. bank_fill must be powers of two */
- unsigned is_banked;
- unsigned long bank_fill[MAX_JEDEC_CHIPS];
-
- struct jedec_flash_chip chips[MAX_JEDEC_CHIPS];
-};
-
-#endif
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 0a13bb3..245f909 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -143,10 +143,12 @@
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */
- int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
+ /* phys is optional and may be set to NULL */
+ int (*point) (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys);
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
- void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len);
+ void (*unpoint) (struct mtd_info *mtd, loff_t from, size_t len);
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
diff --git a/include/linux/mtd/pmc551.h b/include/linux/mtd/pmc551.h
index a7f6d20..5cc070c 100644
--- a/include/linux/mtd/pmc551.h
+++ b/include/linux/mtd/pmc551.h
@@ -36,8 +36,9 @@
* Function Prototypes
*/
static int pmc551_erase(struct mtd_info *, struct erase_info *);
-static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t);
-static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
+static void pmc551_unpoint(struct mtd_info *, loff_t, size_t);
+static int pmc551_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, void **virt, resource_size_t *phys);
static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index 9865720..155719d 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -56,9 +56,11 @@
int magic;
spinlock_t queue_lock;
- struct list_head queue_head;/* Requests are added here... */
+ struct list_head queue_head; /* Requests waiting result */
struct request *active_req;
wait_queue_head_t active_wq;
+ struct list_head waiting_queue; /* Requests to be sent */
+ wait_queue_head_t waiting_wq;
struct mutex tx_lock;
struct gendisk *disk;
@@ -86,11 +88,7 @@
char handle[8];
__be64 from;
__be32 len;
-}
-#ifdef __GNUC__
- __attribute__ ((packed))
-#endif
-;
+} __attribute__ ((packed));
/*
* This is the reply packet that nbd-server sends back to the client after
diff --git a/include/linux/ncp_fs_i.h b/include/linux/ncp_fs_i.h
index bdb4c8a..4b0bec4 100644
--- a/include/linux/ncp_fs_i.h
+++ b/include/linux/ncp_fs_i.h
@@ -8,8 +8,6 @@
#ifndef _LINUX_NCP_FS_I
#define _LINUX_NCP_FS_I
-#ifdef __KERNEL__
-
/*
* This is the ncpfs part of the inode structure. This must contain
* all the information we need to work with an inode after creation.
@@ -28,6 +26,4 @@
struct inode vfs_inode;
};
-#endif /* __KERNEL__ */
-
#endif /* _LINUX_NCP_FS_I */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index fb0713b..bec1062 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -166,6 +166,7 @@
__u32 dst_group;
kernel_cap_t eff_cap;
__u32 loginuid; /* Login (audit) uid */
+ __u32 sessionid; /* Session id (audit) */
__u32 sid; /* SELinux security id */
};
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 20dfed5..0ff6224 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -121,6 +121,10 @@
extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
struct notifier_block *nb);
+extern int blocking_notifier_chain_cond_register(
+ struct blocking_notifier_head *nh,
+ struct notifier_block *nb);
+
extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
struct notifier_block *nb);
extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
diff --git a/include/linux/of_device.h b/include/linux/of_device.h
index 6dc1195..afe3382 100644
--- a/include/linux/of_device.h
+++ b/include/linux/of_device.h
@@ -1,6 +1,5 @@
#ifndef _LINUX_OF_DEVICE_H
#define _LINUX_OF_DEVICE_H
-#ifdef __KERNEL__
#include <linux/device.h>
#include <linux/of.h>
@@ -25,5 +24,4 @@
of_release_dev(&dev->dev);
}
-#endif /* __KERNEL__ */
#endif /* _LINUX_OF_DEVICE_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 2924913..96acd0d 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -20,8 +20,6 @@
/* Include the pci register defines */
#include <linux/pci_regs.h>
-struct pci_vpd;
-
/*
* The PCI interface treats multi-function devices as independent
* devices. The slot/function address of each device is encoded
@@ -131,6 +129,8 @@
};
struct pcie_link_state;
+struct pci_vpd;
+
/*
* The pci_dev structure is used to describe PCI devices.
*/
@@ -254,7 +254,7 @@
#define PCI_NUM_RESOURCES 11
#ifndef PCI_BUS_NUM_RESOURCES
-#define PCI_BUS_NUM_RESOURCES 8
+#define PCI_BUS_NUM_RESOURCES 16
#endif
#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */
@@ -666,6 +666,7 @@
void pci_walk_bus(struct pci_bus *top, void (*cb)(struct pci_dev *, void *),
void *userdata);
+int pci_cfg_space_size_ext(struct pci_dev *dev, unsigned check_exp_pcix);
int pci_cfg_space_size(struct pci_dev *dev);
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
@@ -701,6 +702,8 @@
return -1;
}
+static inline void pci_msi_shutdown(struct pci_dev *dev)
+{ }
static inline void pci_disable_msi(struct pci_dev *dev)
{ }
@@ -710,6 +713,8 @@
return -1;
}
+static inline void pci_msix_shutdown(struct pci_dev *dev)
+{ }
static inline void pci_disable_msix(struct pci_dev *dev)
{ }
@@ -720,9 +725,11 @@
{ }
#else
extern int pci_enable_msi(struct pci_dev *dev);
+extern void pci_msi_shutdown(struct pci_dev *dev);
extern void pci_disable_msi(struct pci_dev *dev);
extern int pci_enable_msix(struct pci_dev *dev,
struct msix_entry *entries, int nvec);
+extern void pci_msix_shutdown(struct pci_dev *dev);
extern void pci_disable_msix(struct pci_dev *dev);
extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
extern void pci_restore_msi_state(struct pci_dev *dev);
@@ -1053,5 +1060,13 @@
extern int pcibios_add_platform_entries(struct pci_dev *dev);
+#ifdef CONFIG_PCI_MMCONFIG
+extern void __init pci_mmcfg_early_init(void);
+extern void __init pci_mmcfg_late_init(void);
+#else
+static inline void pci_mmcfg_early_init(void) { }
+static inline void pci_mmcfg_late_init(void) { }
+#endif
+
#endif /* __KERNEL__ */
#endif /* LINUX_PCI_H */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 70eb3c8..cf6dbd75 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1429,6 +1429,7 @@
#define PCI_DEVICE_ID_NEO_2DB9PRI 0x00C9
#define PCI_DEVICE_ID_NEO_2RJ45 0x00CA
#define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB
+#define PCIE_DEVICE_ID_NEO_4_IBM 0x00F4
#define PCI_VENDOR_ID_XIRCOM 0x115d
#define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101
@@ -2413,6 +2414,8 @@
#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0
#define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2
#define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601
+#define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119
+#define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a
#define PCI_DEVICE_ID_INTEL_82454GX 0x84c4
#define PCI_DEVICE_ID_INTEL_82450GX 0x84c5
#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 1ac9697..d746a2a 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -4,7 +4,6 @@
#include <linux/preempt.h>
#include <linux/slab.h> /* For kmalloc() */
#include <linux/smp.h>
-#include <linux/string.h> /* For memset() */
#include <linux/cpumask.h>
#include <asm/percpu.h>
diff --git a/include/linux/personality.h b/include/linux/personality.h
index 012cd55..a84e9ff 100644
--- a/include/linux/personality.h
+++ b/include/linux/personality.h
@@ -105,10 +105,6 @@
*/
#define personality(pers) (pers & PER_MASK)
-/*
- * Personality of the currently running process.
- */
-#define get_personality (current->personality)
/*
* Change personality of the currently running process.
diff --git a/include/linux/phantom.h b/include/linux/phantom.h
index 96f4048..02268c5 100644
--- a/include/linux/phantom.h
+++ b/include/linux/phantom.h
@@ -27,14 +27,17 @@
#define PH_IOC_MAGIC 'p'
#define PHN_GET_REG _IOWR(PH_IOC_MAGIC, 0, struct phm_reg *)
-#define PHN_SET_REG _IOW (PH_IOC_MAGIC, 1, struct phm_reg *)
+#define PHN_SET_REG _IOW(PH_IOC_MAGIC, 1, struct phm_reg *)
#define PHN_GET_REGS _IOWR(PH_IOC_MAGIC, 2, struct phm_regs *)
-#define PHN_SET_REGS _IOW (PH_IOC_MAGIC, 3, struct phm_regs *)
+#define PHN_SET_REGS _IOW(PH_IOC_MAGIC, 3, struct phm_regs *)
/* this ioctl tells the driver, that the caller is not OpenHaptics and might
* use improved registers update (no more phantom switchoffs when using
* libphantom) */
-#define PHN_NOT_OH _IO (PH_IOC_MAGIC, 4)
-#define PH_IOC_MAXNR 4
+#define PHN_NOT_OH _IO(PH_IOC_MAGIC, 4)
+#define PHN_GETREG _IOWR(PH_IOC_MAGIC, 5, struct phm_reg)
+#define PHN_SETREG _IOW(PH_IOC_MAGIC, 6, struct phm_reg)
+#define PHN_GETREGS _IOWR(PH_IOC_MAGIC, 7, struct phm_regs)
+#define PHN_SETREGS _IOW(PH_IOC_MAGIC, 8, struct phm_regs)
#define PHN_CONTROL 0x6 /* control byte in iaddr space */
#define PHN_CTL_AMP 0x1 /* switch after torques change */
diff --git a/include/linux/pid.h b/include/linux/pid.h
index c798081..c21c7e8 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -60,7 +60,7 @@
/* lists of tasks that use this pid */
struct hlist_head tasks[PIDTYPE_MAX];
struct rcu_head rcu;
- int level;
+ unsigned int level;
struct upid numbers[1];
};
@@ -89,9 +89,11 @@
* attach_pid() and detach_pid() must be called with the tasklist_lock
* write-held.
*/
-extern int attach_pid(struct task_struct *task, enum pid_type type,
- struct pid *pid);
+extern void attach_pid(struct task_struct *task, enum pid_type type,
+ struct pid *pid);
extern void detach_pid(struct task_struct *task, enum pid_type);
+extern void change_pid(struct task_struct *task, enum pid_type,
+ struct pid *pid);
extern void transfer_pid(struct task_struct *old, struct task_struct *new,
enum pid_type);
diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h
index fcd61fa..caff528 100644
--- a/include/linux/pid_namespace.h
+++ b/include/linux/pid_namespace.h
@@ -20,7 +20,7 @@
int last_pid;
struct task_struct *child_reaper;
struct kmem_cache *pid_cachep;
- int level;
+ unsigned int level;
struct pid_namespace *parent;
#ifdef CONFIG_PROC_FS
struct vfsmount *proc_mnt;
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 1de72cb..39a7ee8 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -21,8 +21,6 @@
#ifndef _LINUX_PM_H
#define _LINUX_PM_H
-#ifdef __KERNEL__
-
#include <linux/list.h>
#include <asm/atomic.h>
#include <asm/errno.h>
@@ -225,6 +223,4 @@
#define PM_APM 1
#define PM_ACPI 2
-#endif /* __KERNEL__ */
-
#endif /* _LINUX_PM_H */
diff --git a/include/linux/pnp.h b/include/linux/pnp.h
index b2f05c2..63b128d 100644
--- a/include/linux/pnp.h
+++ b/include/linux/pnp.h
@@ -6,66 +6,127 @@
#ifndef _LINUX_PNP_H
#define _LINUX_PNP_H
-#ifdef __KERNEL__
-
#include <linux/device.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mod_devicetable.h>
-#define PNP_MAX_PORT 40
-#define PNP_MAX_MEM 24
-#define PNP_MAX_IRQ 2
-#define PNP_MAX_DMA 2
#define PNP_NAME_LEN 50
struct pnp_protocol;
struct pnp_dev;
+struct pnp_resource_table;
/*
* Resource Management
*/
+struct resource *pnp_get_resource(struct pnp_dev *, unsigned int, unsigned int);
-/* Use these instead of directly reading pnp_dev to get resource information */
-#define pnp_port_start(dev,bar) ((dev)->res.port_resource[(bar)].start)
-#define pnp_port_end(dev,bar) ((dev)->res.port_resource[(bar)].end)
-#define pnp_port_flags(dev,bar) ((dev)->res.port_resource[(bar)].flags)
-#define pnp_port_valid(dev,bar) \
- ((pnp_port_flags((dev),(bar)) & (IORESOURCE_IO | IORESOURCE_UNSET)) \
- == IORESOURCE_IO)
-#define pnp_port_len(dev,bar) \
- ((pnp_port_start((dev),(bar)) == 0 && \
- pnp_port_end((dev),(bar)) == \
- pnp_port_start((dev),(bar))) ? 0 : \
- \
- (pnp_port_end((dev),(bar)) - \
- pnp_port_start((dev),(bar)) + 1))
+static inline int pnp_resource_valid(struct resource *res)
+{
+ if (res && !(res->flags & IORESOURCE_UNSET))
+ return 1;
+ return 0;
+}
-#define pnp_mem_start(dev,bar) ((dev)->res.mem_resource[(bar)].start)
-#define pnp_mem_end(dev,bar) ((dev)->res.mem_resource[(bar)].end)
-#define pnp_mem_flags(dev,bar) ((dev)->res.mem_resource[(bar)].flags)
-#define pnp_mem_valid(dev,bar) \
- ((pnp_mem_flags((dev),(bar)) & (IORESOURCE_MEM | IORESOURCE_UNSET)) \
- == IORESOURCE_MEM)
-#define pnp_mem_len(dev,bar) \
- ((pnp_mem_start((dev),(bar)) == 0 && \
- pnp_mem_end((dev),(bar)) == \
- pnp_mem_start((dev),(bar))) ? 0 : \
- \
- (pnp_mem_end((dev),(bar)) - \
- pnp_mem_start((dev),(bar)) + 1))
+static inline resource_size_t pnp_resource_len(struct resource *res)
+{
+ if (res->start == 0 && res->end == 0)
+ return 0;
+ return res->end - res->start + 1;
+}
-#define pnp_irq(dev,bar) ((dev)->res.irq_resource[(bar)].start)
-#define pnp_irq_flags(dev,bar) ((dev)->res.irq_resource[(bar)].flags)
-#define pnp_irq_valid(dev,bar) \
- ((pnp_irq_flags((dev),(bar)) & (IORESOURCE_IRQ | IORESOURCE_UNSET)) \
- == IORESOURCE_IRQ)
-#define pnp_dma(dev,bar) ((dev)->res.dma_resource[(bar)].start)
-#define pnp_dma_flags(dev,bar) ((dev)->res.dma_resource[(bar)].flags)
-#define pnp_dma_valid(dev,bar) \
- ((pnp_dma_flags((dev),(bar)) & (IORESOURCE_DMA | IORESOURCE_UNSET)) \
- == IORESOURCE_DMA)
+static inline resource_size_t pnp_port_start(struct pnp_dev *dev,
+ unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_IO, bar)->start;
+}
+
+static inline resource_size_t pnp_port_end(struct pnp_dev *dev,
+ unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_IO, bar)->end;
+}
+
+static inline unsigned long pnp_port_flags(struct pnp_dev *dev,
+ unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_IO, bar)->flags;
+}
+
+static inline int pnp_port_valid(struct pnp_dev *dev, unsigned int bar)
+{
+ return pnp_resource_valid(pnp_get_resource(dev, IORESOURCE_IO, bar));
+}
+
+static inline resource_size_t pnp_port_len(struct pnp_dev *dev,
+ unsigned int bar)
+{
+ return pnp_resource_len(pnp_get_resource(dev, IORESOURCE_IO, bar));
+}
+
+
+static inline resource_size_t pnp_mem_start(struct pnp_dev *dev,
+ unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_MEM, bar)->start;
+}
+
+static inline resource_size_t pnp_mem_end(struct pnp_dev *dev,
+ unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_MEM, bar)->end;
+}
+
+static inline unsigned long pnp_mem_flags(struct pnp_dev *dev, unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_MEM, bar)->flags;
+}
+
+static inline int pnp_mem_valid(struct pnp_dev *dev, unsigned int bar)
+{
+ return pnp_resource_valid(pnp_get_resource(dev, IORESOURCE_MEM, bar));
+}
+
+static inline resource_size_t pnp_mem_len(struct pnp_dev *dev,
+ unsigned int bar)
+{
+ return pnp_resource_len(pnp_get_resource(dev, IORESOURCE_MEM, bar));
+}
+
+
+static inline resource_size_t pnp_irq(struct pnp_dev *dev, unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_IRQ, bar)->start;
+}
+
+static inline unsigned long pnp_irq_flags(struct pnp_dev *dev, unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_IRQ, bar)->flags;
+}
+
+static inline int pnp_irq_valid(struct pnp_dev *dev, unsigned int bar)
+{
+ return pnp_resource_valid(pnp_get_resource(dev, IORESOURCE_IRQ, bar));
+}
+
+
+static inline resource_size_t pnp_dma(struct pnp_dev *dev, unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_DMA, bar)->start;
+}
+
+static inline unsigned long pnp_dma_flags(struct pnp_dev *dev, unsigned int bar)
+{
+ return pnp_get_resource(dev, IORESOURCE_DMA, bar)->flags;
+}
+
+static inline int pnp_dma_valid(struct pnp_dev *dev, unsigned int bar)
+{
+ return pnp_resource_valid(pnp_get_resource(dev, IORESOURCE_DMA, bar));
+}
+
#define PNP_PORT_FLAG_16BITADDR (1<<0)
#define PNP_PORT_FLAG_FIXED (1<<1)
@@ -118,13 +179,6 @@
struct pnp_option *next; /* used to chain dependent resources */
};
-struct pnp_resource_table {
- struct resource port_resource[PNP_MAX_PORT];
- struct resource mem_resource[PNP_MAX_MEM];
- struct resource dma_resource[PNP_MAX_DMA];
- struct resource irq_resource[PNP_MAX_IRQ];
-};
-
/*
* Device Management
*/
@@ -194,10 +248,9 @@
int capabilities;
struct pnp_option *independent;
struct pnp_option *dependent;
- struct pnp_resource_table res;
+ struct pnp_resource_table *res;
char name[PNP_NAME_LEN]; /* contains a human-readable name */
- unsigned short regs; /* ISAPnP: supported registers */
int flags; /* used by protocols */
struct proc_dir_entry *procent; /* device entry in /proc/bus/isapnp */
void *data;
@@ -328,8 +381,8 @@
char *name;
/* resource control functions */
- int (*get) (struct pnp_dev *dev, struct pnp_resource_table *res);
- int (*set) (struct pnp_dev *dev, struct pnp_resource_table *res);
+ int (*get) (struct pnp_dev *dev);
+ int (*set) (struct pnp_dev *dev);
int (*disable) (struct pnp_dev *dev);
/* protocol specific suspend/resume */
@@ -358,20 +411,12 @@
#if defined(CONFIG_PNP)
/* device management */
-int pnp_register_protocol(struct pnp_protocol *protocol);
-void pnp_unregister_protocol(struct pnp_protocol *protocol);
-int pnp_add_device(struct pnp_dev *dev);
int pnp_device_attach(struct pnp_dev *pnp_dev);
void pnp_device_detach(struct pnp_dev *pnp_dev);
extern struct list_head pnp_global;
extern int pnp_platform_devices;
/* multidevice card support */
-int pnp_add_card(struct pnp_card *card);
-void pnp_remove_card(struct pnp_card *card);
-int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev);
-void pnp_remove_card_device(struct pnp_dev *dev);
-int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card);
struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink,
const char *id, struct pnp_dev *from);
void pnp_release_card_device(struct pnp_dev *dev);
@@ -380,77 +425,42 @@
extern struct list_head pnp_cards;
/* resource management */
-struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev);
-struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev,
- int priority);
-int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data);
-int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data);
-int pnp_register_port_resource(struct pnp_option *option,
- struct pnp_port *data);
-int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data);
-void pnp_init_resource_table(struct pnp_resource_table *table);
-int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res,
- int mode);
int pnp_auto_config_dev(struct pnp_dev *dev);
-int pnp_validate_config(struct pnp_dev *dev);
int pnp_start_dev(struct pnp_dev *dev);
int pnp_stop_dev(struct pnp_dev *dev);
int pnp_activate_dev(struct pnp_dev *dev);
int pnp_disable_dev(struct pnp_dev *dev);
-void pnp_resource_change(struct resource *resource, resource_size_t start,
- resource_size_t size);
/* protocol helpers */
int pnp_is_active(struct pnp_dev *dev);
int compare_pnp_id(struct pnp_id *pos, const char *id);
-int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev);
int pnp_register_driver(struct pnp_driver *drv);
void pnp_unregister_driver(struct pnp_driver *drv);
#else
/* device management */
-static inline int pnp_register_protocol(struct pnp_protocol *protocol) { return -ENODEV; }
-static inline void pnp_unregister_protocol(struct pnp_protocol *protocol) { }
-static inline int pnp_init_device(struct pnp_dev *dev) { return -ENODEV; }
-static inline int pnp_add_device(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_device_attach(struct pnp_dev *pnp_dev) { return -ENODEV; }
static inline void pnp_device_detach(struct pnp_dev *pnp_dev) { }
#define pnp_platform_devices 0
/* multidevice card support */
-static inline int pnp_add_card(struct pnp_card *card) { return -ENODEV; }
-static inline void pnp_remove_card(struct pnp_card *card) { }
-static inline int pnp_add_card_device(struct pnp_card *card, struct pnp_dev *dev) { return -ENODEV; }
-static inline void pnp_remove_card_device(struct pnp_dev *dev) { }
-static inline int pnp_add_card_id(struct pnp_id *id, struct pnp_card *card) { return -ENODEV; }
static inline struct pnp_dev *pnp_request_card_device(struct pnp_card_link *clink, const char *id, struct pnp_dev *from) { return NULL; }
static inline void pnp_release_card_device(struct pnp_dev *dev) { }
static inline int pnp_register_card_driver(struct pnp_card_driver *drv) { return -ENODEV; }
static inline void pnp_unregister_card_driver(struct pnp_card_driver *drv) { }
/* resource management */
-static inline struct pnp_option *pnp_register_independent_option(struct pnp_dev *dev) { return NULL; }
-static inline struct pnp_option *pnp_register_dependent_option(struct pnp_dev *dev, int priority) { return NULL; }
-static inline int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data) { return -ENODEV; }
-static inline int pnp_register_dma_resource(struct pnp_option *option, struct pnp_dma *data) { return -ENODEV; }
-static inline int pnp_register_port_resource(struct pnp_option *option, struct pnp_port *data) { return -ENODEV; }
-static inline int pnp_register_mem_resource(struct pnp_option *option, struct pnp_mem *data) { return -ENODEV; }
-static inline void pnp_init_resource_table(struct pnp_resource_table *table) { }
-static inline int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, int mode) { return -ENODEV; }
static inline int pnp_auto_config_dev(struct pnp_dev *dev) { return -ENODEV; }
-static inline int pnp_validate_config(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_start_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_stop_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_activate_dev(struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_disable_dev(struct pnp_dev *dev) { return -ENODEV; }
-static inline void pnp_resource_change(struct resource *resource, resource_size_t start, resource_size_t size) { }
/* protocol helpers */
static inline int pnp_is_active(struct pnp_dev *dev) { return 0; }
static inline int compare_pnp_id(struct pnp_id *pos, const char *id) { return -ENODEV; }
-static inline int pnp_add_id(struct pnp_id *id, struct pnp_dev *dev) { return -ENODEV; }
static inline int pnp_register_driver(struct pnp_driver *drv) { return -ENODEV; }
static inline void pnp_unregister_driver(struct pnp_driver *drv) { }
@@ -466,6 +476,4 @@
#define pnp_dbg(format, arg...) do {} while (0)
#endif
-#endif /* __KERNEL__ */
-
#endif /* _LINUX_PNP_H */
diff --git a/include/linux/pnpbios.h b/include/linux/pnpbios.h
deleted file mode 100644
index 329192a..0000000
--- a/include/linux/pnpbios.h
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Include file for the interface to a PnP BIOS
- *
- * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
- * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
- * Minor reorganizations by David Hinds <dahinds@users.sourceforge.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, or (at your option) any
- * later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _LINUX_PNPBIOS_H
-#define _LINUX_PNPBIOS_H
-
-#ifdef __KERNEL__
-
-#include <linux/types.h>
-#include <linux/pnp.h>
-
-/*
- * Return codes
- */
-#define PNP_SUCCESS 0x00
-#define PNP_NOT_SET_STATICALLY 0x7f
-#define PNP_UNKNOWN_FUNCTION 0x81
-#define PNP_FUNCTION_NOT_SUPPORTED 0x82
-#define PNP_INVALID_HANDLE 0x83
-#define PNP_BAD_PARAMETER 0x84
-#define PNP_SET_FAILED 0x85
-#define PNP_EVENTS_NOT_PENDING 0x86
-#define PNP_SYSTEM_NOT_DOCKED 0x87
-#define PNP_NO_ISA_PNP_CARDS 0x88
-#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89
-#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a
-#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b
-#define PNP_BUFFER_TOO_SMALL 0x8c
-#define PNP_USE_ESCD_SUPPORT 0x8d
-#define PNP_MESSAGE_NOT_SUPPORTED 0x8e
-#define PNP_HARDWARE_ERROR 0x8f
-
-#define ESCD_SUCCESS 0x00
-#define ESCD_IO_ERROR_READING 0x55
-#define ESCD_INVALID 0x56
-#define ESCD_BUFFER_TOO_SMALL 0x59
-#define ESCD_NVRAM_TOO_SMALL 0x5a
-#define ESCD_FUNCTION_NOT_SUPPORTED 0x81
-
-/*
- * Events that can be received by "get event"
- */
-#define PNPEV_ABOUT_TO_CHANGE_CONFIG 0x0001
-#define PNPEV_DOCK_CHANGED 0x0002
-#define PNPEV_SYSTEM_DEVICE_CHANGED 0x0003
-#define PNPEV_CONFIG_CHANGED_FAILED 0x0004
-#define PNPEV_UNKNOWN_SYSTEM_EVENT 0xffff
-/* 0x8000 through 0xfffe are OEM defined */
-
-/*
- * Messages that should be sent through "send message"
- */
-#define PNPMSG_OK 0x00
-#define PNPMSG_ABORT 0x01
-#define PNPMSG_UNDOCK_DEFAULT_ACTION 0x40
-#define PNPMSG_POWER_OFF 0x41
-#define PNPMSG_PNP_OS_ACTIVE 0x42
-#define PNPMSG_PNP_OS_INACTIVE 0x43
-
-/*
- * Plug and Play BIOS flags
- */
-#define PNPBIOS_NO_DISABLE 0x0001
-#define PNPBIOS_NO_CONFIG 0x0002
-#define PNPBIOS_OUTPUT 0x0004
-#define PNPBIOS_INPUT 0x0008
-#define PNPBIOS_BOOTABLE 0x0010
-#define PNPBIOS_DOCK 0x0020
-#define PNPBIOS_REMOVABLE 0x0040
-#define pnpbios_is_static(x) (((x)->flags & 0x0100) == 0x0000)
-#define pnpbios_is_dynamic(x) ((x)->flags & 0x0080)
-
-/*
- * Function Parameters
- */
-#define PNPMODE_STATIC 1
-#define PNPMODE_DYNAMIC 0
-
-/* 0x8000 through 0xffff are OEM defined */
-
-#pragma pack(1)
-struct pnp_dev_node_info {
- __u16 no_nodes;
- __u16 max_node_size;
-};
-struct pnp_docking_station_info {
- __u32 location_id;
- __u32 serial;
- __u16 capabilities;
-};
-struct pnp_isa_config_struc {
- __u8 revision;
- __u8 no_csns;
- __u16 isa_rd_data_port;
- __u16 reserved;
-};
-struct escd_info_struc {
- __u16 min_escd_write_size;
- __u16 escd_size;
- __u32 nv_storage_base;
-};
-struct pnp_bios_node {
- __u16 size;
- __u8 handle;
- __u32 eisa_id;
- __u8 type_code[3];
- __u16 flags;
- __u8 data[0];
-};
-#pragma pack()
-
-#ifdef CONFIG_PNPBIOS
-
-/* non-exported */
-extern struct pnp_dev_node_info node_info;
-
-extern int pnp_bios_dev_node_info(struct pnp_dev_node_info *data);
-extern int pnp_bios_get_dev_node(u8 *nodenum, char config,
- struct pnp_bios_node *data);
-extern int pnp_bios_set_dev_node(u8 nodenum, char config,
- struct pnp_bios_node *data);
-extern int pnp_bios_get_stat_res(char *info);
-extern int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data);
-extern int pnp_bios_escd_info(struct escd_info_struc *data);
-extern int pnp_bios_read_escd(char *data, u32 nvram_base);
-extern int pnp_bios_dock_station_info(struct pnp_docking_station_info *data);
-
-#endif /* CONFIG_PNPBIOS */
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_PNPBIOS_H */
diff --git a/include/linux/poison.h b/include/linux/poison.h
index a9c31be..9f31683 100644
--- a/include/linux/poison.h
+++ b/include/linux/poison.h
@@ -10,6 +10,13 @@
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
+/********** include/linux/timer.h **********/
+/*
+ * Magic number "tsta" to indicate a static timer initializer
+ * for the object debugging code.
+ */
+#define TIMER_ENTRY_STATIC ((void *) 0x74737461)
+
/********** mm/slab.c **********/
/*
* Magic nums for obj red zoning.
diff --git a/include/linux/poll.h b/include/linux/poll.h
index 16d813b..ef45382 100644
--- a/include/linux/poll.h
+++ b/include/linux/poll.h
@@ -117,6 +117,8 @@
extern int do_select(int n, fd_set_bits *fds, s64 *timeout);
extern int do_sys_poll(struct pollfd __user * ufds, unsigned int nfds,
s64 *timeout);
+extern int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,
+ fd_set __user *exp, s64 *timeout);
#endif /* KERNEL */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 9b6c935..9883bc9 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -9,7 +9,6 @@
struct net;
struct completion;
-
/*
* The proc filesystem constants/structures
*/
@@ -41,7 +40,7 @@
* /proc file has a parent, but "subdir" is NULL for all
* non-directory entries).
*
- * "get_info" is called at "read", while "owner" is used to protect module
+ * "owner" is used to protect module
* from unloading while proc_dir_entry is in use
*/
@@ -49,7 +48,6 @@
int count, int *eof, void *data);
typedef int (write_proc_t)(struct file *file, const char __user *buffer,
unsigned long count, void *data);
-typedef int (get_info_t)(char *, char **, off_t, int);
struct proc_dir_entry {
unsigned int low_ino;
@@ -70,7 +68,6 @@
* somewhere.
*/
const struct file_operations *proc_fops;
- get_info_t *get_info;
struct module *owner;
struct proc_dir_entry *next, *parent, *subdir;
void *data;
@@ -97,10 +94,6 @@
#ifdef CONFIG_PROC_FS
-extern struct proc_dir_entry proc_root;
-extern struct proc_dir_entry *proc_root_fs;
-extern struct proc_dir_entry *proc_bus;
-extern struct proc_dir_entry *proc_root_driver;
extern struct proc_dir_entry *proc_root_kcore;
extern spinlock_t proc_subdir_lock;
@@ -123,9 +116,10 @@
extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent);
-struct proc_dir_entry *proc_create(const char *name, mode_t mode,
+struct proc_dir_entry *proc_create_data(const char *name, mode_t mode,
struct proc_dir_entry *parent,
- const struct file_operations *proc_fops);
+ const struct file_operations *proc_fops,
+ void *data);
extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent);
extern struct vfsmount *proc_mnt;
@@ -180,6 +174,12 @@
extern struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
struct proc_dir_entry *parent);
+static inline struct proc_dir_entry *proc_create(const char *name, mode_t mode,
+ struct proc_dir_entry *parent, const struct file_operations *proc_fops)
+{
+ return proc_create_data(name, mode, parent, proc_fops, NULL);
+}
+
static inline struct proc_dir_entry *create_proc_read_entry(const char *name,
mode_t mode, struct proc_dir_entry *base,
read_proc_t *read_proc, void * data)
@@ -192,24 +192,19 @@
return res;
}
-static inline struct proc_dir_entry *create_proc_info_entry(const char *name,
- mode_t mode, struct proc_dir_entry *base, get_info_t *get_info)
-{
- struct proc_dir_entry *res=create_proc_entry(name,mode,base);
- if (res) res->get_info=get_info;
- return res;
-}
-
extern struct proc_dir_entry *proc_net_fops_create(struct net *net,
const char *name, mode_t mode, const struct file_operations *fops);
extern void proc_net_remove(struct net *net, const char *name);
extern struct proc_dir_entry *proc_net_mkdir(struct net *net, const char *name,
struct proc_dir_entry *parent);
-#else
+/* While the {get|set|dup}_mm_exe_file functions are for mm_structs, they are
+ * only needed to implement /proc/<pid>|self/exe so we define them here. */
+extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file);
+extern struct file *get_mm_exe_file(struct mm_struct *mm);
+extern void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm);
-#define proc_root_driver NULL
-#define proc_bus NULL
+#else
#define proc_net_fops_create(net, name, mode, fops) ({ (void)(mode), NULL; })
static inline void proc_net_remove(struct net *net, const char *name) {}
@@ -226,6 +221,12 @@
{
return NULL;
}
+static inline struct proc_dir_entry *proc_create_data(const char *name,
+ mode_t mode, struct proc_dir_entry *parent,
+ const struct file_operations *proc_fops, void *data)
+{
+ return NULL;
+}
#define remove_proc_entry(name, parent) do {} while (0)
static inline struct proc_dir_entry *proc_symlink(const char *name,
@@ -236,16 +237,11 @@
static inline struct proc_dir_entry *create_proc_read_entry(const char *name,
mode_t mode, struct proc_dir_entry *base,
read_proc_t *read_proc, void * data) { return NULL; }
-static inline struct proc_dir_entry *create_proc_info_entry(const char *name,
- mode_t mode, struct proc_dir_entry *base, get_info_t *get_info)
- { return NULL; }
struct tty_driver;
static inline void proc_tty_register_driver(struct tty_driver *driver) {};
static inline void proc_tty_unregister_driver(struct tty_driver *driver) {};
-extern struct proc_dir_entry proc_root;
-
static inline int pid_ns_prepare_proc(struct pid_namespace *ns)
{
return 0;
@@ -255,6 +251,19 @@
{
}
+static inline void set_mm_exe_file(struct mm_struct *mm,
+ struct file *new_exe_file)
+{}
+
+static inline struct file *get_mm_exe_file(struct mm_struct *mm)
+{
+ return NULL;
+}
+
+static inline void dup_mm_exe_file(struct mm_struct *oldmm,
+ struct mm_struct *newmm)
+{}
+
#endif /* CONFIG_PROC_FS */
#if !defined(CONFIG_PROC_KCORE)
diff --git a/include/linux/profile.h b/include/linux/profile.h
index ff576d1..05c1cc7 100644
--- a/include/linux/profile.h
+++ b/include/linux/profile.h
@@ -1,8 +1,6 @@
#ifndef _LINUX_PROFILE_H
#define _LINUX_PROFILE_H
-#ifdef __KERNEL__
-
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/cpumask.h>
@@ -118,6 +116,4 @@
#endif /* CONFIG_PROFILING */
-#endif /* __KERNEL__ */
-
#endif /* _LINUX_PROFILE_H */
diff --git a/include/linux/proportions.h b/include/linux/proportions.h
index 2c3b3ca..5afc1b2 100644
--- a/include/linux/proportions.h
+++ b/include/linux/proportions.h
@@ -78,6 +78,19 @@
}
/*
+ * Limit the time part in order to ensure there are some bits left for the
+ * cycle counter and fraction multiply.
+ */
+#define PROP_MAX_SHIFT (3*BITS_PER_LONG/4)
+
+#define PROP_FRAC_SHIFT (BITS_PER_LONG - PROP_MAX_SHIFT - 1)
+#define PROP_FRAC_BASE (1UL << PROP_FRAC_SHIFT)
+
+void __prop_inc_percpu_max(struct prop_descriptor *pd,
+ struct prop_local_percpu *pl, long frac);
+
+
+/*
* ----- SINGLE ------
*/
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index ebe0c17..f98501b 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -98,6 +98,10 @@
extern int ptrace_may_attach(struct task_struct *task);
extern int __ptrace_may_attach(struct task_struct *task);
+static inline int ptrace_reparented(struct task_struct *child)
+{
+ return child->real_parent != child->parent;
+}
static inline void ptrace_link(struct task_struct *child,
struct task_struct *new_parent)
{
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 52e49dc..dcddfb2 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -347,6 +347,9 @@
((type) == USRQUOTA ? (sb_dqopt(sb)->flags & DQUOT_USR_SUSPENDED) : \
(sb_dqopt(sb)->flags & DQUOT_GRP_SUSPENDED))
+#define sb_any_quota_suspended(sb) (sb_has_quota_suspended(sb, USRQUOTA) | \
+ sb_has_quota_suspended(sb, GRPQUOTA))
+
int register_quota_format(struct quota_format_type *fmt);
void unregister_quota_format(struct quota_format_type *fmt);
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
index 8ab630b..81a1a02 100644
--- a/include/linux/raid/md.h
+++ b/include/linux/raid/md.h
@@ -94,6 +94,7 @@
extern void md_do_sync(mddev_t *mddev);
extern void md_new_event(mddev_t *mddev);
extern void md_allow_write(mddev_t *mddev);
+extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
#endif /* CONFIG_MD */
#endif
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index 7bb6d1a..812ffa5 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -84,6 +84,10 @@
#define AllReserved 6 /* If whole device is reserved for
* one array */
#define AutoDetected 7 /* added by auto-detect */
+#define Blocked 8 /* An error occured on an externally
+ * managed array, don't allow writes
+ * until it is cleared */
+ wait_queue_head_t blocked_wait;
int desc_nr; /* descriptor index in the superblock */
int raid_disk; /* role of device in array */
diff --git a/include/linux/rcuclassic.h b/include/linux/rcuclassic.h
index b3dccd6..b3aa05b 100644
--- a/include/linux/rcuclassic.h
+++ b/include/linux/rcuclassic.h
@@ -33,8 +33,6 @@
#ifndef __LINUX_RCUCLASSIC_H
#define __LINUX_RCUCLASSIC_H
-#ifdef __KERNEL__
-
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/threads.h>
@@ -163,5 +161,4 @@
#define rcu_enter_nohz() do { } while (0)
#define rcu_exit_nohz() do { } while (0)
-#endif /* __KERNEL__ */
#endif /* __LINUX_RCUCLASSIC_H */
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 37a642c..8082d65 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -33,8 +33,6 @@
#ifndef __LINUX_RCUPDATE_H
#define __LINUX_RCUPDATE_H
-#ifdef __KERNEL__
-
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/threads.h>
@@ -245,5 +243,4 @@
extern void rcu_init(void);
extern int rcu_needs_cpu(int cpu);
-#endif /* __KERNEL__ */
#endif /* __LINUX_RCUPDATE_H */
diff --git a/include/linux/rcupreempt.h b/include/linux/rcupreempt.h
index d038aa6..8a05c7e 100644
--- a/include/linux/rcupreempt.h
+++ b/include/linux/rcupreempt.h
@@ -33,8 +33,6 @@
#ifndef __LINUX_RCUPREEMPT_H
#define __LINUX_RCUPREEMPT_H
-#ifdef __KERNEL__
-
#include <linux/cache.h>
#include <linux/spinlock.h>
#include <linux/threads.h>
@@ -104,5 +102,4 @@
#define rcu_exit_nohz() do { } while (0)
#endif /* CONFIG_NO_HZ */
-#endif /* __KERNEL__ */
#endif /* __LINUX_RCUPREEMPT_H */
diff --git a/include/linux/rcupreempt_trace.h b/include/linux/rcupreempt_trace.h
index 21cd6b2..b99ae07 100644
--- a/include/linux/rcupreempt_trace.h
+++ b/include/linux/rcupreempt_trace.h
@@ -32,7 +32,6 @@
#ifndef __LINUX_RCUPREEMPT_TRACE_H
#define __LINUX_RCUPREEMPT_TRACE_H
-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/kernel.h>
@@ -95,5 +94,4 @@
extern void rcupreempt_trace_invoke(struct rcupreempt_trace *trace);
extern void rcupreempt_trace_next_add(struct rcupreempt_trace *trace);
-#endif /* __KERNEL__ */
#endif /* __LINUX_RCUPREEMPT_TRACE_H */
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index db5ef9b..336ee43 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -177,7 +177,6 @@
struct reiserfs_journal_cnode *j_last; /* newest journal block */
struct reiserfs_journal_cnode *j_first; /* oldest journal block. start here for traverse */
- struct file *j_dev_file;
struct block_device *j_dev_bd;
int j_1st_reserved_block; /* first block on s_dev of reserved area journal */
diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
index 61363ce..6d9e1fc 100644
--- a/include/linux/res_counter.h
+++ b/include/linux/res_counter.h
@@ -9,6 +9,8 @@
*
* Author: Pavel Emelianov <xemul@openvz.org>
*
+ * See Documentation/controllers/resource_counter.txt for more
+ * info about what this counter is.
*/
#include <linux/cgroup.h>
@@ -25,6 +27,10 @@
*/
unsigned long long usage;
/*
+ * the maximal value of the usage from the counter creation
+ */
+ unsigned long long max_usage;
+ /*
* the limit that usage cannot exceed
*/
unsigned long long limit;
@@ -39,8 +45,9 @@
spinlock_t lock;
};
-/*
+/**
* Helpers to interact with userspace
+ * res_counter_read_u64() - returns the value of the specified member.
* res_counter_read/_write - put/get the specified fields from the
* res_counter struct to/from the user
*
@@ -51,6 +58,8 @@
* @pos: and the offset.
*/
+u64 res_counter_read_u64(struct res_counter *counter, int member);
+
ssize_t res_counter_read(struct res_counter *counter, int member,
const char __user *buf, size_t nbytes, loff_t *pos,
int (*read_strategy)(unsigned long long val, char *s));
@@ -64,6 +73,7 @@
enum {
RES_USAGE,
+ RES_MAX_USAGE,
RES_LIMIT,
RES_FAILCNT,
};
@@ -124,4 +134,21 @@
return ret;
}
+static inline void res_counter_reset_max(struct res_counter *cnt)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cnt->lock, flags);
+ cnt->max_usage = cnt->usage;
+ spin_unlock_irqrestore(&cnt->lock, flags);
+}
+
+static inline void res_counter_reset_failcnt(struct res_counter *cnt)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&cnt->lock, flags);
+ cnt->failcnt = 0;
+ spin_unlock_irqrestore(&cnt->lock, flags);
+}
#endif
diff --git a/include/linux/resource.h b/include/linux/resource.h
index ae13db7..aaa423a 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -19,6 +19,7 @@
#define RUSAGE_SELF 0
#define RUSAGE_CHILDREN (-1)
#define RUSAGE_BOTH (-2) /* sys_wait4() uses this */
+#define RUSAGE_THREAD 1 /* only the calling thread */
struct rusage {
struct timeval ru_utime; /* user time used */
diff --git a/include/linux/rio.h b/include/linux/rio.h
index 0201849..dc0c755 100644
--- a/include/linux/rio.h
+++ b/include/linux/rio.h
@@ -14,8 +14,6 @@
#ifndef LINUX_RIO_H
#define LINUX_RIO_H
-#ifdef __KERNEL__
-
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/list.h>
@@ -333,5 +331,4 @@
extern int rio_open_outb_mbox(struct rio_mport *, void *, int, int);
extern void rio_close_outb_mbox(struct rio_mport *, int);
-#endif /* __KERNEL__ */
#endif /* LINUX_RIO_H */
diff --git a/include/linux/rio_drv.h b/include/linux/rio_drv.h
index 7adb2a1..90987b7 100644
--- a/include/linux/rio_drv.h
+++ b/include/linux/rio_drv.h
@@ -13,8 +13,6 @@
#ifndef LINUX_RIO_DRV_H
#define LINUX_RIO_DRV_H
-#ifdef __KERNEL__
-
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/list.h>
@@ -465,5 +463,4 @@
extern struct rio_dev *rio_get_asm(u16 vid, u16 did, u16 asm_vid, u16 asm_did,
struct rio_dev *from);
-#endif /* __KERNEL__ */
#endif /* LINUX_RIO_DRV_H */
diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index 7b524b4..efd348f 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -9,8 +9,6 @@
#include <linux/linkage.h>
-#ifdef __KERNEL__
-
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/system.h>
@@ -90,5 +88,4 @@
# define up_read_non_owner(sem) up_read(sem)
#endif
-#endif /* __KERNEL__ */
#endif /* _LINUX_RWSEM_H */
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 024d72b..03c2380 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -554,6 +554,14 @@
#define SIGNAL_STOP_DEQUEUED 0x00000002 /* stop signal dequeued */
#define SIGNAL_STOP_CONTINUED 0x00000004 /* SIGCONT since WCONTINUED reap */
#define SIGNAL_GROUP_EXIT 0x00000008 /* group exit in progress */
+/*
+ * Pending notifications to parent.
+ */
+#define SIGNAL_CLD_STOPPED 0x00000010
+#define SIGNAL_CLD_CONTINUED 0x00000020
+#define SIGNAL_CLD_MASK (SIGNAL_CLD_STOPPED|SIGNAL_CLD_CONTINUED)
+
+#define SIGNAL_UNKILLABLE 0x00000040 /* for init: ignore fatal signals */
/* If true, all threads except ->group_exit_task have pending SIGKILL */
static inline int signal_group_exit(const struct signal_struct *sig)
@@ -1167,7 +1175,7 @@
struct sighand_struct *sighand;
sigset_t blocked, real_blocked;
- sigset_t saved_sigmask; /* To be restored with TIF_RESTORE_SIGMASK */
+ sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */
struct sigpending pending;
unsigned long sas_ss_sp;
@@ -1669,7 +1677,10 @@
extern struct task_struct *find_task_by_pid_type_ns(int type, int pid,
struct pid_namespace *ns);
-extern struct task_struct *find_task_by_pid(pid_t nr);
+static inline struct task_struct *__deprecated find_task_by_pid(pid_t nr)
+{
+ return find_task_by_pid_type_ns(PIDTYPE_PID, nr, &init_pid_ns);
+}
extern struct task_struct *find_task_by_vpid(pid_t nr);
extern struct task_struct *find_task_by_pid_ns(pid_t nr,
struct pid_namespace *ns);
@@ -1745,8 +1756,7 @@
extern int kill_proc(pid_t, int, int);
extern struct sigqueue *sigqueue_alloc(void);
extern void sigqueue_free(struct sigqueue *);
-extern int send_sigqueue(int, struct sigqueue *, struct task_struct *);
-extern int send_group_sigqueue(int, struct sigqueue *, struct task_struct *);
+extern int send_sigqueue(struct sigqueue *, struct task_struct *, int group);
extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long);
@@ -2148,6 +2158,19 @@
#define TASK_SIZE_OF(tsk) TASK_SIZE
#endif
+#ifdef CONFIG_MM_OWNER
+extern void mm_update_next_owner(struct mm_struct *mm);
+extern void mm_init_owner(struct mm_struct *mm, struct task_struct *p);
+#else
+static inline void mm_update_next_owner(struct mm_struct *mm)
+{
+}
+
+static inline void mm_init_owner(struct mm_struct *mm, struct task_struct *p)
+{
+}
+#endif /* CONFIG_MM_OWNER */
+
#endif /* __KERNEL__ */
#endif
diff --git a/include/linux/security.h b/include/linux/security.h
index d0a28fd..50737c7 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -53,8 +53,9 @@
extern int cap_bprm_set_security(struct linux_binprm *bprm);
extern void cap_bprm_apply_creds(struct linux_binprm *bprm, int unsafe);
extern int cap_bprm_secureexec(struct linux_binprm *bprm);
-extern int cap_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags);
-extern int cap_inode_removexattr(struct dentry *dentry, char *name);
+extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry);
extern int cap_task_post_setuid(uid_t old_ruid, uid_t old_euid, uid_t old_suid, int flags);
@@ -1008,6 +1009,17 @@
* @perm describes the combination of permissions required of this key.
* Return 1 if permission granted, 0 if permission denied and -ve it the
* normal permissions model should be effected.
+ * @key_getsecurity:
+ * Get a textual representation of the security context attached to a key
+ * for the purposes of honouring KEYCTL_GETSECURITY. This function
+ * allocates the storage for the NUL-terminated string and the caller
+ * should free it.
+ * @key points to the key to be queried.
+ * @_buffer points to a pointer that should be set to point to the
+ * resulting string (if no label or an error occurs).
+ * Return the length of the string (including terminating NUL) or -ve if
+ * an error.
+ * May also return 0 (and a NULL buffer pointer) if there is no label.
*
* Security hooks affecting all System V IPC operations.
*
@@ -1362,13 +1374,13 @@
int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
int (*inode_getattr) (struct vfsmount *mnt, struct dentry *dentry);
void (*inode_delete) (struct inode *inode);
- int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,
- size_t size, int flags);
- void (*inode_post_setxattr) (struct dentry *dentry, char *name, void *value,
- size_t size, int flags);
- int (*inode_getxattr) (struct dentry *dentry, char *name);
+ int (*inode_setxattr) (struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+ void (*inode_post_setxattr) (struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+ int (*inode_getxattr) (struct dentry *dentry, const char *name);
int (*inode_listxattr) (struct dentry *dentry);
- int (*inode_removexattr) (struct dentry *dentry, char *name);
+ int (*inode_removexattr) (struct dentry *dentry, const char *name);
int (*inode_need_killpriv) (struct dentry *dentry);
int (*inode_killpriv) (struct dentry *dentry);
int (*inode_getsecurity) (const struct inode *inode, const char *name, void **buffer, bool alloc);
@@ -1469,7 +1481,7 @@
int (*getprocattr) (struct task_struct *p, char *name, char **value);
int (*setprocattr) (struct task_struct *p, char *name, void *value, size_t size);
int (*secid_to_secctx) (u32 secid, char **secdata, u32 *seclen);
- int (*secctx_to_secid) (char *secdata, u32 seclen, u32 *secid);
+ int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
void (*release_secctx) (char *secdata, u32 seclen);
#ifdef CONFIG_SECURITY_NETWORK
@@ -1537,7 +1549,7 @@
int (*key_permission) (key_ref_t key_ref,
struct task_struct *context,
key_perm_t perm);
-
+ int (*key_getsecurity)(struct key *key, char **_buffer);
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
@@ -1633,13 +1645,13 @@
int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
int security_inode_getattr(struct vfsmount *mnt, struct dentry *dentry);
void security_inode_delete(struct inode *inode);
-int security_inode_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags);
-void security_inode_post_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags);
-int security_inode_getxattr(struct dentry *dentry, char *name);
+int security_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+void security_inode_post_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+int security_inode_getxattr(struct dentry *dentry, const char *name);
int security_inode_listxattr(struct dentry *dentry);
-int security_inode_removexattr(struct dentry *dentry, char *name);
+int security_inode_removexattr(struct dentry *dentry, const char *name);
int security_inode_need_killpriv(struct dentry *dentry);
int security_inode_killpriv(struct dentry *dentry);
int security_inode_getsecurity(const struct inode *inode, const char *name, void **buffer, bool alloc);
@@ -1718,7 +1730,7 @@
int security_netlink_send(struct sock *sk, struct sk_buff *skb);
int security_netlink_recv(struct sk_buff *skb, int cap);
int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
-int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid);
+int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
void security_release_secctx(char *secdata, u32 seclen);
#else /* CONFIG_SECURITY */
@@ -2041,17 +2053,18 @@
static inline void security_inode_delete(struct inode *inode)
{ }
-static inline int security_inode_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+static inline int security_inode_setxattr(struct dentry *dentry,
+ const char *name, const void *value, size_t size, int flags)
{
return cap_inode_setxattr(dentry, name, value, size, flags);
}
-static inline void security_inode_post_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+static inline void security_inode_post_setxattr(struct dentry *dentry,
+ const char *name, const void *value, size_t size, int flags)
{ }
-static inline int security_inode_getxattr(struct dentry *dentry, char *name)
+static inline int security_inode_getxattr(struct dentry *dentry,
+ const char *name)
{
return 0;
}
@@ -2061,7 +2074,8 @@
return 0;
}
-static inline int security_inode_removexattr(struct dentry *dentry, char *name)
+static inline int security_inode_removexattr(struct dentry *dentry,
+ const char *name)
{
return cap_inode_removexattr(dentry, name);
}
@@ -2435,7 +2449,7 @@
return -EOPNOTSUPP;
}
-static inline int security_secctx_to_secid(char *secdata,
+static inline int security_secctx_to_secid(const char *secdata,
u32 seclen,
u32 *secid)
{
@@ -2729,6 +2743,7 @@
void security_key_free(struct key *key);
int security_key_permission(key_ref_t key_ref,
struct task_struct *context, key_perm_t perm);
+int security_key_getsecurity(struct key *key, char **_buffer);
#else
@@ -2750,6 +2765,12 @@
return 0;
}
+static inline int security_key_getsecurity(struct key *key, char **_buffer)
+{
+ *_buffer = NULL;
+ return 0;
+}
+
#endif
#endif /* CONFIG_KEYS */
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index 5b5369c..a66304a 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -1,6 +1,5 @@
#ifndef _LINUX_SEQ_FILE_H
#define _LINUX_SEQ_FILE_H
-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/string.h>
@@ -69,4 +68,3 @@
loff_t *ppos);
#endif
-#endif
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 7cb094a..d32123a 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -149,13 +149,15 @@
/* Freescale ColdFire */
#define PORT_MCF 78
-#define PORT_SC26XX 79
-
+/* Blackfin SPORT */
+#define PORT_BFIN_SPORT 79
/* MN10300 on-chip UART numbers */
#define PORT_MN10300 80
#define PORT_MN10300_CTS 81
+#define PORT_SC26XX 82
+
#ifdef __KERNEL__
#include <linux/compiler.h>
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 42d2e0a..84f997f 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -362,8 +362,6 @@
#define sig_kernel_stop(sig) \
(((sig) < SIGRTMIN) && siginmask(sig, SIG_KERNEL_STOP_MASK))
-#define sig_needs_tasklist(sig) ((sig) == SIGCONT)
-
#define sig_user_defined(t, signr) \
(((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) && \
((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN))
diff --git a/include/linux/slab.h b/include/linux/slab.h
index f62caaa..805ed4b 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -9,8 +9,6 @@
#ifndef _LINUX_SLAB_H
#define _LINUX_SLAB_H
-#ifdef __KERNEL__
-
#include <linux/gfp.h>
#include <linux/types.h>
@@ -29,6 +27,13 @@
#define SLAB_MEM_SPREAD 0x00100000UL /* Spread some memory over cpuset */
#define SLAB_TRACE 0x00200000UL /* Trace allocations and frees */
+/* Flag to prevent checks on free */
+#ifdef CONFIG_DEBUG_OBJECTS
+# define SLAB_DEBUG_OBJECTS 0x00400000UL
+#else
+# define SLAB_DEBUG_OBJECTS 0x00000000UL
+#endif
+
/* The following flags affect the page allocator grouping pages by mobility */
#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
#define SLAB_TEMPORARY SLAB_RECLAIM_ACCOUNT /* Objects are short-lived */
@@ -276,5 +281,4 @@
ssize_t slabinfo_write(struct file *, const char __user *, size_t, loff_t *);
#endif
-#endif /* __KERNEL__ */
#endif /* _LINUX_SLAB_H */
diff --git a/include/linux/smb.h b/include/linux/smb.h
index f098dff..caa43b2 100644
--- a/include/linux/smb.h
+++ b/include/linux/smb.h
@@ -11,6 +11,7 @@
#include <linux/types.h>
#include <linux/magic.h>
+#include <linux/time.h>
enum smb_protocol {
SMB_PROTOCOL_NONE,
diff --git a/include/linux/smb_fs_i.h b/include/linux/smb_fs_i.h
index 8516954..8ccf4ec 100644
--- a/include/linux/smb_fs_i.h
+++ b/include/linux/smb_fs_i.h
@@ -9,7 +9,6 @@
#ifndef _LINUX_SMB_FS_I
#define _LINUX_SMB_FS_I
-#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/fs.h>
@@ -36,4 +35,3 @@
};
#endif
-#endif
diff --git a/include/linux/smb_fs_sb.h b/include/linux/smb_fs_sb.h
index 3aa97aa..8a060a7 100644
--- a/include/linux/smb_fs_sb.h
+++ b/include/linux/smb_fs_sb.h
@@ -9,8 +9,6 @@
#ifndef _SMB_FS_SB
#define _SMB_FS_SB
-#ifdef __KERNEL__
-
#include <linux/types.h>
#include <linux/smb.h>
@@ -96,6 +94,4 @@
up(&(server->sem));
}
-#endif /* __KERNEL__ */
-
#endif
diff --git a/include/linux/string.h b/include/linux/string.h
index c5d3fca..efdc445 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -109,5 +109,7 @@
extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
extern void argv_free(char **argv);
+extern bool sysfs_streq(const char *s1, const char *s2);
+
#endif
#endif /* _LINUX_STRING_H_ */
diff --git a/include/linux/svga.h b/include/linux/svga.h
index 13ad0b8..c59a51a 100644
--- a/include/linux/svga.h
+++ b/include/linux/svga.h
@@ -1,8 +1,6 @@
#ifndef _LINUX_SVGA_H
#define _LINUX_SVGA_H
-#ifdef __KERNEL__
-
#include <linux/pci.h>
#include <video/vga.h>
@@ -122,6 +120,5 @@
int svga_match_format(const struct svga_fb_format *frm, struct fb_var_screeninfo *var, struct fb_fix_screeninfo *fix);
-#endif /* __KERNEL__ */
#endif /* _LINUX_SVGA_H */
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 8df6d13..0522f36 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -240,26 +240,28 @@
asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length);
#endif
-asmlinkage long sys_setxattr(char __user *path, char __user *name,
- void __user *value, size_t size, int flags);
-asmlinkage long sys_lsetxattr(char __user *path, char __user *name,
- void __user *value, size_t size, int flags);
-asmlinkage long sys_fsetxattr(int fd, char __user *name, void __user *value,
- size_t size, int flags);
-asmlinkage ssize_t sys_getxattr(char __user *path, char __user *name,
+asmlinkage long sys_setxattr(const char __user *path, const char __user *name,
+ const void __user *value, size_t size, int flags);
+asmlinkage long sys_lsetxattr(const char __user *path, const char __user *name,
+ const void __user *value, size_t size, int flags);
+asmlinkage long sys_fsetxattr(int fd, const char __user *name,
+ const void __user *value, size_t size, int flags);
+asmlinkage ssize_t sys_getxattr(const char __user *path, const char __user *name,
void __user *value, size_t size);
-asmlinkage ssize_t sys_lgetxattr(char __user *path, char __user *name,
+asmlinkage ssize_t sys_lgetxattr(const char __user *path, const char __user *name,
void __user *value, size_t size);
-asmlinkage ssize_t sys_fgetxattr(int fd, char __user *name,
+asmlinkage ssize_t sys_fgetxattr(int fd, const char __user *name,
void __user *value, size_t size);
-asmlinkage ssize_t sys_listxattr(char __user *path, char __user *list,
+asmlinkage ssize_t sys_listxattr(const char __user *path, char __user *list,
size_t size);
-asmlinkage ssize_t sys_llistxattr(char __user *path, char __user *list,
+asmlinkage ssize_t sys_llistxattr(const char __user *path, char __user *list,
size_t size);
asmlinkage ssize_t sys_flistxattr(int fd, char __user *list, size_t size);
-asmlinkage long sys_removexattr(char __user *path, char __user *name);
-asmlinkage long sys_lremovexattr(char __user *path, char __user *name);
-asmlinkage long sys_fremovexattr(int fd, char __user *name);
+asmlinkage long sys_removexattr(const char __user *path,
+ const char __user *name);
+asmlinkage long sys_lremovexattr(const char __user *path,
+ const char __user *name);
+asmlinkage long sys_fremovexattr(int fd, const char __user *name);
asmlinkage unsigned long sys_brk(unsigned long brk);
asmlinkage long sys_mprotect(unsigned long start, size_t len,
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 571f01d..24141b4 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -945,11 +945,14 @@
/* For the /proc/sys support */
struct ctl_table;
struct nsproxy;
+struct ctl_table_root;
+
extern struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev);
extern struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
struct ctl_table_header *prev);
extern void sysctl_head_finish(struct ctl_table_header *prev);
-extern int sysctl_perm(struct ctl_table *table, int op);
+extern int sysctl_perm(struct ctl_table_root *root,
+ struct ctl_table *table, int op);
typedef struct ctl_table ctl_table;
@@ -981,11 +984,6 @@
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen);
-extern int do_sysctl_strategy (struct ctl_table *table,
- int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen);
-
extern ctl_handler sysctl_data;
extern ctl_handler sysctl_string;
extern ctl_handler sysctl_intvec;
@@ -1054,6 +1052,8 @@
struct list_head header_list;
struct list_head *(*lookup)(struct ctl_table_root *root,
struct nsproxy *namespaces);
+ int (*permissions)(struct ctl_table_root *root,
+ struct nsproxy *namespaces, struct ctl_table *table);
};
/* struct ctl_table_header is used to maintain dynamic lists of
@@ -1085,8 +1085,6 @@
void unregister_sysctl_table(struct ctl_table_header * table);
int sysctl_check_table(struct nsproxy *namespaces, struct ctl_table *table);
-#else /* __KERNEL__ */
-
#endif /* __KERNEL__ */
#endif /* _LINUX_SYSCTL_H */
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index add3c5a..27bad59 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -190,6 +190,18 @@
return 0;
}
+static inline int sysfs_update_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+ return 0;
+}
+
+static inline int sysfs_update_group(struct kobject *kobj,
+ const struct attribute_group *grp)
+{
+ return 0;
+}
+
static inline void sysfs_remove_group(struct kobject *kobj,
const struct attribute_group *grp)
{
diff --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h
index e024863..9641130 100644
--- a/include/linux/sysv_fs.h
+++ b/include/linux/sysv_fs.h
@@ -1,11 +1,7 @@
#ifndef _LINUX_SYSV_FS_H
#define _LINUX_SYSV_FS_H
-#if defined(__GNUC__)
-# define __packed2__ __attribute__((packed, aligned(2)))
-#else
->> I want to scream! <<
-#endif
+#define __packed2__ __attribute__((packed, aligned(2)))
#ifndef __KERNEL__
diff --git a/include/linux/textsearch.h b/include/linux/textsearch.h
index 004808a..6f371f2 100644
--- a/include/linux/textsearch.h
+++ b/include/linux/textsearch.h
@@ -1,8 +1,6 @@
#ifndef __LINUX_TEXTSEARCH_H
#define __LINUX_TEXTSEARCH_H
-#ifdef __KERNEL__
-
#include <linux/types.h>
#include <linux/list.h>
#include <linux/kernel.h>
@@ -177,6 +175,4 @@
return ((u8 *) conf + TS_PRIV_ALIGN(sizeof(struct ts_config)));
}
-#endif /* __KERNEL__ */
-
#endif
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 90c1c19..06d3e6e 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -41,6 +41,7 @@
int (*set_mode) (struct thermal_zone_device *, const char *);
int (*get_trip_type) (struct thermal_zone_device *, int, char *);
int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
+ int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
};
struct thermal_cooling_device_ops {
@@ -65,6 +66,23 @@
((long)t-2732+5)/10 : ((long)t-2732-5)/10)
#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
+#if defined(CONFIG_HWMON) || \
+ (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+/* thermal zone devices with the same type share one hwmon device */
+struct thermal_hwmon_device {
+ char type[THERMAL_NAME_LENGTH];
+ struct device *device;
+ int count;
+ struct list_head tz_list;
+ struct list_head node;
+};
+
+struct thermal_hwmon_attr {
+ struct device_attribute attr;
+ char name[16];
+};
+#endif
+
struct thermal_zone_device {
int id;
char type[THERMAL_NAME_LENGTH];
@@ -76,6 +94,13 @@
struct idr idr;
struct mutex lock; /* protect cooling devices list */
struct list_head node;
+#if defined(CONFIG_HWMON) || \
+ (defined(CONFIG_HWMON_MODULE) && defined(CONFIG_THERMAL_MODULE))
+ struct list_head hwmon_node;
+ struct thermal_hwmon_device *hwmon;
+ struct thermal_hwmon_attr temp_input; /* hwmon sys attr */
+ struct thermal_hwmon_attr temp_crit; /* hwmon sys attr */
+#endif
};
struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
@@ -88,24 +113,10 @@
struct thermal_cooling_device *);
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
-
-#ifdef CONFIG_THERMAL
struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
struct
thermal_cooling_device_ops
*);
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
-#else
-static inline struct thermal_cooling_device
-*thermal_cooling_device_register(char *c, void *v,
- struct thermal_cooling_device_ops *t)
-{
- return NULL;
-}
-static inline
- void thermal_cooling_device_unregister(struct thermal_cooling_device *t)
-{
-};
-#endif
#endif /* __THERMAL_H__ */
diff --git a/include/linux/thread_info.h b/include/linux/thread_info.h
index accd7ba..38a5647 100644
--- a/include/linux/thread_info.h
+++ b/include/linux/thread_info.h
@@ -92,6 +92,31 @@
#define set_need_resched() set_thread_flag(TIF_NEED_RESCHED)
#define clear_need_resched() clear_thread_flag(TIF_NEED_RESCHED)
-#endif
+#if defined TIF_RESTORE_SIGMASK && !defined HAVE_SET_RESTORE_SIGMASK
+/*
+ * An arch can define its own version of set_restore_sigmask() to get the
+ * job done however works, with or without TIF_RESTORE_SIGMASK.
+ */
+#define HAVE_SET_RESTORE_SIGMASK 1
+
+/**
+ * set_restore_sigmask() - make sure saved_sigmask processing gets done
+ *
+ * This sets TIF_RESTORE_SIGMASK and ensures that the arch signal code
+ * will run before returning to user mode, to process the flag. For
+ * all callers, TIF_SIGPENDING is already set or it's no harm to set
+ * it. TIF_RESTORE_SIGMASK need not be in the set of bits that the
+ * arch code will notice on return to user mode, in case those bits
+ * are scarce. We set TIF_SIGPENDING here to ensure that the arch
+ * signal code always gets run when TIF_RESTORE_SIGMASK is set.
+ */
+static inline void set_restore_sigmask(void)
+{
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_thread_flag(TIF_SIGPENDING);
+}
+#endif /* TIF_RESTORE_SIGMASK && !HAVE_SET_RESTORE_SIGMASK */
+
+#endif /* __KERNEL__ */
#endif /* _LINUX_THREAD_INFO_H */
diff --git a/include/linux/timer.h b/include/linux/timer.h
index 979fefd..d4ba792 100644
--- a/include/linux/timer.h
+++ b/include/linux/timer.h
@@ -4,6 +4,7 @@
#include <linux/list.h>
#include <linux/ktime.h>
#include <linux/stddef.h>
+#include <linux/debugobjects.h>
struct tvec_base;
@@ -25,6 +26,7 @@
extern struct tvec_base boot_tvec_bases;
#define TIMER_INITIALIZER(_function, _expires, _data) { \
+ .entry = { .prev = TIMER_ENTRY_STATIC }, \
.function = (_function), \
.expires = (_expires), \
.data = (_data), \
@@ -38,6 +40,17 @@
void init_timer(struct timer_list *timer);
void init_timer_deferrable(struct timer_list *timer);
+#ifdef CONFIG_DEBUG_OBJECTS_TIMERS
+extern void init_timer_on_stack(struct timer_list *timer);
+extern void destroy_timer_on_stack(struct timer_list *timer);
+#else
+static inline void destroy_timer_on_stack(struct timer_list *timer) { }
+static inline void init_timer_on_stack(struct timer_list *timer)
+{
+ init_timer(timer);
+}
+#endif
+
static inline void setup_timer(struct timer_list * timer,
void (*function)(unsigned long),
unsigned long data)
@@ -47,6 +60,15 @@
init_timer(timer);
}
+static inline void setup_timer_on_stack(struct timer_list *timer,
+ void (*function)(unsigned long),
+ unsigned long data)
+{
+ timer->function = function;
+ timer->data = data;
+ init_timer_on_stack(timer);
+}
+
/**
* timer_pending - is a timer pending?
* @timer: the timer in question
@@ -164,5 +186,4 @@
unsigned long round_jiffies(unsigned long j);
unsigned long round_jiffies_relative(unsigned long j);
-
#endif
diff --git a/include/linux/timex.h b/include/linux/timex.h
index 8ea3e71..fc6035d 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -58,6 +58,8 @@
#include <asm/param.h>
+#define NTP_API 4 /* NTP API version */
+
/*
* SHIFT_KG and SHIFT_KF establish the damping of the PLL and are chosen
* for a slightly underdamped convergence characteristic. SHIFT_KH
@@ -74,24 +76,22 @@
#define MAXTC 10 /* maximum time constant (shift) */
/*
- * The SHIFT_UPDATE define establishes the decimal point of the
- * time_offset variable which represents the current offset with
- * respect to standard time.
- *
* SHIFT_USEC defines the scaling (shift) of the time_freq and
* time_tolerance variables, which represent the current frequency
* offset and maximum frequency tolerance.
*/
-#define SHIFT_UPDATE (SHIFT_HZ + 1) /* time offset scale (shift) */
#define SHIFT_USEC 16 /* frequency offset scale (shift) */
-#define SHIFT_NSEC 12 /* kernel frequency offset scale */
+#define PPM_SCALE (NSEC_PER_USEC << (NTP_SCALE_SHIFT - SHIFT_USEC))
+#define PPM_SCALE_INV_SHIFT 20
+#define PPM_SCALE_INV ((1ll << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \
+ PPM_SCALE + 1)
-#define MAXPHASE 512000L /* max phase error (us) */
-#define MAXFREQ (512L << SHIFT_USEC) /* max frequency error (ppm) */
-#define MAXFREQ_NSEC (512000L << SHIFT_NSEC) /* max frequency error (ppb) */
+#define MAXPHASE 500000000l /* max phase error (ns) */
+#define MAXFREQ 500000 /* max frequency error (ns/s) */
+#define MAXFREQ_SCALED ((s64)MAXFREQ << NTP_SCALE_SHIFT)
#define MINSEC 256 /* min interval between updates (s) */
#define MAXSEC 2048 /* max interval between updates (s) */
-#define NTP_PHASE_LIMIT (MAXPHASE << 5) /* beyond max. dispersion */
+#define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5) /* beyond max. dispersion */
/*
* syscall interface - used (mainly by NTP daemon)
@@ -121,9 +121,11 @@
long errcnt; /* calibration errors (ro) */
long stbcnt; /* stability limit exceeded (ro) */
+ int tai; /* TAI offset (ro) */
+
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
- int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32;
};
/*
@@ -135,6 +137,9 @@
#define ADJ_ESTERROR 0x0008 /* estimated time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
+#define ADJ_TAI 0x0080 /* set TAI offset */
+#define ADJ_MICRO 0x1000 /* select microsecond resolution */
+#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
@@ -146,8 +151,6 @@
#define MOD_ESTERROR ADJ_ESTERROR
#define MOD_STATUS ADJ_STATUS
#define MOD_TIMECONST ADJ_TIMECONST
-#define MOD_CLKB ADJ_TICK
-#define MOD_CLKA ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */
/*
@@ -169,9 +172,13 @@
#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */
#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */
+#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */
+#define STA_MODE 0x4000 /* mode (0 = PLL, 1 = FLL) (ro) */
+#define STA_CLK 0x8000 /* clock source (0 = A, 1 = B) (ro) */
+/* read-only bits */
#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \
- STA_PPSERROR | STA_CLOCKERR) /* read-only bits */
+ STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK)
/*
* Clock states (time_state)
@@ -203,10 +210,9 @@
extern long time_maxerror; /* maximum error */
extern long time_esterror; /* estimated error */
-extern long time_freq; /* frequency offset (scaled ppm) */
-
extern long time_adjust; /* The amount of adjtime left */
+extern void ntp_init(void);
extern void ntp_clear(void);
/**
@@ -225,7 +231,7 @@
__x < 0 ? -(-__x >> __s) : __x >> __s; \
})
-#define TICK_LENGTH_SHIFT 32
+#define NTP_SCALE_SHIFT 32
#ifdef CONFIG_NO_HZ
#define NTP_INTERVAL_FREQ (2)
@@ -234,8 +240,8 @@
#endif
#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ)
-/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
-extern u64 current_tick_length(void);
+/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
+extern u64 tick_length;
extern void second_overflow(void);
extern void update_ntp_one_tick(void);
diff --git a/include/linux/tty.h b/include/linux/tty.h
index dd8e08f..7f7121f 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -177,27 +177,33 @@
* size each time the window is created or resized anyway.
* - TYT, 9/14/92
*/
+
+struct tty_operations;
+
struct tty_struct {
int magic;
struct tty_driver *driver;
+ const struct tty_operations *ops;
int index;
struct tty_ldisc ldisc;
struct mutex termios_mutex;
+ spinlock_t ctrl_lock;
+ /* Termios values are protected by the termios mutex */
struct ktermios *termios, *termios_locked;
char name[64];
- struct pid *pgrp;
+ struct pid *pgrp; /* Protected by ctrl lock */
struct pid *session;
unsigned long flags;
int count;
- struct winsize winsize;
+ struct winsize winsize; /* termios mutex */
unsigned char stopped:1, hw_stopped:1, flow_stopped:1, packet:1;
unsigned char low_latency:1, warned:1;
- unsigned char ctrl_status;
+ unsigned char ctrl_status; /* ctrl_lock */
unsigned int receive_room; /* Bytes free for queue */
struct tty_struct *link;
struct fasync_struct *fasync;
- struct tty_bufhead buf;
+ struct tty_bufhead buf; /* Locked internally */
int alt_speed; /* For magic substitution of 38400 bps */
wait_queue_head_t write_wait;
wait_queue_head_t read_wait;
@@ -211,6 +217,7 @@
/*
* The following is data for the N_TTY line discipline. For
* historical reasons, this is included in the tty structure.
+ * Mostly locked by the BKL.
*/
unsigned int column;
unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
@@ -292,15 +299,21 @@
extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
int buflen);
extern void tty_write_message(struct tty_struct *tty, char *msg);
+extern int tty_put_char(struct tty_struct *tty, unsigned char c);
+extern int tty_chars_in_buffer(struct tty_struct *tty);
+extern int tty_write_room(struct tty_struct *tty);
+extern void tty_driver_flush_buffer(struct tty_struct *tty);
+extern void tty_throttle(struct tty_struct *tty);
+extern void tty_unthrottle(struct tty_struct *tty);
extern int is_current_pgrp_orphaned(void);
+extern struct pid *tty_get_pgrp(struct tty_struct *tty);
extern int is_ignored(int sig);
extern int tty_signal(int sig, struct tty_struct *tty);
extern void tty_hangup(struct tty_struct * tty);
extern void tty_vhangup(struct tty_struct * tty);
extern void tty_unhangup(struct file *filp);
extern int tty_hung_up_p(struct file * filp);
-extern int is_tty(struct file *filp);
extern void do_SAK(struct tty_struct *tty);
extern void __do_SAK(struct tty_struct *tty);
extern void disassociate_ctty(int priv);
@@ -324,8 +337,7 @@
extern void tty_wakeup(struct tty_struct *tty);
extern void tty_ldisc_flush(struct tty_struct *tty);
-extern int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg);
+extern long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg);
extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg);
@@ -351,8 +363,7 @@
extern void tty_audit_exit(void);
extern void tty_audit_fork(struct signal_struct *sig);
extern void tty_audit_push(struct tty_struct *tty);
-extern void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid);
-extern void tty_audit_opening(void);
+extern void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid);
#else
static inline void tty_audit_add_data(struct tty_struct *tty,
unsigned char *data, size_t size)
@@ -367,10 +378,7 @@
static inline void tty_audit_push(struct tty_struct *tty)
{
}
-static inline void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid)
-{
-}
-static inline void tty_audit_opening(void)
+static inline void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid, u32 sessionid)
{
}
#endif
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 21f69ac..59f1c0b 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -12,11 +12,15 @@
* This routine is called when a particular tty device is opened.
* This routine is mandatory; if this routine is not filled in,
* the attempted open will fail with ENODEV.
+ *
+ * Required method.
*
* void (*close)(struct tty_struct * tty, struct file * filp);
*
* This routine is called when a particular tty device is closed.
*
+ * Required method.
+ *
* int (*write)(struct tty_struct * tty,
* const unsigned char *buf, int count);
*
@@ -26,7 +30,9 @@
* number of characters actually accepted for writing. This
* routine is mandatory.
*
- * void (*put_char)(struct tty_struct *tty, unsigned char ch);
+ * Optional: Required for writable devices.
+ *
+ * int (*put_char)(struct tty_struct *tty, unsigned char ch);
*
* This routine is called by the kernel to write a single
* character to the tty device. If the kernel uses this routine,
@@ -34,10 +40,18 @@
* done stuffing characters into the driver. If there is no room
* in the queue, the character is ignored.
*
+ * Optional: Kernel will use the write method if not provided.
+ *
+ * Note: Do not call this function directly, call tty_put_char
+ *
* void (*flush_chars)(struct tty_struct *tty);
*
* This routine is called by the kernel after it has written a
* series of characters to the tty device using put_char().
+ *
+ * Optional:
+ *
+ * Note: Do not call this function directly, call tty_driver_flush_chars
*
* int (*write_room)(struct tty_struct *tty);
*
@@ -45,6 +59,10 @@
* will accept for queuing to be written. This number is subject
* to change as output buffers get emptied, or if the output flow
* control is acted.
+ *
+ * Required if write method is provided else not needed.
+ *
+ * Note: Do not call this function directly, call tty_write_room
*
* int (*ioctl)(struct tty_struct *tty, struct file * file,
* unsigned int cmd, unsigned long arg);
@@ -53,28 +71,37 @@
* device-specific ioctl's. If the ioctl number passed in cmd
* is not recognized by the driver, it should return ENOIOCTLCMD.
*
+ * Optional
+ *
* long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
* unsigned int cmd, unsigned long arg);
*
* implement ioctl processing for 32 bit process on 64 bit system
+ *
+ * Optional
*
* void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
*
* This routine allows the tty driver to be notified when
- * device's termios settings have changed. Note that a
- * well-designed tty driver should be prepared to accept the case
- * where old == NULL, and try to do something rational.
+ * device's termios settings have changed.
+ *
+ * Optional: Called under the termios lock
+ *
*
* void (*set_ldisc)(struct tty_struct *tty);
*
* This routine allows the tty driver to be notified when the
* device's termios settings have changed.
+ *
+ * Optional: Called under BKL (currently)
*
* void (*throttle)(struct tty_struct * tty);
*
* This routine notifies the tty driver that input buffers for
* the line discipline are close to full, and it should somehow
* signal that no more characters should be sent to the tty.
+ *
+ * Optional: Always invoke via tty_throttle();
*
* void (*unthrottle)(struct tty_struct * tty);
*
@@ -82,21 +109,33 @@
* that characters can now be sent to the tty without fear of
* overrunning the input buffers of the line disciplines.
*
+ * Optional: Always invoke via tty_unthrottle();
+ *
* void (*stop)(struct tty_struct *tty);
*
* This routine notifies the tty driver that it should stop
* outputting characters to the tty device.
+ *
+ * Optional:
+ *
+ * Note: Call stop_tty not this method.
*
* void (*start)(struct tty_struct *tty);
*
* This routine notifies the tty driver that it resume sending
* characters to the tty device.
+ *
+ * Optional:
+ *
+ * Note: Call start_tty not this method.
*
* void (*hangup)(struct tty_struct *tty);
*
* This routine notifies the tty driver that it should hangup the
* tty device.
*
+ * Required:
+ *
* void (*break_ctl)(struct tty_stuct *tty, int state);
*
* This optional routine requests the tty driver to turn on or
@@ -106,18 +145,26 @@
*
* If this routine is implemented, the high-level tty driver will
* handle the following ioctls: TCSBRK, TCSBRKP, TIOCSBRK,
- * TIOCCBRK. Otherwise, these ioctls will be passed down to the
- * driver to handle.
+ * TIOCCBRK.
+ *
+ * Optional: Required for TCSBRK/BRKP/etc handling.
*
* void (*wait_until_sent)(struct tty_struct *tty, int timeout);
*
* This routine waits until the device has written out all of the
* characters in its transmitter FIFO.
*
+ * Optional: If not provided the device is assumed to have no FIFO
+ *
+ * Note: Usually correct to call tty_wait_until_sent
+ *
* void (*send_xchar)(struct tty_struct *tty, char ch);
*
* This routine is used to send a high-priority XON/XOFF
* character to the device.
+ *
+ * Optional: If not provided then the write method is called under
+ * the atomic write lock to keep it serialized with the ldisc.
*/
#include <linux/fs.h>
@@ -132,7 +179,7 @@
void (*close)(struct tty_struct * tty, struct file * filp);
int (*write)(struct tty_struct * tty,
const unsigned char *buf, int count);
- void (*put_char)(struct tty_struct *tty, unsigned char ch);
+ int (*put_char)(struct tty_struct *tty, unsigned char ch);
void (*flush_chars)(struct tty_struct *tty);
int (*write_room)(struct tty_struct *tty);
int (*chars_in_buffer)(struct tty_struct *tty);
@@ -153,8 +200,6 @@
void (*send_xchar)(struct tty_struct *tty, char ch);
int (*read_proc)(char *page, char **start, off_t off,
int count, int *eof, void *data);
- int (*write_proc)(struct file *file, const char __user *buffer,
- unsigned long count, void *data);
int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear);
@@ -190,48 +235,13 @@
struct tty_struct **ttys;
struct ktermios **termios;
struct ktermios **termios_locked;
- void *driver_state; /* only used for the PTY driver */
-
- /*
- * Interface routines from the upper tty layer to the tty
- * driver. Will be replaced with struct tty_operations.
- */
- int (*open)(struct tty_struct * tty, struct file * filp);
- void (*close)(struct tty_struct * tty, struct file * filp);
- int (*write)(struct tty_struct * tty,
- const unsigned char *buf, int count);
- void (*put_char)(struct tty_struct *tty, unsigned char ch);
- void (*flush_chars)(struct tty_struct *tty);
- int (*write_room)(struct tty_struct *tty);
- int (*chars_in_buffer)(struct tty_struct *tty);
- int (*ioctl)(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg);
- long (*compat_ioctl)(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg);
- void (*set_termios)(struct tty_struct *tty, struct ktermios * old);
- void (*throttle)(struct tty_struct * tty);
- void (*unthrottle)(struct tty_struct * tty);
- void (*stop)(struct tty_struct *tty);
- void (*start)(struct tty_struct *tty);
- void (*hangup)(struct tty_struct *tty);
- void (*break_ctl)(struct tty_struct *tty, int state);
- void (*flush_buffer)(struct tty_struct *tty);
- void (*set_ldisc)(struct tty_struct *tty);
- void (*wait_until_sent)(struct tty_struct *tty, int timeout);
- void (*send_xchar)(struct tty_struct *tty, char ch);
- int (*read_proc)(char *page, char **start, off_t off,
- int count, int *eof, void *data);
- int (*write_proc)(struct file *file, const char __user *buffer,
- unsigned long count, void *data);
- int (*tiocmget)(struct tty_struct *tty, struct file *file);
- int (*tiocmset)(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear);
-#ifdef CONFIG_CONSOLE_POLL
- int (*poll_init)(struct tty_driver *driver, int line, char *options);
- int (*poll_get_char)(struct tty_driver *driver, int line);
- void (*poll_put_char)(struct tty_driver *driver, int line, char ch);
-#endif
+ void *driver_state;
+ /*
+ * Driver methods
+ */
+
+ const struct tty_operations *ops;
struct list_head tty_drivers;
};
diff --git a/include/linux/unaligned/access_ok.h b/include/linux/unaligned/access_ok.h
new file mode 100644
index 0000000..99c1b4d
--- /dev/null
+++ b/include/linux/unaligned/access_ok.h
@@ -0,0 +1,67 @@
+#ifndef _LINUX_UNALIGNED_ACCESS_OK_H
+#define _LINUX_UNALIGNED_ACCESS_OK_H
+
+#include <linux/kernel.h>
+#include <asm/byteorder.h>
+
+static inline u16 get_unaligned_le16(const void *p)
+{
+ return le16_to_cpup((__le16 *)p);
+}
+
+static inline u32 get_unaligned_le32(const void *p)
+{
+ return le32_to_cpup((__le32 *)p);
+}
+
+static inline u64 get_unaligned_le64(const void *p)
+{
+ return le64_to_cpup((__le64 *)p);
+}
+
+static inline u16 get_unaligned_be16(const void *p)
+{
+ return be16_to_cpup((__be16 *)p);
+}
+
+static inline u32 get_unaligned_be32(const void *p)
+{
+ return be32_to_cpup((__be32 *)p);
+}
+
+static inline u64 get_unaligned_be64(const void *p)
+{
+ return be64_to_cpup((__be64 *)p);
+}
+
+static inline void put_unaligned_le16(u16 val, void *p)
+{
+ *((__le16 *)p) = cpu_to_le16(val);
+}
+
+static inline void put_unaligned_le32(u32 val, void *p)
+{
+ *((__le32 *)p) = cpu_to_le32(val);
+}
+
+static inline void put_unaligned_le64(u64 val, void *p)
+{
+ *((__le64 *)p) = cpu_to_le64(val);
+}
+
+static inline void put_unaligned_be16(u16 val, void *p)
+{
+ *((__be16 *)p) = cpu_to_be16(val);
+}
+
+static inline void put_unaligned_be32(u32 val, void *p)
+{
+ *((__be32 *)p) = cpu_to_be32(val);
+}
+
+static inline void put_unaligned_be64(u64 val, void *p)
+{
+ *((__be64 *)p) = cpu_to_be64(val);
+}
+
+#endif /* _LINUX_UNALIGNED_ACCESS_OK_H */
diff --git a/include/linux/unaligned/be_byteshift.h b/include/linux/unaligned/be_byteshift.h
new file mode 100644
index 0000000..46dd12c
--- /dev/null
+++ b/include/linux/unaligned/be_byteshift.h
@@ -0,0 +1,70 @@
+#ifndef _LINUX_UNALIGNED_BE_BYTESHIFT_H
+#define _LINUX_UNALIGNED_BE_BYTESHIFT_H
+
+#include <linux/kernel.h>
+
+static inline u16 __get_unaligned_be16(const u8 *p)
+{
+ return p[0] << 8 | p[1];
+}
+
+static inline u32 __get_unaligned_be32(const u8 *p)
+{
+ return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
+}
+
+static inline u64 __get_unaligned_be64(const u8 *p)
+{
+ return (u64)__get_unaligned_be32(p) << 32 |
+ __get_unaligned_be32(p + 4);
+}
+
+static inline void __put_unaligned_be16(u16 val, u8 *p)
+{
+ *p++ = val >> 8;
+ *p++ = val;
+}
+
+static inline void __put_unaligned_be32(u32 val, u8 *p)
+{
+ __put_unaligned_be16(val >> 16, p);
+ __put_unaligned_be16(val, p + 2);
+}
+
+static inline void __put_unaligned_be64(u64 val, u8 *p)
+{
+ __put_unaligned_be32(val >> 32, p);
+ __put_unaligned_be32(val, p + 4);
+}
+
+static inline u16 get_unaligned_be16(const void *p)
+{
+ return __get_unaligned_be16((const u8 *)p);
+}
+
+static inline u32 get_unaligned_be32(const void *p)
+{
+ return __get_unaligned_be32((const u8 *)p);
+}
+
+static inline u64 get_unaligned_be64(const void *p)
+{
+ return __get_unaligned_be64((const u8 *)p);
+}
+
+static inline void put_unaligned_be16(u16 val, void *p)
+{
+ __put_unaligned_be16(val, p);
+}
+
+static inline void put_unaligned_be32(u32 val, void *p)
+{
+ __put_unaligned_be32(val, p);
+}
+
+static inline void put_unaligned_be64(u64 val, void *p)
+{
+ __put_unaligned_be64(val, p);
+}
+
+#endif /* _LINUX_UNALIGNED_BE_BYTESHIFT_H */
diff --git a/include/linux/unaligned/be_memmove.h b/include/linux/unaligned/be_memmove.h
new file mode 100644
index 0000000..c2a76c5
--- /dev/null
+++ b/include/linux/unaligned/be_memmove.h
@@ -0,0 +1,36 @@
+#ifndef _LINUX_UNALIGNED_BE_MEMMOVE_H
+#define _LINUX_UNALIGNED_BE_MEMMOVE_H
+
+#include <linux/unaligned/memmove.h>
+
+static inline u16 get_unaligned_be16(const void *p)
+{
+ return __get_unaligned_memmove16((const u8 *)p);
+}
+
+static inline u32 get_unaligned_be32(const void *p)
+{
+ return __get_unaligned_memmove32((const u8 *)p);
+}
+
+static inline u64 get_unaligned_be64(const void *p)
+{
+ return __get_unaligned_memmove64((const u8 *)p);
+}
+
+static inline void put_unaligned_be16(u16 val, void *p)
+{
+ __put_unaligned_memmove16(val, p);
+}
+
+static inline void put_unaligned_be32(u32 val, void *p)
+{
+ __put_unaligned_memmove32(val, p);
+}
+
+static inline void put_unaligned_be64(u64 val, void *p)
+{
+ __put_unaligned_memmove64(val, p);
+}
+
+#endif /* _LINUX_UNALIGNED_LE_MEMMOVE_H */
diff --git a/include/linux/unaligned/be_struct.h b/include/linux/unaligned/be_struct.h
new file mode 100644
index 0000000..1324158
--- /dev/null
+++ b/include/linux/unaligned/be_struct.h
@@ -0,0 +1,36 @@
+#ifndef _LINUX_UNALIGNED_BE_STRUCT_H
+#define _LINUX_UNALIGNED_BE_STRUCT_H
+
+#include <linux/unaligned/packed_struct.h>
+
+static inline u16 get_unaligned_be16(const void *p)
+{
+ return __get_unaligned_cpu16((const u8 *)p);
+}
+
+static inline u32 get_unaligned_be32(const void *p)
+{
+ return __get_unaligned_cpu32((const u8 *)p);
+}
+
+static inline u64 get_unaligned_be64(const void *p)
+{
+ return __get_unaligned_cpu64((const u8 *)p);
+}
+
+static inline void put_unaligned_be16(u16 val, void *p)
+{
+ __put_unaligned_cpu16(val, p);
+}
+
+static inline void put_unaligned_be32(u32 val, void *p)
+{
+ __put_unaligned_cpu32(val, p);
+}
+
+static inline void put_unaligned_be64(u64 val, void *p)
+{
+ __put_unaligned_cpu64(val, p);
+}
+
+#endif /* _LINUX_UNALIGNED_BE_STRUCT_H */
diff --git a/include/linux/unaligned/generic.h b/include/linux/unaligned/generic.h
new file mode 100644
index 0000000..02d97ff
--- /dev/null
+++ b/include/linux/unaligned/generic.h
@@ -0,0 +1,68 @@
+#ifndef _LINUX_UNALIGNED_GENERIC_H
+#define _LINUX_UNALIGNED_GENERIC_H
+
+/*
+ * Cause a link-time error if we try an unaligned access other than
+ * 1,2,4 or 8 bytes long
+ */
+extern void __bad_unaligned_access_size(void);
+
+#define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({ \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \
+ __bad_unaligned_access_size())))); \
+ }))
+
+#define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({ \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \
+ __bad_unaligned_access_size())))); \
+ }))
+
+#define __put_unaligned_le(val, ptr) ({ \
+ void *__gu_p = (ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ *(u8 *)__gu_p = (__force u8)(val); \
+ break; \
+ case 2: \
+ put_unaligned_le16((__force u16)(val), __gu_p); \
+ break; \
+ case 4: \
+ put_unaligned_le32((__force u32)(val), __gu_p); \
+ break; \
+ case 8: \
+ put_unaligned_le64((__force u64)(val), __gu_p); \
+ break; \
+ default: \
+ __bad_unaligned_access_size(); \
+ break; \
+ } \
+ (void)0; })
+
+#define __put_unaligned_be(val, ptr) ({ \
+ void *__gu_p = (ptr); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ *(u8 *)__gu_p = (__force u8)(val); \
+ break; \
+ case 2: \
+ put_unaligned_be16((__force u16)(val), __gu_p); \
+ break; \
+ case 4: \
+ put_unaligned_be32((__force u32)(val), __gu_p); \
+ break; \
+ case 8: \
+ put_unaligned_be64((__force u64)(val), __gu_p); \
+ break; \
+ default: \
+ __bad_unaligned_access_size(); \
+ break; \
+ } \
+ (void)0; })
+
+#endif /* _LINUX_UNALIGNED_GENERIC_H */
diff --git a/include/linux/unaligned/le_byteshift.h b/include/linux/unaligned/le_byteshift.h
new file mode 100644
index 0000000..59777e9
--- /dev/null
+++ b/include/linux/unaligned/le_byteshift.h
@@ -0,0 +1,70 @@
+#ifndef _LINUX_UNALIGNED_LE_BYTESHIFT_H
+#define _LINUX_UNALIGNED_LE_BYTESHIFT_H
+
+#include <linux/kernel.h>
+
+static inline u16 __get_unaligned_le16(const u8 *p)
+{
+ return p[0] | p[1] << 8;
+}
+
+static inline u32 __get_unaligned_le32(const u8 *p)
+{
+ return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+}
+
+static inline u64 __get_unaligned_le64(const u8 *p)
+{
+ return (u64)__get_unaligned_le32(p + 4) << 32 |
+ __get_unaligned_le32(p);
+}
+
+static inline void __put_unaligned_le16(u16 val, u8 *p)
+{
+ *p++ = val;
+ *p++ = val >> 8;
+}
+
+static inline void __put_unaligned_le32(u32 val, u8 *p)
+{
+ __put_unaligned_le16(val >> 16, p + 2);
+ __put_unaligned_le16(val, p);
+}
+
+static inline void __put_unaligned_le64(u64 val, u8 *p)
+{
+ __put_unaligned_le32(val >> 32, p + 4);
+ __put_unaligned_le32(val, p);
+}
+
+static inline u16 get_unaligned_le16(const void *p)
+{
+ return __get_unaligned_le16((const u8 *)p);
+}
+
+static inline u32 get_unaligned_le32(const void *p)
+{
+ return __get_unaligned_le32((const u8 *)p);
+}
+
+static inline u64 get_unaligned_le64(const void *p)
+{
+ return __get_unaligned_le64((const u8 *)p);
+}
+
+static inline void put_unaligned_le16(u16 val, void *p)
+{
+ __put_unaligned_le16(val, p);
+}
+
+static inline void put_unaligned_le32(u32 val, void *p)
+{
+ __put_unaligned_le32(val, p);
+}
+
+static inline void put_unaligned_le64(u64 val, void *p)
+{
+ __put_unaligned_le64(val, p);
+}
+
+#endif /* _LINUX_UNALIGNED_LE_BYTESHIFT_H */
diff --git a/include/linux/unaligned/le_memmove.h b/include/linux/unaligned/le_memmove.h
new file mode 100644
index 0000000..269849b
--- /dev/null
+++ b/include/linux/unaligned/le_memmove.h
@@ -0,0 +1,36 @@
+#ifndef _LINUX_UNALIGNED_LE_MEMMOVE_H
+#define _LINUX_UNALIGNED_LE_MEMMOVE_H
+
+#include <linux/unaligned/memmove.h>
+
+static inline u16 get_unaligned_le16(const void *p)
+{
+ return __get_unaligned_memmove16((const u8 *)p);
+}
+
+static inline u32 get_unaligned_le32(const void *p)
+{
+ return __get_unaligned_memmove32((const u8 *)p);
+}
+
+static inline u64 get_unaligned_le64(const void *p)
+{
+ return __get_unaligned_memmove64((const u8 *)p);
+}
+
+static inline void put_unaligned_le16(u16 val, void *p)
+{
+ __put_unaligned_memmove16(val, p);
+}
+
+static inline void put_unaligned_le32(u32 val, void *p)
+{
+ __put_unaligned_memmove32(val, p);
+}
+
+static inline void put_unaligned_le64(u64 val, void *p)
+{
+ __put_unaligned_memmove64(val, p);
+}
+
+#endif /* _LINUX_UNALIGNED_LE_MEMMOVE_H */
diff --git a/include/linux/unaligned/le_struct.h b/include/linux/unaligned/le_struct.h
new file mode 100644
index 0000000..088c457
--- /dev/null
+++ b/include/linux/unaligned/le_struct.h
@@ -0,0 +1,36 @@
+#ifndef _LINUX_UNALIGNED_LE_STRUCT_H
+#define _LINUX_UNALIGNED_LE_STRUCT_H
+
+#include <linux/unaligned/packed_struct.h>
+
+static inline u16 get_unaligned_le16(const void *p)
+{
+ return __get_unaligned_cpu16((const u8 *)p);
+}
+
+static inline u32 get_unaligned_le32(const void *p)
+{
+ return __get_unaligned_cpu32((const u8 *)p);
+}
+
+static inline u64 get_unaligned_le64(const void *p)
+{
+ return __get_unaligned_cpu64((const u8 *)p);
+}
+
+static inline void put_unaligned_le16(u16 val, void *p)
+{
+ __put_unaligned_cpu16(val, p);
+}
+
+static inline void put_unaligned_le32(u32 val, void *p)
+{
+ __put_unaligned_cpu32(val, p);
+}
+
+static inline void put_unaligned_le64(u64 val, void *p)
+{
+ __put_unaligned_cpu64(val, p);
+}
+
+#endif /* _LINUX_UNALIGNED_LE_STRUCT_H */
diff --git a/include/linux/unaligned/memmove.h b/include/linux/unaligned/memmove.h
new file mode 100644
index 0000000..eeb5a77
--- /dev/null
+++ b/include/linux/unaligned/memmove.h
@@ -0,0 +1,45 @@
+#ifndef _LINUX_UNALIGNED_MEMMOVE_H
+#define _LINUX_UNALIGNED_MEMMOVE_H
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+
+/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
+
+static inline u16 __get_unaligned_memmove16(const void *p)
+{
+ u16 tmp;
+ memmove(&tmp, p, 2);
+ return tmp;
+}
+
+static inline u32 __get_unaligned_memmove32(const void *p)
+{
+ u32 tmp;
+ memmove(&tmp, p, 4);
+ return tmp;
+}
+
+static inline u64 __get_unaligned_memmove64(const void *p)
+{
+ u64 tmp;
+ memmove(&tmp, p, 8);
+ return tmp;
+}
+
+static inline void __put_unaligned_memmove16(u16 val, void *p)
+{
+ memmove(p, &val, 2);
+}
+
+static inline void __put_unaligned_memmove32(u32 val, void *p)
+{
+ memmove(p, &val, 4);
+}
+
+static inline void __put_unaligned_memmove64(u64 val, void *p)
+{
+ memmove(p, &val, 8);
+}
+
+#endif /* _LINUX_UNALIGNED_MEMMOVE_H */
diff --git a/include/linux/unaligned/packed_struct.h b/include/linux/unaligned/packed_struct.h
new file mode 100644
index 0000000..2498bb9
--- /dev/null
+++ b/include/linux/unaligned/packed_struct.h
@@ -0,0 +1,46 @@
+#ifndef _LINUX_UNALIGNED_PACKED_STRUCT_H
+#define _LINUX_UNALIGNED_PACKED_STRUCT_H
+
+#include <linux/kernel.h>
+
+struct __una_u16 { u16 x __attribute__((packed)); };
+struct __una_u32 { u32 x __attribute__((packed)); };
+struct __una_u64 { u64 x __attribute__((packed)); };
+
+static inline u16 __get_unaligned_cpu16(const void *p)
+{
+ const struct __una_u16 *ptr = (const struct __una_u16 *)p;
+ return ptr->x;
+}
+
+static inline u32 __get_unaligned_cpu32(const void *p)
+{
+ const struct __una_u32 *ptr = (const struct __una_u32 *)p;
+ return ptr->x;
+}
+
+static inline u64 __get_unaligned_cpu64(const void *p)
+{
+ const struct __una_u64 *ptr = (const struct __una_u64 *)p;
+ return ptr->x;
+}
+
+static inline void __put_unaligned_cpu16(u16 val, void *p)
+{
+ struct __una_u16 *ptr = (struct __una_u16 *)p;
+ ptr->x = val;
+}
+
+static inline void __put_unaligned_cpu32(u32 val, void *p)
+{
+ struct __una_u32 *ptr = (struct __una_u32 *)p;
+ ptr->x = val;
+}
+
+static inline void __put_unaligned_cpu64(u64 val, void *p)
+{
+ struct __una_u64 *ptr = (struct __una_u64 *)p;
+ ptr->x = val;
+}
+
+#endif /* _LINUX_UNALIGNED_PACKED_STRUCT_H */
diff --git a/include/linux/usb/c67x00.h b/include/linux/usb/c67x00.h
new file mode 100644
index 0000000..83c6b45
--- /dev/null
+++ b/include/linux/usb/c67x00.h
@@ -0,0 +1,48 @@
+/*
+ * usb_c67x00.h: platform definitions for the Cypress C67X00 USB chip
+ *
+ * Copyright (C) 2006-2008 Barco N.V.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301 USA.
+ */
+
+#ifndef _LINUX_USB_C67X00_H
+#define _LINUX_USB_C67X00_H
+
+/* SIE configuration */
+#define C67X00_SIE_UNUSED 0
+#define C67X00_SIE_HOST 1
+#define C67X00_SIE_PERIPHERAL_A 2 /* peripheral on A port */
+#define C67X00_SIE_PERIPHERAL_B 3 /* peripheral on B port */
+
+#define c67x00_sie_config(config, n) (((config)>>(4*(n)))&0x3)
+
+#define C67X00_SIE1_UNUSED (C67X00_SIE_UNUSED << 0)
+#define C67X00_SIE1_HOST (C67X00_SIE_HOST << 0)
+#define C67X00_SIE1_PERIPHERAL_A (C67X00_SIE_PERIPHERAL_A << 0)
+#define C67X00_SIE1_PERIPHERAL_B (C67X00_SIE_PERIPHERAL_B << 0)
+
+#define C67X00_SIE2_UNUSED (C67X00_SIE_UNUSED << 4)
+#define C67X00_SIE2_HOST (C67X00_SIE_HOST << 4)
+#define C67X00_SIE2_PERIPHERAL_A (C67X00_SIE_PERIPHERAL_A << 4)
+#define C67X00_SIE2_PERIPHERAL_B (C67X00_SIE_PERIPHERAL_B << 4)
+
+struct c67x00_platform_data {
+ int sie_config; /* SIEs config (C67X00_SIEx_*) */
+ unsigned long hpi_regstep; /* Step between HPI registers */
+};
+
+#endif /* _LINUX_USB_C67X00_H */
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index 7e0d308..73a2f4e 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -455,7 +455,7 @@
/*-------------------------------------------------------------------------*/
-/* USB_DT_BOS: group of wireless capabilities */
+/* USB_DT_BOS: group of device-level capabilities */
struct usb_bos_descriptor {
__u8 bLength;
__u8 bDescriptorType;
@@ -501,6 +501,16 @@
__u8 bReserved;
} __attribute__((packed));
+#define USB_CAP_TYPE_EXT 2
+
+struct usb_ext_cap_descriptor { /* Link Power Management */
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDevCapabilityType;
+ __u8 bmAttributes;
+#define USB_LPM_SUPPORT (1 << 1) /* supports LPM */
+} __attribute__((packed));
+
/*-------------------------------------------------------------------------*/
/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index d8128f7..cf468fb 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -114,6 +114,8 @@
int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
int (*set_halt) (struct usb_ep *ep, int value);
+ int (*set_wedge) (struct usb_ep *ep);
+
int (*fifo_status) (struct usb_ep *ep);
void (*fifo_flush) (struct usb_ep *ep);
};
@@ -349,6 +351,25 @@
}
/**
+ * usb_ep_set_wedge - sets the halt feature and ignores clear requests
+ * @ep: the endpoint being wedged
+ *
+ * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
+ * requests. If the gadget driver clears the halt status, it will
+ * automatically unwedge the endpoint.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int
+usb_ep_set_wedge(struct usb_ep *ep)
+{
+ if (ep->ops->set_wedge)
+ return ep->ops->set_wedge(ep);
+ else
+ return ep->ops->set_halt(ep, 1);
+}
+
+/**
* usb_ep_fifo_status - returns number of bytes in fifo, or error
* @ep: the endpoint whose fifo status is being checked.
*
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index e7d1084..06005fa 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -76,6 +76,7 @@
* @dev: underlying device.
* @id: the device type identification (used to match it with a driver).
* @config: the configuration ops for this device.
+ * @features: the features supported by both driver and device.
* @priv: private pointer for the driver's use.
*/
struct virtio_device
@@ -84,6 +85,8 @@
struct device dev;
struct virtio_device_id id;
struct virtio_config_ops *config;
+ /* Note that this is a Linux set_bit-style bitmap. */
+ unsigned long features[1];
void *priv;
};
@@ -94,6 +97,8 @@
* virtio_driver - operations for a virtio I/O driver
* @driver: underlying device driver (populate name and owner).
* @id_table: the ids serviced by this driver.
+ * @feature_table: an array of feature numbers supported by this device.
+ * @feature_table_size: number of entries in the feature table array.
* @probe: the function to call when a device is found. Returns a token for
* remove, or PTR_ERR().
* @remove: the function when a device is removed.
@@ -103,6 +108,8 @@
struct virtio_driver {
struct device_driver driver;
const struct virtio_device_id *id_table;
+ const unsigned int *feature_table;
+ unsigned int feature_table_size;
int (*probe)(struct virtio_device *dev);
void (*remove)(struct virtio_device *dev);
void (*config_changed)(struct virtio_device *dev);
diff --git a/include/linux/virtio_blk.h b/include/linux/virtio_blk.h
index bca0b10..d4695a3 100644
--- a/include/linux/virtio_blk.h
+++ b/include/linux/virtio_blk.h
@@ -9,6 +9,7 @@
#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */
#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */
#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
+#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */
struct virtio_blk_config
{
@@ -18,6 +19,12 @@
__le32 size_max;
/* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
__le32 seg_max;
+ /* geometry the device (if VIRTIO_BLK_F_GEOMETRY) */
+ struct virtio_blk_geometry {
+ __le16 cylinders;
+ __u8 heads;
+ __u8 sectors;
+ } geometry;
} __attribute__((packed));
/* These two define direction. */
@@ -41,13 +48,8 @@
__u64 sector;
};
+/* And this is the final byte of the write scatter-gather list. */
#define VIRTIO_BLK_S_OK 0
#define VIRTIO_BLK_S_IOERR 1
#define VIRTIO_BLK_S_UNSUPP 2
-
-/* This is the first element of the write scatter-gather list */
-struct virtio_blk_inhdr
-{
- unsigned char status;
-};
#endif /* _LINUX_VIRTIO_BLK_H */
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index d581b29..50db245 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -16,27 +16,20 @@
#define VIRTIO_CONFIG_S_FAILED 0x80
#ifdef __KERNEL__
-struct virtio_device;
+#include <linux/virtio.h>
/**
* virtio_config_ops - operations for configuring a virtio device
- * @feature: search for a feature in this config
- * vdev: the virtio_device
- * bit: the feature bit
- * Returns true if the feature is supported. Acknowledges the feature
- * so the host can see it.
* @get: read the value of a configuration field
* vdev: the virtio_device
* offset: the offset of the configuration field
* buf: the buffer to write the field value into.
* len: the length of the buffer
- * Note that contents are conventionally little-endian.
* @set: write the value of a configuration field
* vdev: the virtio_device
* offset: the offset of the configuration field
* buf: the buffer to read the field value from.
* len: the length of the buffer
- * Note that contents are conventionally little-endian.
* @get_status: read the status byte
* vdev: the virtio_device
* Returns the status byte
@@ -52,10 +45,15 @@
* callback: the virqtueue callback
* Returns the new virtqueue or ERR_PTR() (eg. -ENOENT).
* @del_vq: free a virtqueue found by find_vq().
+ * @get_features: get the array of feature bits for this device.
+ * vdev: the virtio_device
+ * Returns the first 32 feature bits (all we currently need).
+ * @set_features: confirm what device features we'll be using.
+ * vdev: the virtio_device
+ * feature: the first 32 feature bits
*/
struct virtio_config_ops
{
- bool (*feature)(struct virtio_device *vdev, unsigned bit);
void (*get)(struct virtio_device *vdev, unsigned offset,
void *buf, unsigned len);
void (*set)(struct virtio_device *vdev, unsigned offset,
@@ -67,43 +65,52 @@
unsigned index,
void (*callback)(struct virtqueue *));
void (*del_vq)(struct virtqueue *vq);
+ u32 (*get_features)(struct virtio_device *vdev);
+ void (*set_features)(struct virtio_device *vdev, u32 features);
};
+/* If driver didn't advertise the feature, it will never appear. */
+void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
+ unsigned int fbit);
+
/**
- * virtio_config_val - look for a feature and get a single virtio config.
+ * virtio_has_feature - helper to determine if this device has this feature.
+ * @vdev: the device
+ * @fbit: the feature bit
+ */
+static inline bool virtio_has_feature(const struct virtio_device *vdev,
+ unsigned int fbit)
+{
+ /* Did you forget to fix assumptions on max features? */
+ if (__builtin_constant_p(fbit))
+ BUILD_BUG_ON(fbit >= 32);
+
+ virtio_check_driver_offered_feature(vdev, fbit);
+ return test_bit(fbit, vdev->features);
+}
+
+/**
+ * virtio_config_val - look for a feature and get a virtio config entry.
* @vdev: the virtio device
* @fbit: the feature bit
* @offset: the type to search for.
* @val: a pointer to the value to fill in.
*
* The return value is -ENOENT if the feature doesn't exist. Otherwise
- * the value is endian-corrected and returned in v. */
-#define virtio_config_val(vdev, fbit, offset, v) ({ \
- int _err; \
- if ((vdev)->config->feature((vdev), (fbit))) { \
- __virtio_config_val((vdev), (offset), (v)); \
- _err = 0; \
- } else \
- _err = -ENOENT; \
- _err; \
-})
+ * the config value is copied into whatever is pointed to by v. */
+#define virtio_config_val(vdev, fbit, offset, v) \
+ virtio_config_buf((vdev), (fbit), (offset), (v), sizeof(v))
-/**
- * __virtio_config_val - get a single virtio config without feature check.
- * @vdev: the virtio device
- * @offset: the type to search for.
- * @val: a pointer to the value to fill in.
- *
- * The value is endian-corrected and returned in v. */
-#define __virtio_config_val(vdev, offset, v) do { \
- BUILD_BUG_ON(sizeof(*(v)) != 1 && sizeof(*(v)) != 2 \
- && sizeof(*(v)) != 4 && sizeof(*(v)) != 8); \
- (vdev)->config->get((vdev), (offset), (v), sizeof(*(v))); \
- switch (sizeof(*(v))) { \
- case 2: le16_to_cpus((__u16 *) v); break; \
- case 4: le32_to_cpus((__u32 *) v); break; \
- case 8: le64_to_cpus((__u64 *) v); break; \
- } \
-} while(0)
+static inline int virtio_config_buf(struct virtio_device *vdev,
+ unsigned int fbit,
+ unsigned int offset,
+ void *buf, unsigned len)
+{
+ if (!virtio_has_feature(vdev, fbit))
+ return -ENOENT;
+
+ vdev->config->get(vdev, offset, buf, len);
+ return 0;
+}
#endif /* __KERNEL__ */
#endif /* _LINUX_VIRTIO_CONFIG_H */
diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h
index 1ea3351..9405aa6 100644
--- a/include/linux/virtio_net.h
+++ b/include/linux/virtio_net.h
@@ -6,9 +6,18 @@
#define VIRTIO_ID_NET 1
/* The feature bitmap for virtio net */
-#define VIRTIO_NET_F_CSUM 0 /* Can handle pkts w/ partial csum */
+#define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */
+#define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */
#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */
-#define VIRTIO_NET_F_GSO 6 /* Can handle pkts w/ any GSO type */
+#define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */
+#define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in. */
+#define VIRTIO_NET_F_GUEST_TSO6 8 /* Guest can handle TSOv6 in. */
+#define VIRTIO_NET_F_GUEST_ECN 9 /* Guest can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_GUEST_UFO 10 /* Guest can handle UFO in. */
+#define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in. */
+#define VIRTIO_NET_F_HOST_TSO6 12 /* Host can handle TSOv6 in. */
+#define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in. */
+#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */
struct virtio_net_config
{
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index b7b3362..f462439 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -114,6 +114,9 @@
int dirty_writeback_centisecs_handler(struct ctl_table *, int, struct file *,
void __user *, size_t *, loff_t *);
+void get_dirty_limits(long *pbackground, long *pdirty, long *pbdi_dirty,
+ struct backing_dev_info *bdi);
+
void page_writeback_init(void);
void balance_dirty_pages_ratelimited_nr(struct address_space *mapping,
unsigned long nr_pages_dirtied);
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index df6b95d..d131e35 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -47,10 +47,10 @@
};
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
-ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
+ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
-int vfs_setxattr(struct dentry *, char *, void *, size_t, int);
-int vfs_removexattr(struct dentry *, char *);
+int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
+int vfs_removexattr(struct dentry *, const char *);
ssize_t generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size);
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 0ea0bd8..2a52774 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -64,6 +64,7 @@
/* Conexant MPEG encoder/decoders: reserved range 410-420 */
V4L2_IDENT_CX23415 = 415,
V4L2_IDENT_CX23416 = 416,
+ V4L2_IDENT_CX23418 = 418,
/* module vp27smpx: just ident 2700 */
V4L2_IDENT_VP27SMPX = 2700,
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 316a584..020d057 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -107,9 +107,11 @@
struct i2c_driver;
struct i2c_adapter;
struct i2c_client;
+struct i2c_device_id;
int v4l2_i2c_attach(struct i2c_adapter *adapter, int address, struct i2c_driver *driver,
- const char *name, int (*probe)(struct i2c_client *));
+ const char *name,
+ int (*probe)(struct i2c_client *, const struct i2c_device_id *));
/* ------------------------------------------------------------------------- */
diff --git a/include/media/v4l2-i2c-drv-legacy.h b/include/media/v4l2-i2c-drv-legacy.h
index e764557..347b6f8 100644
--- a/include/media/v4l2-i2c-drv-legacy.h
+++ b/include/media/v4l2-i2c-drv-legacy.h
@@ -25,7 +25,7 @@
const char * const name;
int driverid;
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
- int (*probe)(struct i2c_client *client);
+ int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
int (*remove)(struct i2c_client *client);
int (*suspend)(struct i2c_client *client, pm_message_t state);
int (*resume)(struct i2c_client *client);
diff --git a/include/media/v4l2-i2c-drv.h b/include/media/v4l2-i2c-drv.h
index 9e4bab2..7b6f06b 100644
--- a/include/media/v4l2-i2c-drv.h
+++ b/include/media/v4l2-i2c-drv.h
@@ -30,7 +30,7 @@
const char * const name;
int driverid;
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
- int (*probe)(struct i2c_client *client);
+ int (*probe)(struct i2c_client *client, const struct i2c_device_id *id);
int (*remove)(struct i2c_client *client);
int (*suspend)(struct i2c_client *client, pm_message_t state);
int (*resume)(struct i2c_client *client);
diff --git a/include/net/compat.h b/include/net/compat.h
index 05fa5d0..164cb68 100644
--- a/include/net/compat.h
+++ b/include/net/compat.h
@@ -42,5 +42,8 @@
extern int compat_mc_setsockopt(struct sock *, int, int, char __user *, int,
int (*)(struct sock *, int, int, char __user *, int));
+extern int compat_mc_getsockopt(struct sock *, int, int, char __user *,
+ int __user *, int (*)(struct sock *, int, int, char __user *,
+ int __user *));
#endif /* NET_COMPAT_H */
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 56f3c94..9a51eba 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -405,7 +405,8 @@
struct ip_vs_protocol {
struct ip_vs_protocol *next;
char *name;
- __u16 protocol;
+ u16 protocol;
+ u16 num_states;
int dont_defrag;
atomic_t appcnt; /* counter of proto app incs */
int *timeout_table; /* protocol timeout table */
diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h
index 1bb7087..a6874ba2 100644
--- a/include/net/netfilter/nf_conntrack_tuple.h
+++ b/include/net/netfilter/nf_conntrack_tuple.h
@@ -107,16 +107,6 @@
} src;
};
-/* This is optimized opposed to a memset of the whole structure. Everything we
- * really care about is the source/destination unions */
-#define NF_CT_TUPLE_U_BLANK(tuple) \
- do { \
- (tuple)->src.u.all = 0; \
- (tuple)->dst.u.all = 0; \
- memset(&(tuple)->src.u3, 0, sizeof((tuple)->src.u3)); \
- memset(&(tuple)->dst.u3, 0, sizeof((tuple)->dst.u3)); \
- } while (0)
-
#ifdef __KERNEL__
static inline void nf_ct_dump_tuple_ip(const struct nf_conntrack_tuple *t)
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 5e53a85..e4d2d6b 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -103,6 +103,7 @@
struct netlbl_audit {
u32 secid;
uid_t loginuid;
+ u32 sessionid;
};
/*
diff --git a/include/net/route.h b/include/net/route.h
index c633880..fc836ff 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -116,7 +116,7 @@
extern int ip_route_output_key(struct net *, struct rtable **, struct flowi *flp);
extern int ip_route_output_flow(struct net *, struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
-extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu);
+extern unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph, unsigned short new_mtu, struct net_device *dev);
extern void ip_rt_send_redirect(struct sk_buff *skb);
extern unsigned inet_addr_type(struct net *net, __be32 addr);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index baa9f37..d1350bc 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -597,8 +597,9 @@
/* Audit Information */
struct xfrm_audit
{
- u32 loginuid;
u32 secid;
+ uid_t loginuid;
+ u32 sessionid;
};
#ifdef CONFIG_AUDITSYSCALL
@@ -616,13 +617,13 @@
return audit_buf;
}
-static inline void xfrm_audit_helper_usrinfo(u32 auid, u32 secid,
+static inline void xfrm_audit_helper_usrinfo(uid_t auid, u32 ses, u32 secid,
struct audit_buffer *audit_buf)
{
char *secctx;
u32 secctx_len;
- audit_log_format(audit_buf, " auid=%u", auid);
+ audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses);
if (secid != 0 &&
security_secid_to_secctx(secid, &secctx, &secctx_len) == 0) {
audit_log_format(audit_buf, " subj=%s", secctx);
@@ -632,13 +633,13 @@
}
extern void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
- u32 auid, u32 secid);
+ u32 auid, u32 ses, u32 secid);
extern void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
- u32 auid, u32 secid);
+ u32 auid, u32 ses, u32 secid);
extern void xfrm_audit_state_add(struct xfrm_state *x, int result,
- u32 auid, u32 secid);
+ u32 auid, u32 ses, u32 secid);
extern void xfrm_audit_state_delete(struct xfrm_state *x, int result,
- u32 auid, u32 secid);
+ u32 auid, u32 ses, u32 secid);
extern void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
struct sk_buff *skb);
extern void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family);
@@ -647,10 +648,10 @@
extern void xfrm_audit_state_icvfail(struct xfrm_state *x,
struct sk_buff *skb, u8 proto);
#else
-#define xfrm_audit_policy_add(x, r, a, s) do { ; } while (0)
-#define xfrm_audit_policy_delete(x, r, a, s) do { ; } while (0)
-#define xfrm_audit_state_add(x, r, a, s) do { ; } while (0)
-#define xfrm_audit_state_delete(x, r, a, s) do { ; } while (0)
+#define xfrm_audit_policy_add(x, r, a, se, s) do { ; } while (0)
+#define xfrm_audit_policy_delete(x, r, a, se, s) do { ; } while (0)
+#define xfrm_audit_state_add(x, r, a, se, s) do { ; } while (0)
+#define xfrm_audit_state_delete(x, r, a, se, s) do { ; } while (0)
#define xfrm_audit_state_replay_overflow(x, s) do { ; } while (0)
#define xfrm_audit_state_notfound_simple(s, f) do { ; } while (0)
#define xfrm_audit_state_notfound(s, f, sp, sq) do { ; } while (0)
diff --git a/include/rdma/ib_umem.h b/include/rdma/ib_umem.h
index 2229842..9ee0d2e 100644
--- a/include/rdma/ib_umem.h
+++ b/include/rdma/ib_umem.h
@@ -62,7 +62,7 @@
#ifdef CONFIG_INFINIBAND_USER_MEM
struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
- size_t size, int access);
+ size_t size, int access, int dmasync);
void ib_umem_release(struct ib_umem *umem);
int ib_umem_page_count(struct ib_umem *umem);
@@ -72,7 +72,7 @@
static inline struct ib_umem *ib_umem_get(struct ib_ucontext *context,
unsigned long addr, size_t size,
- int access) {
+ int access, int dmasync) {
return ERR_PTR(-EINVAL);
}
static inline void ib_umem_release(struct ib_umem *umem) { }
diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h
index 2dcbecc..911a661 100644
--- a/include/rdma/ib_verbs.h
+++ b/include/rdma/ib_verbs.h
@@ -1542,6 +1542,24 @@
dma_unmap_single(dev->dma_device, addr, size, direction);
}
+static inline u64 ib_dma_map_single_attrs(struct ib_device *dev,
+ void *cpu_addr, size_t size,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ return dma_map_single_attrs(dev->dma_device, cpu_addr, size,
+ direction, attrs);
+}
+
+static inline void ib_dma_unmap_single_attrs(struct ib_device *dev,
+ u64 addr, size_t size,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ return dma_unmap_single_attrs(dev->dma_device, addr, size,
+ direction, attrs);
+}
+
/**
* ib_dma_map_page - Map a physical page to DMA address
* @dev: The device for which the dma_addr is to be created
@@ -1611,6 +1629,21 @@
dma_unmap_sg(dev->dma_device, sg, nents, direction);
}
+static inline int ib_dma_map_sg_attrs(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ return dma_map_sg_attrs(dev->dma_device, sg, nents, direction, attrs);
+}
+
+static inline void ib_dma_unmap_sg_attrs(struct ib_device *dev,
+ struct scatterlist *sg, int nents,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs)
+{
+ dma_unmap_sg_attrs(dev->dma_device, sg, nents, direction, attrs);
+}
/**
* ib_sg_dma_address - Return the DMA address from a scatter/gather entry
* @dev: The device for which the DMA addresses were created
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 7b90b63..cd3ca63 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -225,6 +225,7 @@
/* custom statistics */
uint32_t eh_abort_cnt;
+ uint32_t fmr_unalign_cnt;
};
struct iscsi_pool {
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index 1f74bcd..32742c4 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -30,13 +30,6 @@
#endif
/*
- * SCSI command lengths
- */
-
-extern const unsigned char scsi_command_size[8];
-#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
-
-/*
* Special value for scanning to specify scanning or rescanning of all
* possible channels, (target) ids, or luns on a given shost.
*/
@@ -109,6 +102,7 @@
#define MODE_SENSE_10 0x5a
#define PERSISTENT_RESERVE_IN 0x5e
#define PERSISTENT_RESERVE_OUT 0x5f
+#define VARIABLE_LENGTH_CMD 0x7f
#define REPORT_LUNS 0xa0
#define MAINTENANCE_IN 0xa3
#define MOVE_MEDIUM 0xa5
@@ -136,6 +130,38 @@
#define ATA_12 0xa1 /* 12-byte pass-thru */
/*
+ * SCSI command lengths
+ */
+
+#define SCSI_MAX_VARLEN_CDB_SIZE 260
+
+/* defined in T10 SCSI Primary Commands-2 (SPC2) */
+struct scsi_varlen_cdb_hdr {
+ u8 opcode; /* opcode always == VARIABLE_LENGTH_CMD */
+ u8 control;
+ u8 misc[5];
+ u8 additional_cdb_length; /* total cdb length - 8 */
+ __be16 service_action;
+ /* service specific data follows */
+};
+
+static inline unsigned
+scsi_varlen_cdb_length(const void *hdr)
+{
+ return ((struct scsi_varlen_cdb_hdr *)hdr)->additional_cdb_length + 8;
+}
+
+extern const unsigned char scsi_command_size_tbl[8];
+#define COMMAND_SIZE(opcode) scsi_command_size_tbl[((opcode) >> 5) & 7]
+
+static inline unsigned
+scsi_command_size(const unsigned char *cmnd)
+{
+ return (cmnd[0] == VARIABLE_LENGTH_CMD) ?
+ scsi_varlen_cdb_length(cmnd) : COMMAND_SIZE(cmnd[0]);
+}
+
+/*
* SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft
* T10/1561-D Revision 4 Draft dated 7th November 2002.
*/
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 8d20e60..3e46dfa 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -7,10 +7,28 @@
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/scatterlist.h>
+#include <linux/blkdev.h>
struct Scsi_Host;
struct scsi_device;
+/*
+ * MAX_COMMAND_SIZE is:
+ * The longest fixed-length SCSI CDB as per the SCSI standard.
+ * fixed-length means: commands that their size can be determined
+ * by their opcode and the CDB does not carry a length specifier, (unlike
+ * the VARIABLE_LENGTH_CMD(0x7f) command). This is actually not exactly
+ * true and the SCSI standard also defines extended commands and
+ * vendor specific commands that can be bigger than 16 bytes. The kernel
+ * will support these using the same infrastructure used for VARLEN CDB's.
+ * So in effect MAX_COMMAND_SIZE means the maximum size command scsi-ml
+ * supports without specifying a cmd_len by ULD's
+ */
+#define MAX_COMMAND_SIZE 16
+#if (MAX_COMMAND_SIZE > BLK_MAX_CDB)
+# error MAX_COMMAND_SIZE can not be bigger than BLK_MAX_CDB
+#endif
+
struct scsi_data_buffer {
struct sg_table table;
unsigned length;
@@ -60,12 +78,11 @@
int allowed;
int timeout_per_command;
- unsigned char cmd_len;
+ unsigned short cmd_len;
enum dma_data_direction sc_data_direction;
/* These elements define the operation we are about to perform */
-#define MAX_COMMAND_SIZE 16
- unsigned char cmnd[MAX_COMMAND_SIZE];
+ unsigned char *cmnd;
struct timer_list eh_timeout; /* Used to time out the command. */
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index d3a133b..2a9add2 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -75,11 +75,11 @@
int result;
enum dma_data_direction data_direction;
unsigned char cmd_len;
- unsigned char cmnd[MAX_COMMAND_SIZE];
+ unsigned char *cmnd;
struct scsi_data_buffer sdb;
struct request *next_rq;
-
/* new command support */
+ unsigned char eh_cmnd[BLK_MAX_CDB];
struct scatterlist sense_sgl;
};
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index d967d6d..1834fdf 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -573,13 +573,11 @@
/*
* The maximum length of SCSI commands that this host can accept.
* Probably 12 for most host adapters, but could be 16 for others.
+ * or 260 if the driver supports variable length cdbs.
* For drivers that don't set this field, a value of 12 is
- * assumed. I am leaving this as a number rather than a bit
- * because you never know what subsequent SCSI standards might do
- * (i.e. could there be a 20 byte or a 24-byte command a few years
- * down the road?).
+ * assumed.
*/
- unsigned char max_cmd_len;
+ unsigned short max_cmd_len;
int this_id;
int can_queue;
diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h
index 68b634b..1f1d53f 100644
--- a/include/sound/mpu401.h
+++ b/include/sound/mpu401.h
@@ -50,6 +50,7 @@
#define MPU401_INFO_INTEGRATED (1 << 2) /* integrated h/w port */
#define MPU401_INFO_MMIO (1 << 3) /* MMIO access */
#define MPU401_INFO_TX_IRQ (1 << 4) /* independent TX irq */
+#define MPU401_INFO_NO_ACK (1 << 6) /* No ACK cmd needed */
#define MPU401_MODE_BIT_INPUT 0
#define MPU401_MODE_BIT_OUTPUT 1
diff --git a/init/Kconfig b/init/Kconfig
index da071c4..3e7b257 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -259,17 +259,14 @@
config LOG_BUF_SHIFT
int "Kernel log buffer size (16 => 64KB, 17 => 128KB)"
range 12 21
- default 17 if S390 || LOCKDEP
- default 16 if X86_NUMAQ || IA64
- default 15 if SMP
- default 14
+ default 17
help
Select kernel log buffer size as a power of 2.
- Defaults and Examples:
- 17 => 128 KB for S/390
- 16 => 64 KB for x86 NUMAQ or IA-64
- 15 => 32 KB for SMP
- 14 => 16 KB for uniprocessor
+ Examples:
+ 17 => 128 KB
+ 16 => 64 KB
+ 15 => 32 KB
+ 14 => 16 KB
13 => 8 KB
12 => 4 KB
@@ -284,6 +281,7 @@
config CGROUP_DEBUG
bool "Example debug cgroup subsystem"
depends on CGROUPS
+ default n
help
This option enables a simple cgroup subsystem that
exports useful debugging information about the cgroups
@@ -300,6 +298,13 @@
for instance virtual servers and checkpoint/restart
jobs.
+config CGROUP_DEVICE
+ bool "Device controller for cgroups"
+ depends on CGROUPS && EXPERIMENTAL
+ help
+ Provides a cgroup implementing whitelists for devices which
+ a process in the cgroup can mknod or open.
+
config CPUSETS
bool "Cpuset support"
depends on SMP && CGROUPS
@@ -373,9 +378,13 @@
infrastructure that works with cgroups
depends on CGROUPS
+config MM_OWNER
+ bool
+
config CGROUP_MEM_RES_CTLR
bool "Memory Resource Controller for Control Groups"
depends on CGROUPS && RESOURCE_COUNTERS
+ select MM_OWNER
help
Provides a memory resource controller that manages both page cache and
RSS memory.
@@ -388,6 +397,9 @@
Only enable when you're ok with these trade offs and really
sure you need the memory resource controller.
+ This config option also selects MM_OWNER config option, which
+ could in turn add some fork/exit overhead.
+
config SYSFS_DEPRECATED
bool
@@ -538,6 +550,17 @@
If unsure say Y here.
+config SYSCTL_SYSCALL_CHECK
+ bool "Sysctl checks" if EMBEDDED
+ depends on SYSCTL_SYSCALL
+ default y
+ ---help---
+ sys_sysctl uses binary paths that have been found challenging
+ to properly maintain and use. This enables checks that help
+ you to keep things correct.
+
+ If unsure say Y here.
+
config KALLSYMS
bool "Load all symbols for debugging/ksymoops" if EMBEDDED
default y
diff --git a/init/initramfs.c b/init/initramfs.c
index d53fee8..8eeeccb 100644
--- a/init/initramfs.c
+++ b/init/initramfs.c
@@ -57,7 +57,7 @@
continue;
return (*p)->name;
}
- q = (struct hash *)malloc(sizeof(struct hash));
+ q = kmalloc(sizeof(struct hash), GFP_KERNEL);
if (!q)
panic("can't allocate link hash entry");
q->major = major;
@@ -77,7 +77,7 @@
while (*p) {
q = *p;
*p = q->next;
- free(q);
+ kfree(q);
}
}
}
@@ -445,10 +445,10 @@
{
int written;
dry_run = check_only;
- header_buf = malloc(110);
- symlink_buf = malloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1);
- name_buf = malloc(N_ALIGN(PATH_MAX));
- window = malloc(WSIZE);
+ header_buf = kmalloc(110, GFP_KERNEL);
+ symlink_buf = kmalloc(PATH_MAX + N_ALIGN(PATH_MAX) + 1, GFP_KERNEL);
+ name_buf = kmalloc(N_ALIGN(PATH_MAX), GFP_KERNEL);
+ window = kmalloc(WSIZE, GFP_KERNEL);
if (!window || !header_buf || !symlink_buf || !name_buf)
panic("can't allocate buffers");
state = Start;
@@ -484,10 +484,10 @@
buf += inptr;
len -= inptr;
}
- free(window);
- free(name_buf);
- free(symlink_buf);
- free(header_buf);
+ kfree(window);
+ kfree(name_buf);
+ kfree(symlink_buf);
+ kfree(header_buf);
return message;
}
diff --git a/init/main.c b/init/main.c
index 1687b01..a87d4ca5 100644
--- a/init/main.c
+++ b/init/main.c
@@ -52,12 +52,14 @@
#include <linux/unwind.h>
#include <linux/buffer_head.h>
#include <linux/debug_locks.h>
+#include <linux/debugobjects.h>
#include <linux/lockdep.h>
#include <linux/pid_namespace.h>
#include <linux/device.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/signal.h>
+#include <linux/idr.h>
#include <asm/io.h>
#include <asm/bugs.h>
@@ -458,7 +460,7 @@
kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
numa_default_policy();
pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);
- kthreadd_task = find_task_by_pid(pid);
+ kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns);
unlock_kernel();
/*
@@ -542,6 +544,7 @@
*/
unwind_init();
lockdep_init();
+ debug_objects_early_init();
cgroup_init_early();
local_irq_disable();
@@ -559,6 +562,7 @@
printk(KERN_NOTICE);
printk(linux_banner);
setup_arch(&command_line);
+ mm_init_owner(&init_mm, &init_task);
setup_command_line(command_line);
unwind_setup();
setup_per_cpu_areas();
@@ -636,6 +640,8 @@
enable_debug_pagealloc();
cpu_hotplug_init();
kmem_cache_init();
+ debug_objects_mem_init();
+ idr_init_cache();
setup_per_cpu_pageset();
numa_policy_init();
if (late_time_init)
@@ -700,10 +706,8 @@
int result;
if (initcall_debug) {
- printk("Calling initcall 0x%p", *call);
- print_fn_descriptor_symbol(": %s()",
+ print_fn_descriptor_symbol("calling %s()\n",
(unsigned long) *call);
- printk("\n");
t0 = ktime_get();
}
@@ -713,15 +717,10 @@
t1 = ktime_get();
delta = ktime_sub(t1, t0);
- printk("initcall 0x%p", *call);
- print_fn_descriptor_symbol(": %s()",
+ print_fn_descriptor_symbol("initcall %s()",
(unsigned long) *call);
- printk(" returned %d.\n", result);
-
- printk("initcall 0x%p ran for %Ld msecs: ",
- *call, (unsigned long long)delta.tv64 >> 20);
- print_fn_descriptor_symbol("%s()\n",
- (unsigned long) *call);
+ printk(" returned %d after %Ld msecs\n", result,
+ (unsigned long long) delta.tv64 >> 20);
}
if (result && result != -ENODEV && initcall_debug) {
@@ -737,10 +736,9 @@
local_irq_enable();
}
if (msg) {
- printk(KERN_WARNING "initcall at 0x%p", *call);
- print_fn_descriptor_symbol(": %s()",
+ print_fn_descriptor_symbol(KERN_WARNING "initcall %s()",
(unsigned long) *call);
- printk(": returned with %s\n", msg);
+ printk(" returned with %s\n", msg);
}
}
@@ -807,6 +805,8 @@
(void) sys_dup(0);
(void) sys_dup(0);
+ current->signal->flags |= SIGNAL_UNKILLABLE;
+
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
diff --git a/ipc/Makefile b/ipc/Makefile
index 5fc5e33..65c3843 100644
--- a/ipc/Makefile
+++ b/ipc/Makefile
@@ -3,7 +3,7 @@
#
obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o
-obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o
+obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o ipcns_notifier.o
obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
obj_mq-$(CONFIG_COMPAT) += compat_mq.o
obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c
index 7f4235b..d349746 100644
--- a/ipc/ipc_sysctl.c
+++ b/ipc/ipc_sysctl.c
@@ -15,6 +15,8 @@
#include <linux/sysctl.h>
#include <linux/uaccess.h>
#include <linux/ipc_namespace.h>
+#include <linux/msg.h>
+#include "util.h"
static void *get_ipc(ctl_table *table)
{
@@ -24,6 +26,27 @@
return which;
}
+/*
+ * Routine that is called when a tunable has successfully been changed by
+ * hand and it has a callback routine registered on the ipc namespace notifier
+ * chain: we don't want such tunables to be recomputed anymore upon memory
+ * add/remove or ipc namespace creation/removal.
+ * They can come back to a recomputable state by being set to a <0 value.
+ */
+static void tunable_set_callback(int val)
+{
+ if (val >= 0)
+ unregister_ipcns_notifier(current->nsproxy->ipc_ns);
+ else {
+ /*
+ * Re-enable automatic recomputing only if not already
+ * enabled.
+ */
+ recompute_msgmni(current->nsproxy->ipc_ns);
+ cond_register_ipcns_notifier(current->nsproxy->ipc_ns);
+ }
+}
+
#ifdef CONFIG_PROC_FS
static int proc_ipc_dointvec(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
@@ -35,6 +58,24 @@
return proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos);
}
+static int proc_ipc_callback_dointvec(ctl_table *table, int write,
+ struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct ctl_table ipc_table;
+ size_t lenp_bef = *lenp;
+ int rc;
+
+ memcpy(&ipc_table, table, sizeof(ipc_table));
+ ipc_table.data = get_ipc(table);
+
+ rc = proc_dointvec(&ipc_table, write, filp, buffer, lenp, ppos);
+
+ if (write && !rc && lenp_bef == *lenp)
+ tunable_set_callback(*((int *)(ipc_table.data)));
+
+ return rc;
+}
+
static int proc_ipc_doulongvec_minmax(ctl_table *table, int write,
struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos)
{
@@ -49,6 +90,7 @@
#else
#define proc_ipc_doulongvec_minmax NULL
#define proc_ipc_dointvec NULL
+#define proc_ipc_callback_dointvec NULL
#endif
#ifdef CONFIG_SYSCTL_SYSCALL
@@ -90,8 +132,30 @@
}
return 1;
}
+
+static int sysctl_ipc_registered_data(ctl_table *table, int __user *name,
+ int nlen, void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen)
+{
+ int rc;
+
+ rc = sysctl_ipc_data(table, name, nlen, oldval, oldlenp, newval,
+ newlen);
+
+ if (newval && newlen && rc > 0) {
+ /*
+ * Tunable has successfully been changed from userland
+ */
+ int *data = get_ipc(table);
+
+ tunable_set_callback(*data);
+ }
+
+ return rc;
+}
#else
#define sysctl_ipc_data NULL
+#define sysctl_ipc_registered_data NULL
#endif
static struct ctl_table ipc_kern_table[] = {
@@ -137,8 +201,8 @@
.data = &init_ipc_ns.msg_ctlmni,
.maxlen = sizeof (init_ipc_ns.msg_ctlmni),
.mode = 0644,
- .proc_handler = proc_ipc_dointvec,
- .strategy = sysctl_ipc_data,
+ .proc_handler = proc_ipc_callback_dointvec,
+ .strategy = sysctl_ipc_registered_data,
},
{
.ctl_name = KERN_MSGMNB,
diff --git a/ipc/ipcns_notifier.c b/ipc/ipcns_notifier.c
new file mode 100644
index 0000000..70ff091
--- /dev/null
+++ b/ipc/ipcns_notifier.c
@@ -0,0 +1,82 @@
+/*
+ * linux/ipc/ipcns_notifier.c
+ * Copyright (C) 2007 BULL SA. Nadia Derbey
+ *
+ * Notification mechanism for ipc namespaces:
+ * The callback routine registered in the memory chain invokes the ipcns
+ * notifier chain with the IPCNS_MEMCHANGED event.
+ * Each callback routine registered in the ipcns namespace recomputes msgmni
+ * for the owning namespace.
+ */
+
+#include <linux/msg.h>
+#include <linux/rcupdate.h>
+#include <linux/notifier.h>
+#include <linux/nsproxy.h>
+#include <linux/ipc_namespace.h>
+
+#include "util.h"
+
+
+
+static BLOCKING_NOTIFIER_HEAD(ipcns_chain);
+
+
+static int ipcns_callback(struct notifier_block *self,
+ unsigned long action, void *arg)
+{
+ struct ipc_namespace *ns;
+
+ switch (action) {
+ case IPCNS_MEMCHANGED: /* amount of lowmem has changed */
+ case IPCNS_CREATED:
+ case IPCNS_REMOVED:
+ /*
+ * It's time to recompute msgmni
+ */
+ ns = container_of(self, struct ipc_namespace, ipcns_nb);
+ /*
+ * No need to get a reference on the ns: the 1st job of
+ * free_ipc_ns() is to unregister the callback routine.
+ * blocking_notifier_chain_unregister takes the wr lock to do
+ * it.
+ * When this callback routine is called the rd lock is held by
+ * blocking_notifier_call_chain.
+ * So the ipc ns cannot be freed while we are here.
+ */
+ recompute_msgmni(ns);
+ break;
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+int register_ipcns_notifier(struct ipc_namespace *ns)
+{
+ memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
+ ns->ipcns_nb.notifier_call = ipcns_callback;
+ ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
+ return blocking_notifier_chain_register(&ipcns_chain, &ns->ipcns_nb);
+}
+
+int cond_register_ipcns_notifier(struct ipc_namespace *ns)
+{
+ memset(&ns->ipcns_nb, 0, sizeof(ns->ipcns_nb));
+ ns->ipcns_nb.notifier_call = ipcns_callback;
+ ns->ipcns_nb.priority = IPCNS_CALLBACK_PRI;
+ return blocking_notifier_chain_cond_register(&ipcns_chain,
+ &ns->ipcns_nb);
+}
+
+int unregister_ipcns_notifier(struct ipc_namespace *ns)
+{
+ return blocking_notifier_chain_unregister(&ipcns_chain,
+ &ns->ipcns_nb);
+}
+
+int ipcns_notify(unsigned long val)
+{
+ return blocking_notifier_call_chain(&ipcns_chain, val, NULL);
+}
diff --git a/ipc/msg.c b/ipc/msg.c
index 46585a0..32494e8 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -27,6 +27,7 @@
#include <linux/msg.h>
#include <linux/spinlock.h>
#include <linux/init.h>
+#include <linux/mm.h>
#include <linux/proc_fs.h>
#include <linux/list.h>
#include <linux/security.h>
@@ -70,7 +71,6 @@
#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS])
#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
-#define msg_buildid(id, seq) ipc_buildid(id, seq)
static void freeque(struct ipc_namespace *, struct kern_ipc_perm *);
static int newque(struct ipc_namespace *, struct ipc_params *);
@@ -78,11 +78,49 @@
static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
#endif
+/*
+ * Scale msgmni with the available lowmem size: the memory dedicated to msg
+ * queues should occupy at most 1/MSG_MEM_SCALE of lowmem.
+ * Also take into account the number of nsproxies created so far.
+ * This should be done staying within the (MSGMNI , IPCMNI/nr_ipc_ns) range.
+ */
+void recompute_msgmni(struct ipc_namespace *ns)
+{
+ struct sysinfo i;
+ unsigned long allowed;
+ int nb_ns;
+
+ si_meminfo(&i);
+ allowed = (((i.totalram - i.totalhigh) / MSG_MEM_SCALE) * i.mem_unit)
+ / MSGMNB;
+ nb_ns = atomic_read(&nr_ipc_ns);
+ allowed /= nb_ns;
+
+ if (allowed < MSGMNI) {
+ ns->msg_ctlmni = MSGMNI;
+ goto out_callback;
+ }
+
+ if (allowed > IPCMNI / nb_ns) {
+ ns->msg_ctlmni = IPCMNI / nb_ns;
+ goto out_callback;
+ }
+
+ ns->msg_ctlmni = allowed;
+
+out_callback:
+
+ printk(KERN_INFO "msgmni has been set to %d for ipc namespace %p\n",
+ ns->msg_ctlmni, ns);
+}
+
void msg_init_ns(struct ipc_namespace *ns)
{
ns->msg_ctlmax = MSGMAX;
ns->msg_ctlmnb = MSGMNB;
- ns->msg_ctlmni = MSGMNI;
+
+ recompute_msgmni(ns);
+
atomic_set(&ns->msg_bytes, 0);
atomic_set(&ns->msg_hdrs, 0);
ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
@@ -104,21 +142,6 @@
}
/*
- * This routine is called in the paths where the rw_mutex is held to protect
- * access to the idr tree.
- */
-static inline struct msg_queue *msg_lock_check_down(struct ipc_namespace *ns,
- int id)
-{
- struct kern_ipc_perm *ipcp = ipc_lock_check_down(&msg_ids(ns), id);
-
- if (IS_ERR(ipcp))
- return (struct msg_queue *)ipcp;
-
- return container_of(ipcp, struct msg_queue, q_perm);
-}
-
-/*
* msg_lock_(check_) routines are called in the paths where the rw_mutex
* is not held.
*/
@@ -186,7 +209,6 @@
return id;
}
- msq->q_perm.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;
@@ -324,19 +346,19 @@
out.msg_rtime = in->msg_rtime;
out.msg_ctime = in->msg_ctime;
- if (in->msg_cbytes > USHRT_MAX)
- out.msg_cbytes = USHRT_MAX;
+ if (in->msg_cbytes > USHORT_MAX)
+ out.msg_cbytes = USHORT_MAX;
else
out.msg_cbytes = in->msg_cbytes;
out.msg_lcbytes = in->msg_cbytes;
- if (in->msg_qnum > USHRT_MAX)
- out.msg_qnum = USHRT_MAX;
+ if (in->msg_qnum > USHORT_MAX)
+ out.msg_qnum = USHORT_MAX;
else
out.msg_qnum = in->msg_qnum;
- if (in->msg_qbytes > USHRT_MAX)
- out.msg_qbytes = USHRT_MAX;
+ if (in->msg_qbytes > USHORT_MAX)
+ out.msg_qbytes = USHORT_MAX;
else
out.msg_qbytes = in->msg_qbytes;
out.msg_lqbytes = in->msg_qbytes;
@@ -351,31 +373,14 @@
}
}
-struct msq_setbuf {
- unsigned long qbytes;
- uid_t uid;
- gid_t gid;
- mode_t mode;
-};
-
static inline unsigned long
-copy_msqid_from_user(struct msq_setbuf *out, void __user *buf, int version)
+copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
{
switch(version) {
case IPC_64:
- {
- struct msqid64_ds tbuf;
-
- if (copy_from_user(&tbuf, buf, sizeof(tbuf)))
+ if (copy_from_user(out, buf, sizeof(*out)))
return -EFAULT;
-
- out->qbytes = tbuf.msg_qbytes;
- out->uid = tbuf.msg_perm.uid;
- out->gid = tbuf.msg_perm.gid;
- out->mode = tbuf.msg_perm.mode;
-
return 0;
- }
case IPC_OLD:
{
struct msqid_ds tbuf_old;
@@ -383,14 +388,14 @@
if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
return -EFAULT;
- out->uid = tbuf_old.msg_perm.uid;
- out->gid = tbuf_old.msg_perm.gid;
- out->mode = tbuf_old.msg_perm.mode;
+ out->msg_perm.uid = tbuf_old.msg_perm.uid;
+ out->msg_perm.gid = tbuf_old.msg_perm.gid;
+ out->msg_perm.mode = tbuf_old.msg_perm.mode;
if (tbuf_old.msg_qbytes == 0)
- out->qbytes = tbuf_old.msg_lqbytes;
+ out->msg_qbytes = tbuf_old.msg_lqbytes;
else
- out->qbytes = tbuf_old.msg_qbytes;
+ out->msg_qbytes = tbuf_old.msg_qbytes;
return 0;
}
@@ -399,10 +404,71 @@
}
}
-asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
+/*
+ * This function handles some msgctl commands which require the rw_mutex
+ * to be held in write mode.
+ * NOTE: no locks must be held, the rw_mutex is taken inside this function.
+ */
+static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
+ struct msqid_ds __user *buf, int version)
{
struct kern_ipc_perm *ipcp;
- struct msq_setbuf uninitialized_var(setbuf);
+ struct msqid64_ds msqid64;
+ struct msg_queue *msq;
+ int err;
+
+ if (cmd == IPC_SET) {
+ if (copy_msqid_from_user(&msqid64, buf, version))
+ return -EFAULT;
+ }
+
+ ipcp = ipcctl_pre_down(&msg_ids(ns), msqid, cmd,
+ &msqid64.msg_perm, msqid64.msg_qbytes);
+ if (IS_ERR(ipcp))
+ return PTR_ERR(ipcp);
+
+ msq = container_of(ipcp, struct msg_queue, q_perm);
+
+ err = security_msg_queue_msgctl(msq, cmd);
+ if (err)
+ goto out_unlock;
+
+ switch (cmd) {
+ case IPC_RMID:
+ freeque(ns, ipcp);
+ goto out_up;
+ case IPC_SET:
+ if (msqid64.msg_qbytes > ns->msg_ctlmnb &&
+ !capable(CAP_SYS_RESOURCE)) {
+ err = -EPERM;
+ goto out_unlock;
+ }
+
+ msq->q_qbytes = msqid64.msg_qbytes;
+
+ ipc_update_perm(&msqid64.msg_perm, ipcp);
+ msq->q_ctime = get_seconds();
+ /* sleeping receivers might be excluded by
+ * stricter permissions.
+ */
+ expunge_all(msq, -EAGAIN);
+ /* sleeping senders might be able to send
+ * due to a larger queue size.
+ */
+ ss_wakeup(&msq->q_senders, 0);
+ break;
+ default:
+ err = -EINVAL;
+ }
+out_unlock:
+ msg_unlock(msq);
+out_up:
+ up_write(&msg_ids(ns).rw_mutex);
+ return err;
+}
+
+asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
+{
struct msg_queue *msq;
int err, version;
struct ipc_namespace *ns;
@@ -498,82 +564,13 @@
return success_return;
}
case IPC_SET:
- if (!buf)
- return -EFAULT;
- if (copy_msqid_from_user(&setbuf, buf, version))
- return -EFAULT;
- break;
case IPC_RMID:
- break;
+ err = msgctl_down(ns, msqid, cmd, buf, version);
+ return err;
default:
return -EINVAL;
}
- down_write(&msg_ids(ns).rw_mutex);
- msq = msg_lock_check_down(ns, msqid);
- if (IS_ERR(msq)) {
- err = PTR_ERR(msq);
- goto out_up;
- }
-
- ipcp = &msq->q_perm;
-
- err = audit_ipc_obj(ipcp);
- if (err)
- goto out_unlock_up;
- if (cmd == IPC_SET) {
- err = audit_ipc_set_perm(setbuf.qbytes, setbuf.uid, setbuf.gid,
- setbuf.mode);
- if (err)
- goto out_unlock_up;
- }
-
- err = -EPERM;
- if (current->euid != ipcp->cuid &&
- current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
- /* We _could_ check for CAP_CHOWN above, but we don't */
- goto out_unlock_up;
-
- err = security_msg_queue_msgctl(msq, cmd);
- if (err)
- goto out_unlock_up;
-
- switch (cmd) {
- case IPC_SET:
- {
- err = -EPERM;
- if (setbuf.qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
- goto out_unlock_up;
-
- msq->q_qbytes = setbuf.qbytes;
-
- ipcp->uid = setbuf.uid;
- ipcp->gid = setbuf.gid;
- ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
- (S_IRWXUGO & setbuf.mode);
- msq->q_ctime = get_seconds();
- /* sleeping receivers might be excluded by
- * stricter permissions.
- */
- expunge_all(msq, -EAGAIN);
- /* sleeping senders might be able to send
- * due to a larger queue size.
- */
- ss_wakeup(&msq->q_senders, 0);
- msg_unlock(msq);
- break;
- }
- case IPC_RMID:
- freeque(ns, &msq->q_perm);
- break;
- }
- err = 0;
-out_up:
- up_write(&msg_ids(ns).rw_mutex);
- return err;
-out_unlock_up:
- msg_unlock(msq);
- goto out_up;
out_unlock:
msg_unlock(msq);
return err;
diff --git a/ipc/namespace.c b/ipc/namespace.c
index 1b96765..9171d94 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -20,10 +20,20 @@
if (ns == NULL)
return ERR_PTR(-ENOMEM);
+ atomic_inc(&nr_ipc_ns);
+
sem_init_ns(ns);
msg_init_ns(ns);
shm_init_ns(ns);
+ /*
+ * msgmni has already been computed for the new ipc ns.
+ * Thus, do the ipcns creation notification before registering that
+ * new ipcns in the chain.
+ */
+ ipcns_notify(IPCNS_CREATED);
+ register_ipcns_notifier(ns);
+
kref_init(&ns->kref);
return ns;
}
@@ -79,8 +89,24 @@
struct ipc_namespace *ns;
ns = container_of(kref, struct ipc_namespace, kref);
+ /*
+ * Unregistering the hotplug notifier at the beginning guarantees
+ * that the ipc namespace won't be freed while we are inside the
+ * callback routine. Since the blocking_notifier_chain_XXX routines
+ * hold a rw lock on the notifier list, unregister_ipcns_notifier()
+ * won't take the rw lock before blocking_notifier_call_chain() has
+ * released the rd lock.
+ */
+ unregister_ipcns_notifier(ns);
sem_exit_ns(ns);
msg_exit_ns(ns);
shm_exit_ns(ns);
kfree(ns);
+ atomic_dec(&nr_ipc_ns);
+
+ /*
+ * Do the ipcns removal notification after decrementing nr_ipc_ns in
+ * order to have a correct value when recomputing msgmni.
+ */
+ ipcns_notify(IPCNS_REMOVED);
}
diff --git a/ipc/sem.c b/ipc/sem.c
index 0b45a4d..e9418df 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -91,7 +91,6 @@
#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
#define sem_checkid(sma, semid) ipc_checkid(&sma->sem_perm, semid)
-#define sem_buildid(id, seq) ipc_buildid(id, seq)
static int newary(struct ipc_namespace *, struct ipc_params *);
static void freeary(struct ipc_namespace *, struct kern_ipc_perm *);
@@ -142,21 +141,6 @@
}
/*
- * This routine is called in the paths where the rw_mutex is held to protect
- * access to the idr tree.
- */
-static inline struct sem_array *sem_lock_check_down(struct ipc_namespace *ns,
- int id)
-{
- struct kern_ipc_perm *ipcp = ipc_lock_check_down(&sem_ids(ns), id);
-
- if (IS_ERR(ipcp))
- return (struct sem_array *)ipcp;
-
- return container_of(ipcp, struct sem_array, sem_perm);
-}
-
-/*
* sem_lock_(check_) routines are called in the paths where the rw_mutex
* is not held.
*/
@@ -181,6 +165,25 @@
return container_of(ipcp, struct sem_array, sem_perm);
}
+static inline void sem_lock_and_putref(struct sem_array *sma)
+{
+ ipc_lock_by_ptr(&sma->sem_perm);
+ ipc_rcu_putref(sma);
+}
+
+static inline void sem_getref_and_unlock(struct sem_array *sma)
+{
+ ipc_rcu_getref(sma);
+ ipc_unlock(&(sma)->sem_perm);
+}
+
+static inline void sem_putref(struct sem_array *sma)
+{
+ ipc_lock_by_ptr(&sma->sem_perm);
+ ipc_rcu_putref(sma);
+ ipc_unlock(&(sma)->sem_perm);
+}
+
static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
{
ipc_rmid(&sem_ids(ns), &s->sem_perm);
@@ -268,7 +271,6 @@
}
ns->used_sems += nsems;
- sma->sem_perm.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;
@@ -700,19 +702,15 @@
int i;
if(nsems > SEMMSL_FAST) {
- ipc_rcu_getref(sma);
- sem_unlock(sma);
+ sem_getref_and_unlock(sma);
sem_io = ipc_alloc(sizeof(ushort)*nsems);
if(sem_io == NULL) {
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
- sem_unlock(sma);
+ sem_putref(sma);
return -ENOMEM;
}
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
+ sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
sem_unlock(sma);
err = -EIDRM;
@@ -733,38 +731,30 @@
int i;
struct sem_undo *un;
- ipc_rcu_getref(sma);
- sem_unlock(sma);
+ sem_getref_and_unlock(sma);
if(nsems > SEMMSL_FAST) {
sem_io = ipc_alloc(sizeof(ushort)*nsems);
if(sem_io == NULL) {
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
- sem_unlock(sma);
+ sem_putref(sma);
return -ENOMEM;
}
}
if (copy_from_user (sem_io, arg.array, nsems*sizeof(ushort))) {
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
- sem_unlock(sma);
+ sem_putref(sma);
err = -EFAULT;
goto out_free;
}
for (i = 0; i < nsems; i++) {
if (sem_io[i] > SEMVMX) {
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
- sem_unlock(sma);
+ sem_putref(sma);
err = -ERANGE;
goto out_free;
}
}
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
+ sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
sem_unlock(sma);
err = -EIDRM;
@@ -830,28 +820,14 @@
return err;
}
-struct sem_setbuf {
- uid_t uid;
- gid_t gid;
- mode_t mode;
-};
-
-static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __user *buf, int version)
+static inline unsigned long
+copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
{
switch(version) {
case IPC_64:
- {
- struct semid64_ds tbuf;
-
- if(copy_from_user(&tbuf, buf, sizeof(tbuf)))
+ if (copy_from_user(out, buf, sizeof(*out)))
return -EFAULT;
-
- out->uid = tbuf.sem_perm.uid;
- out->gid = tbuf.sem_perm.gid;
- out->mode = tbuf.sem_perm.mode;
-
return 0;
- }
case IPC_OLD:
{
struct semid_ds tbuf_old;
@@ -859,9 +835,9 @@
if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
return -EFAULT;
- out->uid = tbuf_old.sem_perm.uid;
- out->gid = tbuf_old.sem_perm.gid;
- out->mode = tbuf_old.sem_perm.mode;
+ out->sem_perm.uid = tbuf_old.sem_perm.uid;
+ out->sem_perm.gid = tbuf_old.sem_perm.gid;
+ out->sem_perm.mode = tbuf_old.sem_perm.mode;
return 0;
}
@@ -870,38 +846,29 @@
}
}
-static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
- int cmd, int version, union semun arg)
+/*
+ * This function handles some semctl commands which require the rw_mutex
+ * to be held in write mode.
+ * NOTE: no locks must be held, the rw_mutex is taken inside this function.
+ */
+static int semctl_down(struct ipc_namespace *ns, int semid,
+ int cmd, int version, union semun arg)
{
struct sem_array *sma;
int err;
- struct sem_setbuf uninitialized_var(setbuf);
+ struct semid64_ds semid64;
struct kern_ipc_perm *ipcp;
if(cmd == IPC_SET) {
- if(copy_semid_from_user (&setbuf, arg.buf, version))
+ if (copy_semid_from_user(&semid64, arg.buf, version))
return -EFAULT;
}
- sma = sem_lock_check_down(ns, semid);
- if (IS_ERR(sma))
- return PTR_ERR(sma);
- ipcp = &sma->sem_perm;
+ ipcp = ipcctl_pre_down(&sem_ids(ns), semid, cmd, &semid64.sem_perm, 0);
+ if (IS_ERR(ipcp))
+ return PTR_ERR(ipcp);
- err = audit_ipc_obj(ipcp);
- if (err)
- goto out_unlock;
-
- if (cmd == IPC_SET) {
- err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode);
- if (err)
- goto out_unlock;
- }
- if (current->euid != ipcp->cuid &&
- current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
- err=-EPERM;
- goto out_unlock;
- }
+ sma = container_of(ipcp, struct sem_array, sem_perm);
err = security_sem_semctl(sma, cmd);
if (err)
@@ -910,26 +877,19 @@
switch(cmd){
case IPC_RMID:
freeary(ns, ipcp);
- err = 0;
- break;
+ goto out_up;
case IPC_SET:
- ipcp->uid = setbuf.uid;
- ipcp->gid = setbuf.gid;
- ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
- | (setbuf.mode & S_IRWXUGO);
+ ipc_update_perm(&semid64.sem_perm, ipcp);
sma->sem_ctime = get_seconds();
- sem_unlock(sma);
- err = 0;
break;
default:
- sem_unlock(sma);
err = -EINVAL;
- break;
}
- return err;
out_unlock:
sem_unlock(sma);
+out_up:
+ up_write(&sem_ids(ns).rw_mutex);
return err;
}
@@ -963,9 +923,7 @@
return err;
case IPC_RMID:
case IPC_SET:
- down_write(&sem_ids(ns).rw_mutex);
- err = semctl_down(ns,semid,semnum,cmd,version,arg);
- up_write(&sem_ids(ns).rw_mutex);
+ err = semctl_down(ns, semid, cmd, version, arg);
return err;
default:
return -EINVAL;
@@ -1044,14 +1002,11 @@
return ERR_PTR(PTR_ERR(sma));
nsems = sma->sem_nsems;
- ipc_rcu_getref(sma);
- sem_unlock(sma);
+ sem_getref_and_unlock(sma);
new = kzalloc(sizeof(struct sem_undo) + sizeof(short)*nsems, GFP_KERNEL);
if (!new) {
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
- sem_unlock(sma);
+ sem_putref(sma);
return ERR_PTR(-ENOMEM);
}
new->semadj = (short *) &new[1];
@@ -1062,13 +1017,10 @@
if (un) {
spin_unlock(&ulp->lock);
kfree(new);
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
- sem_unlock(sma);
+ sem_putref(sma);
goto out;
}
- ipc_lock_by_ptr(&sma->sem_perm);
- ipc_rcu_putref(sma);
+ sem_lock_and_putref(sma);
if (sma->sem_perm.deleted) {
sem_unlock(sma);
spin_unlock(&ulp->lock);
@@ -1298,6 +1250,7 @@
undo_list = tsk->sysvsem.undo_list;
if (!undo_list)
return;
+ tsk->sysvsem.undo_list = NULL;
if (!atomic_dec_and_test(&undo_list->refcnt))
return;
diff --git a/ipc/shm.c b/ipc/shm.c
index e636910..554429a 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -60,7 +60,6 @@
#define shm_unlock(shp) \
ipc_unlock(&(shp)->shm_perm)
-#define shm_buildid(id, seq) ipc_buildid(id, seq)
static int newseg(struct ipc_namespace *, struct ipc_params *);
static void shm_open(struct vm_area_struct *vma);
@@ -127,18 +126,6 @@
return container_of(ipcp, struct shmid_kernel, shm_perm);
}
-static inline struct shmid_kernel *shm_lock_check_down(
- struct ipc_namespace *ns,
- int id)
-{
- struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id);
-
- if (IS_ERR(ipcp))
- return (struct shmid_kernel *)ipcp;
-
- return container_of(ipcp, struct shmid_kernel, shm_perm);
-}
-
/*
* shm_lock_(check_) routines are called in the paths where the rw_mutex
* is not held.
@@ -169,12 +156,6 @@
ipc_rmid(&shm_ids(ns), &s->shm_perm);
}
-static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp)
-{
- return ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
-}
-
-
/* This is called by fork, once for every shm attach. */
static void shm_open(struct vm_area_struct *vma)
@@ -416,7 +397,7 @@
if (IS_ERR(file))
goto no_file;
- id = shm_addid(ns, shp);
+ id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
if (id < 0) {
error = id;
goto no_id;
@@ -428,7 +409,6 @@
shp->shm_ctim = get_seconds();
shp->shm_segsz = size;
shp->shm_nattch = 0;
- shp->shm_perm.id = shm_buildid(id, shp->shm_perm.seq);
shp->shm_file = file;
/*
* shmid gets reported as "inode#" in /proc/pid/maps.
@@ -519,28 +499,14 @@
}
}
-struct shm_setbuf {
- uid_t uid;
- gid_t gid;
- mode_t mode;
-};
-
-static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __user *buf, int version)
+static inline unsigned long
+copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version)
{
switch(version) {
case IPC_64:
- {
- struct shmid64_ds tbuf;
-
- if (copy_from_user(&tbuf, buf, sizeof(tbuf)))
+ if (copy_from_user(out, buf, sizeof(*out)))
return -EFAULT;
-
- out->uid = tbuf.shm_perm.uid;
- out->gid = tbuf.shm_perm.gid;
- out->mode = tbuf.shm_perm.mode;
-
return 0;
- }
case IPC_OLD:
{
struct shmid_ds tbuf_old;
@@ -548,9 +514,9 @@
if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
return -EFAULT;
- out->uid = tbuf_old.shm_perm.uid;
- out->gid = tbuf_old.shm_perm.gid;
- out->mode = tbuf_old.shm_perm.mode;
+ out->shm_perm.uid = tbuf_old.shm_perm.uid;
+ out->shm_perm.gid = tbuf_old.shm_perm.gid;
+ out->shm_perm.mode = tbuf_old.shm_perm.mode;
return 0;
}
@@ -624,9 +590,53 @@
}
}
-asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
+/*
+ * This function handles some shmctl commands which require the rw_mutex
+ * to be held in write mode.
+ * NOTE: no locks must be held, the rw_mutex is taken inside this function.
+ */
+static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
+ struct shmid_ds __user *buf, int version)
{
- struct shm_setbuf setbuf;
+ struct kern_ipc_perm *ipcp;
+ struct shmid64_ds shmid64;
+ struct shmid_kernel *shp;
+ int err;
+
+ if (cmd == IPC_SET) {
+ if (copy_shmid_from_user(&shmid64, buf, version))
+ return -EFAULT;
+ }
+
+ ipcp = ipcctl_pre_down(&shm_ids(ns), shmid, cmd, &shmid64.shm_perm, 0);
+ if (IS_ERR(ipcp))
+ return PTR_ERR(ipcp);
+
+ shp = container_of(ipcp, struct shmid_kernel, shm_perm);
+
+ err = security_shm_shmctl(shp, cmd);
+ if (err)
+ goto out_unlock;
+ switch (cmd) {
+ case IPC_RMID:
+ do_shm_rmid(ns, ipcp);
+ goto out_up;
+ case IPC_SET:
+ ipc_update_perm(&shmid64.shm_perm, ipcp);
+ shp->shm_ctim = get_seconds();
+ break;
+ default:
+ err = -EINVAL;
+ }
+out_unlock:
+ shm_unlock(shp);
+out_up:
+ up_write(&shm_ids(ns).rw_mutex);
+ return err;
+}
+
+asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
+{
struct shmid_kernel *shp;
int err, version;
struct ipc_namespace *ns;
@@ -783,97 +793,13 @@
goto out;
}
case IPC_RMID:
- {
- /*
- * We cannot simply remove the file. The SVID states
- * that the block remains until the last person
- * detaches from it, then is deleted. A shmat() on
- * an RMID segment is legal in older Linux and if
- * we change it apps break...
- *
- * Instead we set a destroyed flag, and then blow
- * the name away when the usage hits zero.
- */
- down_write(&shm_ids(ns).rw_mutex);
- shp = shm_lock_check_down(ns, shmid);
- if (IS_ERR(shp)) {
- err = PTR_ERR(shp);
- goto out_up;
- }
-
- err = audit_ipc_obj(&(shp->shm_perm));
- if (err)
- goto out_unlock_up;
-
- if (current->euid != shp->shm_perm.uid &&
- current->euid != shp->shm_perm.cuid &&
- !capable(CAP_SYS_ADMIN)) {
- err=-EPERM;
- goto out_unlock_up;
- }
-
- err = security_shm_shmctl(shp, cmd);
- if (err)
- goto out_unlock_up;
-
- do_shm_rmid(ns, &shp->shm_perm);
- up_write(&shm_ids(ns).rw_mutex);
- goto out;
- }
-
case IPC_SET:
- {
- if (!buf) {
- err = -EFAULT;
- goto out;
- }
-
- if (copy_shmid_from_user (&setbuf, buf, version)) {
- err = -EFAULT;
- goto out;
- }
- down_write(&shm_ids(ns).rw_mutex);
- shp = shm_lock_check_down(ns, shmid);
- if (IS_ERR(shp)) {
- err = PTR_ERR(shp);
- goto out_up;
- }
- err = audit_ipc_obj(&(shp->shm_perm));
- if (err)
- goto out_unlock_up;
- err = audit_ipc_set_perm(0, setbuf.uid, setbuf.gid, setbuf.mode);
- if (err)
- goto out_unlock_up;
- err=-EPERM;
- if (current->euid != shp->shm_perm.uid &&
- current->euid != shp->shm_perm.cuid &&
- !capable(CAP_SYS_ADMIN)) {
- goto out_unlock_up;
- }
-
- err = security_shm_shmctl(shp, cmd);
- if (err)
- goto out_unlock_up;
-
- shp->shm_perm.uid = setbuf.uid;
- shp->shm_perm.gid = setbuf.gid;
- shp->shm_perm.mode = (shp->shm_perm.mode & ~S_IRWXUGO)
- | (setbuf.mode & S_IRWXUGO);
- shp->shm_ctim = get_seconds();
- break;
- }
-
+ err = shmctl_down(ns, shmid, cmd, buf, version);
+ return err;
default:
- err = -EINVAL;
- goto out;
+ return -EINVAL;
}
- err = 0;
-out_unlock_up:
- shm_unlock(shp);
-out_up:
- up_write(&shm_ids(ns).rw_mutex);
- goto out;
out_unlock:
shm_unlock(shp);
out:
diff --git a/ipc/util.c b/ipc/util.c
index fd1b50d..3339177 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -33,6 +33,7 @@
#include <linux/audit.h>
#include <linux/nsproxy.h>
#include <linux/rwsem.h>
+#include <linux/memory.h>
#include <linux/ipc_namespace.h>
#include <asm/unistd.h>
@@ -52,11 +53,57 @@
},
};
+atomic_t nr_ipc_ns = ATOMIC_INIT(1);
+
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+
+static void ipc_memory_notifier(struct work_struct *work)
+{
+ ipcns_notify(IPCNS_MEMCHANGED);
+}
+
+static DECLARE_WORK(ipc_memory_wq, ipc_memory_notifier);
+
+
+static int ipc_memory_callback(struct notifier_block *self,
+ unsigned long action, void *arg)
+{
+ switch (action) {
+ case MEM_ONLINE: /* memory successfully brought online */
+ case MEM_OFFLINE: /* or offline: it's time to recompute msgmni */
+ /*
+ * This is done by invoking the ipcns notifier chain with the
+ * IPC_MEMCHANGED event.
+ * In order not to keep the lock on the hotplug memory chain
+ * for too long, queue a work item that will, when waken up,
+ * activate the ipcns notification chain.
+ * No need to keep several ipc work items on the queue.
+ */
+ if (!work_pending(&ipc_memory_wq))
+ schedule_work(&ipc_memory_wq);
+ break;
+ case MEM_GOING_ONLINE:
+ case MEM_GOING_OFFLINE:
+ case MEM_CANCEL_ONLINE:
+ case MEM_CANCEL_OFFLINE:
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
/**
* ipc_init - initialise IPC subsystem
*
* The various system5 IPC resources (semaphores, messages and shared
* memory) are initialised
+ * A callback routine is registered into the memory hotplug notifier
+ * chain: since msgmni scales to lowmem this callback routine will be
+ * called upon successful memory add / remove to recompute msmgni.
*/
static int __init ipc_init(void)
@@ -64,6 +111,8 @@
sem_init();
msg_init();
shm_init();
+ hotplug_memory_notifier(ipc_memory_callback, IPC_CALLBACK_PRI);
+ register_ipcns_notifier(&init_ipc_ns);
return 0;
}
__initcall(ipc_init);
@@ -84,8 +133,8 @@
ids->seq = 0;
{
int seq_limit = INT_MAX/SEQ_MULTIPLIER;
- if(seq_limit > USHRT_MAX)
- ids->seq_max = USHRT_MAX;
+ if (seq_limit > USHORT_MAX)
+ ids->seq_max = USHORT_MAX;
else
ids->seq_max = seq_limit;
}
@@ -116,13 +165,12 @@
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 {
+ pde = proc_create_data(path,
+ S_IRUGO, /* world readable */
+ NULL, /* parent dir */
+ &sysvipc_proc_fops,
+ iface);
+ if (!pde) {
kfree(iface);
}
}
@@ -231,6 +279,7 @@
if(ids->seq > ids->seq_max)
ids->seq = 0;
+ new->id = ipc_buildid(id, new->seq);
spin_lock_init(&new->lock);
new->deleted = 0;
rcu_read_lock();
@@ -761,6 +810,70 @@
return ipcget_public(ns, ids, ops, params);
}
+/**
+ * ipc_update_perm - update the permissions of an IPC.
+ * @in: the permission given as input.
+ * @out: the permission of the ipc to set.
+ */
+void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
+{
+ out->uid = in->uid;
+ out->gid = in->gid;
+ out->mode = (out->mode & ~S_IRWXUGO)
+ | (in->mode & S_IRWXUGO);
+}
+
+/**
+ * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
+ * @ids: the table of ids where to look for the ipc
+ * @id: the id of the ipc to retrieve
+ * @cmd: the cmd to check
+ * @perm: the permission to set
+ * @extra_perm: one extra permission parameter used by msq
+ *
+ * This function does some common audit and permissions check for some IPC_XXX
+ * cmd and is called from semctl_down, shmctl_down and msgctl_down.
+ * It must be called without any lock held and
+ * - retrieves the ipc with the given id in the given table.
+ * - performs some audit and permission check, depending on the given cmd
+ * - returns the ipc with both ipc and rw_mutex locks held in case of success
+ * or an err-code without any lock held otherwise.
+ */
+struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
+ struct ipc64_perm *perm, int extra_perm)
+{
+ struct kern_ipc_perm *ipcp;
+ int err;
+
+ down_write(&ids->rw_mutex);
+ ipcp = ipc_lock_check_down(ids, id);
+ if (IS_ERR(ipcp)) {
+ err = PTR_ERR(ipcp);
+ goto out_up;
+ }
+
+ err = audit_ipc_obj(ipcp);
+ if (err)
+ goto out_unlock;
+
+ if (cmd == IPC_SET) {
+ err = audit_ipc_set_perm(extra_perm, perm->uid,
+ perm->gid, perm->mode);
+ if (err)
+ goto out_unlock;
+ }
+ if (current->euid == ipcp->cuid ||
+ current->euid == ipcp->uid || capable(CAP_SYS_ADMIN))
+ return ipcp;
+
+ err = -EPERM;
+out_unlock:
+ ipc_unlock(ipcp);
+out_up:
+ up_write(&ids->rw_mutex);
+ return ERR_PTR(err);
+}
+
#ifdef __ARCH_WANT_IPC_PARSE_VERSION
diff --git a/ipc/util.h b/ipc/util.h
index f37d160..cdb966a 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -12,7 +12,6 @@
#include <linux/err.h>
-#define USHRT_MAX 0xffff
#define SEQ_MULTIPLIER (IPCMNI)
void sem_init (void);
@@ -112,6 +111,9 @@
void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
+void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
+struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
+ struct ipc64_perm *perm, int extra_perm);
#if defined(__ia64__) || defined(__x86_64__) || defined(__hppa__) || defined(__XTENSA__)
/* On IA-64, we always use the "64-bit version" of the IPC structures. */
@@ -124,6 +126,8 @@
extern struct msg_msg *load_msg(const void __user *src, int len);
extern int store_msg(void __user *dest, struct msg_msg *msg, int len);
+extern void recompute_msgmni(struct ipc_namespace *);
+
static inline int ipc_buildid(int id, int seq)
{
return SEQ_MULTIPLIER * seq + id;
diff --git a/kernel/Makefile b/kernel/Makefile
index 6c5f081..188c432 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -11,7 +11,7 @@
hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
notifier.o ksysfs.o pm_qos_params.o
-obj-$(CONFIG_SYSCTL) += sysctl_check.o
+obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sysctl_check.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += time/
obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
diff --git a/kernel/audit.c b/kernel/audit.c
index a7b1608..b7d3709 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -126,6 +126,8 @@
static LIST_HEAD(audit_freelist);
static struct sk_buff_head audit_skb_queue;
+/* queue of skbs to send to auditd when/if it comes back */
+static struct sk_buff_head audit_skb_hold_queue;
static struct task_struct *kauditd_task;
static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
@@ -154,6 +156,11 @@
gfp_t gfp_mask;
};
+struct audit_reply {
+ int pid;
+ struct sk_buff *skb;
+};
+
static void audit_set_pid(struct audit_buffer *ab, pid_t pid)
{
if (ab) {
@@ -252,14 +259,15 @@
}
static int audit_log_config_change(char *function_name, int new, int old,
- uid_t loginuid, u32 sid, int allow_changes)
+ uid_t loginuid, u32 sessionid, u32 sid,
+ int allow_changes)
{
struct audit_buffer *ab;
int rc = 0;
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
- audit_log_format(ab, "%s=%d old=%d by auid=%u", function_name, new,
- old, loginuid);
+ audit_log_format(ab, "%s=%d old=%d auid=%u ses=%u", function_name, new,
+ old, loginuid, sessionid);
if (sid) {
char *ctx = NULL;
u32 len;
@@ -279,7 +287,8 @@
}
static int audit_do_config_change(char *function_name, int *to_change,
- int new, uid_t loginuid, u32 sid)
+ int new, uid_t loginuid, u32 sessionid,
+ u32 sid)
{
int allow_changes, rc = 0, old = *to_change;
@@ -290,8 +299,8 @@
allow_changes = 1;
if (audit_enabled != AUDIT_OFF) {
- rc = audit_log_config_change(function_name, new, old,
- loginuid, sid, allow_changes);
+ rc = audit_log_config_change(function_name, new, old, loginuid,
+ sessionid, sid, allow_changes);
if (rc)
allow_changes = 0;
}
@@ -305,26 +314,28 @@
return rc;
}
-static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sid)
+static int audit_set_rate_limit(int limit, uid_t loginuid, u32 sessionid,
+ u32 sid)
{
return audit_do_config_change("audit_rate_limit", &audit_rate_limit,
- limit, loginuid, sid);
+ limit, loginuid, sessionid, sid);
}
-static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sid)
+static int audit_set_backlog_limit(int limit, uid_t loginuid, u32 sessionid,
+ u32 sid)
{
return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit,
- limit, loginuid, sid);
+ limit, loginuid, sessionid, sid);
}
-static int audit_set_enabled(int state, uid_t loginuid, u32 sid)
+static int audit_set_enabled(int state, uid_t loginuid, u32 sessionid, u32 sid)
{
int rc;
if (state < AUDIT_OFF || state > AUDIT_LOCKED)
return -EINVAL;
rc = audit_do_config_change("audit_enabled", &audit_enabled, state,
- loginuid, sid);
+ loginuid, sessionid, sid);
if (!rc)
audit_ever_enabled |= !!state;
@@ -332,7 +343,7 @@
return rc;
}
-static int audit_set_failure(int state, uid_t loginuid, u32 sid)
+static int audit_set_failure(int state, uid_t loginuid, u32 sessionid, u32 sid)
{
if (state != AUDIT_FAIL_SILENT
&& state != AUDIT_FAIL_PRINTK
@@ -340,7 +351,43 @@
return -EINVAL;
return audit_do_config_change("audit_failure", &audit_failure, state,
- loginuid, sid);
+ loginuid, sessionid, sid);
+}
+
+/*
+ * Queue skbs to be sent to auditd when/if it comes back. These skbs should
+ * already have been sent via prink/syslog and so if these messages are dropped
+ * it is not a huge concern since we already passed the audit_log_lost()
+ * notification and stuff. This is just nice to get audit messages during
+ * boot before auditd is running or messages generated while auditd is stopped.
+ * This only holds messages is audit_default is set, aka booting with audit=1
+ * or building your kernel that way.
+ */
+static void audit_hold_skb(struct sk_buff *skb)
+{
+ if (audit_default &&
+ skb_queue_len(&audit_skb_hold_queue) < audit_backlog_limit)
+ skb_queue_tail(&audit_skb_hold_queue, skb);
+ else
+ kfree_skb(skb);
+}
+
+static void kauditd_send_skb(struct sk_buff *skb)
+{
+ int err;
+ /* take a reference in case we can't send it and we want to hold it */
+ skb_get(skb);
+ err = netlink_unicast(audit_sock, skb, audit_nlk_pid, 0);
+ if (err < 0) {
+ BUG_ON(err != -ECONNREFUSED); /* Shoudn't happen */
+ printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid);
+ audit_log_lost("auditd dissapeared\n");
+ audit_pid = 0;
+ /* we might get lucky and get this in the next auditd */
+ audit_hold_skb(skb);
+ } else
+ /* drop the extra reference if sent ok */
+ kfree_skb(skb);
}
static int kauditd_thread(void *dummy)
@@ -349,24 +396,41 @@
set_freezable();
while (!kthread_should_stop()) {
+ /*
+ * if auditd just started drain the queue of messages already
+ * sent to syslog/printk. remember loss here is ok. we already
+ * called audit_log_lost() if it didn't go out normally. so the
+ * race between the skb_dequeue and the next check for audit_pid
+ * doesn't matter.
+ *
+ * if you ever find kauditd to be too slow we can get a perf win
+ * by doing our own locking and keeping better track if there
+ * are messages in this queue. I don't see the need now, but
+ * in 5 years when I want to play with this again I'll see this
+ * note and still have no friggin idea what i'm thinking today.
+ */
+ if (audit_default && audit_pid) {
+ skb = skb_dequeue(&audit_skb_hold_queue);
+ if (unlikely(skb)) {
+ while (skb && audit_pid) {
+ kauditd_send_skb(skb);
+ skb = skb_dequeue(&audit_skb_hold_queue);
+ }
+ }
+ }
+
skb = skb_dequeue(&audit_skb_queue);
wake_up(&audit_backlog_wait);
if (skb) {
- if (audit_pid) {
- int err = netlink_unicast(audit_sock, skb, audit_nlk_pid, 0);
- if (err < 0) {
- BUG_ON(err != -ECONNREFUSED); /* Shoudn't happen */
- printk(KERN_ERR "audit: *NO* daemon at audit_pid=%d\n", audit_pid);
- audit_log_lost("auditd dissapeared\n");
- audit_pid = 0;
- }
- } else {
+ if (audit_pid)
+ kauditd_send_skb(skb);
+ else {
if (printk_ratelimit())
- printk(KERN_NOTICE "%s\n", skb->data +
- NLMSG_SPACE(0));
+ printk(KERN_NOTICE "%s\n", skb->data + NLMSG_SPACE(0));
else
audit_log_lost("printk limit exceeded\n");
- kfree_skb(skb);
+
+ audit_hold_skb(skb);
}
} else {
DECLARE_WAITQUEUE(wait, current);
@@ -385,13 +449,13 @@
return 0;
}
-static int audit_prepare_user_tty(pid_t pid, uid_t loginuid)
+static int audit_prepare_user_tty(pid_t pid, uid_t loginuid, u32 sessionid)
{
struct task_struct *tsk;
int err;
read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
+ tsk = find_task_by_vpid(pid);
err = -ESRCH;
if (!tsk)
goto out;
@@ -404,7 +468,7 @@
if (err)
goto out;
- tty_audit_push_task(tsk, loginuid);
+ tty_audit_push_task(tsk, loginuid, sessionid);
out:
read_unlock(&tasklist_lock);
return err;
@@ -469,6 +533,19 @@
return NULL;
}
+static int audit_send_reply_thread(void *arg)
+{
+ struct audit_reply *reply = (struct audit_reply *)arg;
+
+ mutex_lock(&audit_cmd_mutex);
+ mutex_unlock(&audit_cmd_mutex);
+
+ /* Ignore failure. It'll only happen if the sender goes away,
+ because our timeout is set to infinite. */
+ netlink_unicast(audit_sock, reply->skb, reply->pid, 0);
+ kfree(reply);
+ return 0;
+}
/**
* audit_send_reply - send an audit reply message via netlink
* @pid: process id to send reply to
@@ -485,14 +562,26 @@
void audit_send_reply(int pid, int seq, int type, int done, int multi,
void *payload, int size)
{
- struct sk_buff *skb;
+ struct sk_buff *skb;
+ struct task_struct *tsk;
+ struct audit_reply *reply = kmalloc(sizeof(struct audit_reply),
+ GFP_KERNEL);
+
+ if (!reply)
+ return;
+
skb = audit_make_reply(pid, seq, type, done, multi, payload, size);
if (!skb)
return;
- /* Ignore failure. It'll only happen if the sender goes away,
- because our timeout is set to infinite. */
- netlink_unicast(audit_sock, skb, pid, 0);
- return;
+
+ reply->pid = pid;
+ reply->skb = skb;
+
+ tsk = kthread_run(audit_send_reply_thread, reply, "audit_send_reply");
+ if (IS_ERR(tsk)) {
+ kfree(reply);
+ kfree_skb(skb);
+ }
}
/*
@@ -534,7 +623,8 @@
}
static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,
- u32 pid, u32 uid, uid_t auid, u32 sid)
+ u32 pid, u32 uid, uid_t auid, u32 ses,
+ u32 sid)
{
int rc = 0;
char *ctx = NULL;
@@ -546,8 +636,8 @@
}
*ab = audit_log_start(NULL, GFP_KERNEL, msg_type);
- audit_log_format(*ab, "user pid=%d uid=%u auid=%u",
- pid, uid, auid);
+ audit_log_format(*ab, "user pid=%d uid=%u auid=%u ses=%u",
+ pid, uid, auid, ses);
if (sid) {
rc = security_secid_to_secctx(sid, &ctx, &len);
if (rc)
@@ -570,6 +660,7 @@
struct audit_buffer *ab;
u16 msg_type = nlh->nlmsg_type;
uid_t loginuid; /* loginuid of sender */
+ u32 sessionid;
struct audit_sig_info *sig_data;
char *ctx = NULL;
u32 len;
@@ -591,6 +682,7 @@
pid = NETLINK_CREDS(skb)->pid;
uid = NETLINK_CREDS(skb)->uid;
loginuid = NETLINK_CB(skb).loginuid;
+ sessionid = NETLINK_CB(skb).sessionid;
sid = NETLINK_CB(skb).sid;
seq = nlh->nlmsg_seq;
data = NLMSG_DATA(nlh);
@@ -613,12 +705,12 @@
status_get = (struct audit_status *)data;
if (status_get->mask & AUDIT_STATUS_ENABLED) {
err = audit_set_enabled(status_get->enabled,
- loginuid, sid);
+ loginuid, sessionid, sid);
if (err < 0) return err;
}
if (status_get->mask & AUDIT_STATUS_FAILURE) {
err = audit_set_failure(status_get->failure,
- loginuid, sid);
+ loginuid, sessionid, sid);
if (err < 0) return err;
}
if (status_get->mask & AUDIT_STATUS_PID) {
@@ -627,17 +719,17 @@
if (audit_enabled != AUDIT_OFF)
audit_log_config_change("audit_pid", new_pid,
audit_pid, loginuid,
- sid, 1);
+ sessionid, sid, 1);
audit_pid = new_pid;
audit_nlk_pid = NETLINK_CB(skb).pid;
}
if (status_get->mask & AUDIT_STATUS_RATE_LIMIT)
err = audit_set_rate_limit(status_get->rate_limit,
- loginuid, sid);
+ loginuid, sessionid, sid);
if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
err = audit_set_backlog_limit(status_get->backlog_limit,
- loginuid, sid);
+ loginuid, sessionid, sid);
break;
case AUDIT_USER:
case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
@@ -649,12 +741,13 @@
if (err == 1) {
err = 0;
if (msg_type == AUDIT_USER_TTY) {
- err = audit_prepare_user_tty(pid, loginuid);
+ err = audit_prepare_user_tty(pid, loginuid,
+ sessionid);
if (err)
break;
}
audit_log_common_recv_msg(&ab, msg_type, pid, uid,
- loginuid, sid);
+ loginuid, sessionid, sid);
if (msg_type != AUDIT_USER_TTY)
audit_log_format(ab, " msg='%.1024s'",
@@ -664,8 +757,7 @@
audit_log_format(ab, " msg=");
size = nlmsg_len(nlh);
- audit_log_n_untrustedstring(ab, size,
- data);
+ audit_log_n_untrustedstring(ab, data, size);
}
audit_set_pid(ab, pid);
audit_log_end(ab);
@@ -677,7 +769,7 @@
return -EINVAL;
if (audit_enabled == AUDIT_LOCKED) {
audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
- uid, loginuid, sid);
+ uid, loginuid, sessionid, sid);
audit_log_format(ab, " audit_enabled=%d res=0",
audit_enabled);
@@ -688,7 +780,7 @@
case AUDIT_LIST:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
uid, seq, data, nlmsg_len(nlh),
- loginuid, sid);
+ loginuid, sessionid, sid);
break;
case AUDIT_ADD_RULE:
case AUDIT_DEL_RULE:
@@ -696,7 +788,7 @@
return -EINVAL;
if (audit_enabled == AUDIT_LOCKED) {
audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
- uid, loginuid, sid);
+ uid, loginuid, sessionid, sid);
audit_log_format(ab, " audit_enabled=%d res=0",
audit_enabled);
@@ -707,13 +799,13 @@
case AUDIT_LIST_RULES:
err = audit_receive_filter(nlh->nlmsg_type, NETLINK_CB(skb).pid,
uid, seq, data, nlmsg_len(nlh),
- loginuid, sid);
+ loginuid, sessionid, sid);
break;
case AUDIT_TRIM:
audit_trim_trees();
audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
- uid, loginuid, sid);
+ uid, loginuid, sessionid, sid);
audit_log_format(ab, " op=trim res=1");
audit_log_end(ab);
@@ -721,21 +813,21 @@
case AUDIT_MAKE_EQUIV: {
void *bufp = data;
u32 sizes[2];
- size_t len = nlmsg_len(nlh);
+ size_t msglen = nlmsg_len(nlh);
char *old, *new;
err = -EINVAL;
- if (len < 2 * sizeof(u32))
+ if (msglen < 2 * sizeof(u32))
break;
memcpy(sizes, bufp, 2 * sizeof(u32));
bufp += 2 * sizeof(u32);
- len -= 2 * sizeof(u32);
- old = audit_unpack_string(&bufp, &len, sizes[0]);
+ msglen -= 2 * sizeof(u32);
+ old = audit_unpack_string(&bufp, &msglen, sizes[0]);
if (IS_ERR(old)) {
err = PTR_ERR(old);
break;
}
- new = audit_unpack_string(&bufp, &len, sizes[1]);
+ new = audit_unpack_string(&bufp, &msglen, sizes[1]);
if (IS_ERR(new)) {
err = PTR_ERR(new);
kfree(old);
@@ -745,7 +837,7 @@
err = audit_tag_tree(old, new);
audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, pid,
- uid, loginuid, sid);
+ uid, loginuid, sessionid, sid);
audit_log_format(ab, " op=make_equiv old=");
audit_log_untrustedstring(ab, old);
@@ -779,7 +871,7 @@
struct task_struct *tsk;
read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
+ tsk = find_task_by_vpid(pid);
if (!tsk)
err = -ESRCH;
else {
@@ -802,7 +894,7 @@
if (s->enabled != 0 && s->enabled != 1)
return -EINVAL;
read_lock(&tasklist_lock);
- tsk = find_task_by_pid(pid);
+ tsk = find_task_by_vpid(pid);
if (!tsk)
err = -ESRCH;
else {
@@ -877,6 +969,7 @@
audit_sock->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT;
skb_queue_head_init(&audit_skb_queue);
+ skb_queue_head_init(&audit_skb_hold_queue);
audit_initialized = 1;
audit_enabled = audit_default;
audit_ever_enabled |= !!audit_default;
@@ -1199,7 +1292,7 @@
* This function will take the passed buf and convert it into a string of
* ascii hex digits. The new string is placed onto the skb.
*/
-void audit_log_hex(struct audit_buffer *ab, const unsigned char *buf,
+void audit_log_n_hex(struct audit_buffer *ab, const unsigned char *buf,
size_t len)
{
int i, avail, new_len;
@@ -1235,8 +1328,8 @@
* Format a string of no more than slen characters into the audit buffer,
* enclosed in quote marks.
*/
-static void audit_log_n_string(struct audit_buffer *ab, size_t slen,
- const char *string)
+void audit_log_n_string(struct audit_buffer *ab, const char *string,
+ size_t slen)
{
int avail, new_len;
unsigned char *ptr;
@@ -1292,13 +1385,13 @@
* The caller specifies the number of characters in the string to log, which may
* or may not be the entire string.
*/
-void audit_log_n_untrustedstring(struct audit_buffer *ab, size_t len,
- const char *string)
+void audit_log_n_untrustedstring(struct audit_buffer *ab, const char *string,
+ size_t len)
{
if (audit_string_contains_control(string, len))
- audit_log_hex(ab, string, len);
+ audit_log_n_hex(ab, string, len);
else
- audit_log_n_string(ab, len, string);
+ audit_log_n_string(ab, string, len);
}
/**
@@ -1311,7 +1404,7 @@
*/
void audit_log_untrustedstring(struct audit_buffer *ab, const char *string)
{
- audit_log_n_untrustedstring(ab, strlen(string), string);
+ audit_log_n_untrustedstring(ab, string, strlen(string));
}
/* This is a helper-function to print the escaped d_path */
@@ -1355,19 +1448,23 @@
audit_log_lost("rate limit exceeded");
} else {
struct nlmsghdr *nlh = nlmsg_hdr(ab->skb);
+ nlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0);
+
if (audit_pid) {
- nlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0);
skb_queue_tail(&audit_skb_queue, ab->skb);
- ab->skb = NULL;
wake_up_interruptible(&kauditd_wait);
- } else if (nlh->nlmsg_type != AUDIT_EOE) {
- if (printk_ratelimit()) {
- printk(KERN_NOTICE "type=%d %s\n",
- nlh->nlmsg_type,
- ab->skb->data + NLMSG_SPACE(0));
- } else
- audit_log_lost("printk limit exceeded\n");
+ } else {
+ if (nlh->nlmsg_type != AUDIT_EOE) {
+ if (printk_ratelimit()) {
+ printk(KERN_NOTICE "type=%d %s\n",
+ nlh->nlmsg_type,
+ ab->skb->data + NLMSG_SPACE(0));
+ } else
+ audit_log_lost("printk limit exceeded\n");
+ }
+ audit_hold_skb(ab->skb);
}
+ ab->skb = NULL;
}
audit_buffer_free(ab);
}
diff --git a/kernel/audit.h b/kernel/audit.h
index 3cfc54e..9d67174 100644
--- a/kernel/audit.h
+++ b/kernel/audit.h
@@ -74,6 +74,11 @@
struct audit_krule rule;
};
+#ifdef CONFIG_AUDIT
+extern int audit_enabled;
+extern int audit_ever_enabled;
+#endif
+
extern int audit_pid;
#define AUDIT_INODE_BUCKETS 32
@@ -104,6 +109,9 @@
int audit_send_list(void *);
struct inotify_watch;
+/* Inotify handle */
+extern struct inotify_handle *audit_ih;
+
extern void audit_free_parent(struct inotify_watch *);
extern void audit_handle_ievent(struct inotify_watch *, u32, u32, u32,
const char *, struct inode *);
@@ -111,6 +119,7 @@
extern struct mutex audit_filter_mutex;
extern void audit_free_rule_rcu(struct rcu_head *);
+extern struct list_head audit_filter_list[];
#ifdef CONFIG_AUDIT_TREE
extern struct audit_chunk *audit_tree_lookup(const struct inode *);
@@ -137,6 +146,10 @@
extern char *audit_unpack_string(void **, size_t *, size_t);
+extern pid_t audit_sig_pid;
+extern uid_t audit_sig_uid;
+extern u32 audit_sig_sid;
+
#ifdef CONFIG_AUDITSYSCALL
extern int __audit_signal_info(int sig, struct task_struct *t);
static inline int audit_signal_info(int sig, struct task_struct *t)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 28fef6b..0e0bd27e 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -89,14 +89,9 @@
DEFINE_MUTEX(audit_filter_mutex);
-/* Inotify handle */
-extern struct inotify_handle *audit_ih;
-
/* Inotify events we care about. */
#define AUDIT_IN_WATCH IN_MOVE|IN_CREATE|IN_DELETE|IN_DELETE_SELF|IN_MOVE_SELF
-extern int audit_enabled;
-
void audit_free_parent(struct inotify_watch *i_watch)
{
struct audit_parent *parent;
@@ -272,7 +267,7 @@
return -EINVAL;
watch = audit_init_watch(path);
- if (unlikely(IS_ERR(watch)))
+ if (IS_ERR(watch))
return PTR_ERR(watch);
audit_get_watch(watch);
@@ -422,7 +417,7 @@
static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
{
struct audit_entry *entry;
- struct audit_field *f;
+ struct audit_field *ino_f;
int err = 0;
int i;
@@ -483,6 +478,10 @@
if (f->val & ~15)
goto exit_free;
break;
+ case AUDIT_FILETYPE:
+ if ((f->val & ~S_IFMT) > S_IFMT)
+ goto exit_free;
+ break;
case AUDIT_INODE:
err = audit_to_inode(&entry->rule, f);
if (err)
@@ -504,9 +503,9 @@
}
}
- f = entry->rule.inode_f;
- if (f) {
- switch(f->op) {
+ ino_f = entry->rule.inode_f;
+ if (ino_f) {
+ switch(ino_f->op) {
case AUDIT_NOT_EQUAL:
entry->rule.inode_f = NULL;
case AUDIT_EQUAL:
@@ -531,7 +530,7 @@
{
int err = 0;
struct audit_entry *entry;
- struct audit_field *f;
+ struct audit_field *ino_f;
void *bufp;
size_t remain = datasz - sizeof(struct audit_rule_data);
int i;
@@ -654,14 +653,18 @@
if (f->val & ~15)
goto exit_free;
break;
+ case AUDIT_FILETYPE:
+ if ((f->val & ~S_IFMT) > S_IFMT)
+ goto exit_free;
+ break;
default:
goto exit_free;
}
}
- f = entry->rule.inode_f;
- if (f) {
- switch(f->op) {
+ ino_f = entry->rule.inode_f;
+ if (ino_f) {
+ switch(ino_f->op) {
case AUDIT_NOT_EQUAL:
entry->rule.inode_f = NULL;
case AUDIT_EQUAL:
@@ -848,7 +851,7 @@
return ERR_PTR(-ENOMEM);
new = audit_init_watch(path);
- if (unlikely(IS_ERR(new))) {
+ if (IS_ERR(new)) {
kfree(path);
goto out;
}
@@ -989,7 +992,7 @@
audit_set_auditable(current->audit_context);
nwatch = audit_dupe_watch(owatch);
- if (unlikely(IS_ERR(nwatch))) {
+ if (IS_ERR(nwatch)) {
mutex_unlock(&audit_filter_mutex);
audit_panic("error updating watch, skipping");
return;
@@ -1004,7 +1007,7 @@
list_del_rcu(&oentry->list);
nentry = audit_dupe_rule(&oentry->rule, nwatch);
- if (unlikely(IS_ERR(nentry)))
+ if (IS_ERR(nentry))
audit_panic("error updating watch, removing");
else {
int h = audit_hash_ino((u32)ino);
@@ -1500,8 +1503,9 @@
}
/* Log rule additions and removals */
-static void audit_log_rule_change(uid_t loginuid, u32 sid, char *action,
- struct audit_krule *rule, int res)
+static void audit_log_rule_change(uid_t loginuid, u32 sessionid, u32 sid,
+ char *action, struct audit_krule *rule,
+ int res)
{
struct audit_buffer *ab;
@@ -1511,7 +1515,7 @@
ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);
if (!ab)
return;
- audit_log_format(ab, "auid=%u", loginuid);
+ audit_log_format(ab, "auid=%u ses=%u", loginuid, sessionid);
if (sid) {
char *ctx = NULL;
u32 len;
@@ -1543,7 +1547,7 @@
* @sid: SE Linux Security ID of sender
*/
int audit_receive_filter(int type, int pid, int uid, int seq, void *data,
- size_t datasz, uid_t loginuid, u32 sid)
+ size_t datasz, uid_t loginuid, u32 sessionid, u32 sid)
{
struct task_struct *tsk;
struct audit_netlink_list *dest;
@@ -1590,7 +1594,8 @@
err = audit_add_rule(entry,
&audit_filter_list[entry->rule.listnr]);
- audit_log_rule_change(loginuid, sid, "add", &entry->rule, !err);
+ audit_log_rule_change(loginuid, sessionid, sid, "add",
+ &entry->rule, !err);
if (err)
audit_free_rule(entry);
@@ -1606,8 +1611,8 @@
err = audit_del_rule(entry,
&audit_filter_list[entry->rule.listnr]);
- audit_log_rule_change(loginuid, sid, "remove", &entry->rule,
- !err);
+ audit_log_rule_change(loginuid, sessionid, sid, "remove",
+ &entry->rule, !err);
audit_free_rule(entry);
break;
@@ -1785,7 +1790,7 @@
watch = entry->rule.watch;
tree = entry->rule.tree;
nentry = audit_dupe_rule(&entry->rule, watch);
- if (unlikely(IS_ERR(nentry))) {
+ if (IS_ERR(nentry)) {
/* save the first error encountered for the
* return value */
if (!err)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 56e56ed..c10e7aa 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -68,9 +68,6 @@
#include "audit.h"
-extern struct list_head audit_filter_list[];
-extern int audit_ever_enabled;
-
/* AUDIT_NAMES is the number of slots we reserve in the audit_context
* for saving names from getname(). */
#define AUDIT_NAMES 20
@@ -283,6 +280,19 @@
}
}
+static int audit_match_filetype(struct audit_context *ctx, int which)
+{
+ unsigned index = which & ~S_IFMT;
+ mode_t mode = which & S_IFMT;
+ if (index >= ctx->name_count)
+ return 0;
+ if (ctx->names[index].ino == -1)
+ return 0;
+ if ((ctx->names[index].mode ^ mode) & S_IFMT)
+ return 0;
+ return 1;
+}
+
/*
* We keep a linked list of fixed-sized (31 pointer) arrays of audit_chunk *;
* ->first_trees points to its beginning, ->trees - to the current end of data.
@@ -592,6 +602,9 @@
case AUDIT_PERM:
result = audit_match_perm(ctx, f->val);
break;
+ case AUDIT_FILETYPE:
+ result = audit_match_filetype(ctx, f->val);
+ break;
}
if (!result)
@@ -1095,7 +1108,7 @@
audit_log_format(*ab, "[%d]", i);
audit_log_format(*ab, "=");
if (has_cntl)
- audit_log_hex(*ab, buf, to_send);
+ audit_log_n_hex(*ab, buf, to_send);
else
audit_log_format(*ab, "\"%s\"", buf);
audit_log_format(*ab, "\n");
@@ -1296,7 +1309,6 @@
break; }
case AUDIT_SOCKETCALL: {
- int i;
struct audit_aux_data_socketcall *axs = (void *)aux;
audit_log_format(ab, "nargs=%d", axs->nargs);
for (i=0; i<axs->nargs; i++)
@@ -1307,7 +1319,7 @@
struct audit_aux_data_sockaddr *axs = (void *)aux;
audit_log_format(ab, "saddr=");
- audit_log_hex(ab, axs->a, axs->len);
+ audit_log_n_hex(ab, axs->a, axs->len);
break; }
case AUDIT_FD_PAIR: {
@@ -1321,7 +1333,6 @@
for (aux = context->aux_pids; aux; aux = aux->next) {
struct audit_aux_data_pids *axs = (void *)aux;
- int i;
for (i = 0; i < axs->pid_count; i++)
if (audit_log_pid_context(context, axs->target_pid[i],
@@ -1371,8 +1382,8 @@
default:
/* log the name's directory component */
audit_log_format(ab, " name=");
- audit_log_n_untrustedstring(ab, n->name_len,
- n->name);
+ audit_log_n_untrustedstring(ab, n->name,
+ n->name_len);
}
} else
audit_log_format(ab, " name=(null)");
@@ -1596,7 +1607,7 @@
if (likely(put_tree_ref(context, chunk)))
return;
if (unlikely(!grow_tree_refs(context))) {
- printk(KERN_WARNING "out of memory, audit has lost a tree reference");
+ printk(KERN_WARNING "out of memory, audit has lost a tree reference\n");
audit_set_auditable(context);
audit_put_chunk(chunk);
unroll_tree_refs(context, p, count);
@@ -1656,7 +1667,7 @@
}
/* too bad */
printk(KERN_WARNING
- "out of memory, audit has lost a tree reference");
+ "out of memory, audit has lost a tree reference\n");
unroll_tree_refs(context, p, count);
audit_set_auditable(context);
return;
@@ -1752,13 +1763,13 @@
if (context->name_count >= AUDIT_NAMES) {
if (inode)
printk(KERN_DEBUG "name_count maxed, losing inode data: "
- "dev=%02x:%02x, inode=%lu",
+ "dev=%02x:%02x, inode=%lu\n",
MAJOR(inode->i_sb->s_dev),
MINOR(inode->i_sb->s_dev),
inode->i_ino);
else
- printk(KERN_DEBUG "name_count maxed, losing inode data");
+ printk(KERN_DEBUG "name_count maxed, losing inode data\n");
return 1;
}
context->name_count++;
@@ -2361,9 +2372,6 @@
struct audit_aux_data_pids *axp;
struct task_struct *tsk = current;
struct audit_context *ctx = tsk->audit_context;
- extern pid_t audit_sig_pid;
- extern uid_t audit_sig_uid;
- extern u32 audit_sig_sid;
if (audit_pid && t->tgid == audit_pid) {
if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1) {
diff --git a/kernel/bounds.c b/kernel/bounds.c
index c3c5554..3c53013 100644
--- a/kernel/bounds.c
+++ b/kernel/bounds.c
@@ -8,11 +8,7 @@
/* Include headers that define the enum constants of interest */
#include <linux/page-flags.h>
#include <linux/mmzone.h>
-
-#define DEFINE(sym, val) \
- asm volatile("\n->" #sym " %0 " #val : : "i" (val))
-
-#define BLANK() asm volatile("\n->" : : )
+#include <linux/kbuild.h>
void foo(void)
{
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 6d8de05..fbc6fc89 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -44,6 +44,7 @@
#include <linux/kmod.h>
#include <linux/delayacct.h>
#include <linux/cgroupstats.h>
+#include <linux/hash.h>
#include <asm/atomic.h>
@@ -118,17 +119,7 @@
* be called.
*/
static int need_forkexit_callback;
-
-/* bits in struct cgroup flags field */
-enum {
- /* Control Group is dead */
- CGRP_REMOVED,
- /* Control Group has previously had a child cgroup or a task,
- * but no longer (only if CGRP_NOTIFY_ON_RELEASE is set) */
- CGRP_RELEASABLE,
- /* Control Group requires release notifications to userspace */
- CGRP_NOTIFY_ON_RELEASE,
-};
+static int need_mm_owner_callback __read_mostly;
/* convenient tests for these bits */
inline int cgroup_is_removed(const struct cgroup *cgrp)
@@ -204,6 +195,27 @@
static DEFINE_RWLOCK(css_set_lock);
static int css_set_count;
+/* hash table for cgroup groups. This improves the performance to
+ * find an existing css_set */
+#define CSS_SET_HASH_BITS 7
+#define CSS_SET_TABLE_SIZE (1 << CSS_SET_HASH_BITS)
+static struct hlist_head css_set_table[CSS_SET_TABLE_SIZE];
+
+static struct hlist_head *css_set_hash(struct cgroup_subsys_state *css[])
+{
+ int i;
+ int index;
+ unsigned long tmp = 0UL;
+
+ for (i = 0; i < CGROUP_SUBSYS_COUNT; i++)
+ tmp += (unsigned long)css[i];
+ tmp = (tmp >> 16) ^ tmp;
+
+ index = hash_long(tmp, CSS_SET_HASH_BITS);
+
+ return &css_set_table[index];
+}
+
/* We don't maintain the lists running through each css_set to its
* task until after the first call to cgroup_iter_start(). This
* reduces the fork()/exit() overhead for people who have cgroups
@@ -230,7 +242,7 @@
static void unlink_css_set(struct css_set *cg)
{
write_lock(&css_set_lock);
- list_del(&cg->list);
+ hlist_del(&cg->hlist);
css_set_count--;
while (!list_empty(&cg->cg_links)) {
struct cg_cgroup_link *link;
@@ -295,9 +307,7 @@
/*
* find_existing_css_set() is a helper for
* find_css_set(), and checks to see whether an existing
- * css_set is suitable. This currently walks a linked-list for
- * simplicity; a later patch will use a hash table for better
- * performance
+ * css_set is suitable.
*
* oldcg: the cgroup group that we're using before the cgroup
* transition
@@ -314,7 +324,9 @@
{
int i;
struct cgroupfs_root *root = cgrp->root;
- struct list_head *l = &init_css_set.list;
+ struct hlist_head *hhead;
+ struct hlist_node *node;
+ struct css_set *cg;
/* Built the set of subsystem state objects that we want to
* see in the new css_set */
@@ -331,18 +343,13 @@
}
}
- /* Look through existing cgroup groups to find one to reuse */
- do {
- struct css_set *cg =
- list_entry(l, struct css_set, list);
-
+ hhead = css_set_hash(template);
+ hlist_for_each_entry(cg, node, hhead, hlist) {
if (!memcmp(template, cg->subsys, sizeof(cg->subsys))) {
/* All subsystems matched */
return cg;
}
- /* Try the next cgroup group */
- l = l->next;
- } while (l != &init_css_set.list);
+ }
/* No existing cgroup group matched */
return NULL;
@@ -404,6 +411,8 @@
struct list_head tmp_cg_links;
struct cg_cgroup_link *link;
+ struct hlist_head *hhead;
+
/* First see if we already have a cgroup group that matches
* the desired set */
write_lock(&css_set_lock);
@@ -428,6 +437,7 @@
kref_init(&res->ref);
INIT_LIST_HEAD(&res->cg_links);
INIT_LIST_HEAD(&res->tasks);
+ INIT_HLIST_NODE(&res->hlist);
/* Copy the set of subsystem state objects generated in
* find_existing_css_set() */
@@ -467,9 +477,12 @@
BUG_ON(!list_empty(&tmp_cg_links));
- /* Link this cgroup group into the list */
- list_add(&res->list, &init_css_set.list);
css_set_count++;
+
+ /* Add this cgroup group to the hash table */
+ hhead = css_set_hash(res->subsys);
+ hlist_add_head(&res->hlist, hhead);
+
write_unlock(&css_set_lock);
return res;
@@ -562,7 +575,7 @@
static struct file_operations proc_cgroupstats_operations;
static struct backing_dev_info cgroup_backing_dev_info = {
- .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
};
static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
@@ -948,7 +961,7 @@
int ret = 0;
struct super_block *sb;
struct cgroupfs_root *root;
- struct list_head tmp_cg_links, *l;
+ struct list_head tmp_cg_links;
INIT_LIST_HEAD(&tmp_cg_links);
/* First find the desired set of subsystems */
@@ -990,6 +1003,7 @@
/* New superblock */
struct cgroup *cgrp = &root->top_cgroup;
struct inode *inode;
+ int i;
BUG_ON(sb->s_root != NULL);
@@ -1034,22 +1048,25 @@
/* Link the top cgroup in this hierarchy into all
* the css_set objects */
write_lock(&css_set_lock);
- l = &init_css_set.list;
- do {
+ for (i = 0; i < CSS_SET_TABLE_SIZE; i++) {
+ struct hlist_head *hhead = &css_set_table[i];
+ struct hlist_node *node;
struct css_set *cg;
- struct cg_cgroup_link *link;
- cg = list_entry(l, struct css_set, list);
- BUG_ON(list_empty(&tmp_cg_links));
- link = list_entry(tmp_cg_links.next,
- struct cg_cgroup_link,
- cgrp_link_list);
- list_del(&link->cgrp_link_list);
- link->cg = cg;
- list_add(&link->cgrp_link_list,
- &root->top_cgroup.css_sets);
- list_add(&link->cg_link_list, &cg->cg_links);
- l = l->next;
- } while (l != &init_css_set.list);
+
+ hlist_for_each_entry(cg, node, hhead, hlist) {
+ struct cg_cgroup_link *link;
+
+ BUG_ON(list_empty(&tmp_cg_links));
+ link = list_entry(tmp_cg_links.next,
+ struct cg_cgroup_link,
+ cgrp_link_list);
+ list_del(&link->cgrp_link_list);
+ link->cg = cg;
+ list_add(&link->cgrp_link_list,
+ &root->top_cgroup.css_sets);
+ list_add(&link->cg_link_list, &cg->cg_links);
+ }
+ }
write_unlock(&css_set_lock);
free_cg_links(&tmp_cg_links);
@@ -1307,18 +1324,16 @@
FILE_DIR,
FILE_TASKLIST,
FILE_NOTIFY_ON_RELEASE,
- FILE_RELEASABLE,
FILE_RELEASE_AGENT,
};
-static ssize_t cgroup_write_uint(struct cgroup *cgrp, struct cftype *cft,
- struct file *file,
- const char __user *userbuf,
- size_t nbytes, loff_t *unused_ppos)
+static ssize_t cgroup_write_X64(struct cgroup *cgrp, struct cftype *cft,
+ struct file *file,
+ const char __user *userbuf,
+ size_t nbytes, loff_t *unused_ppos)
{
char buffer[64];
int retval = 0;
- u64 val;
char *end;
if (!nbytes)
@@ -1329,16 +1344,18 @@
return -EFAULT;
buffer[nbytes] = 0; /* nul-terminate */
-
- /* strip newline if necessary */
- if (nbytes && (buffer[nbytes-1] == '\n'))
- buffer[nbytes-1] = 0;
- val = simple_strtoull(buffer, &end, 0);
- if (*end)
- return -EINVAL;
-
- /* Pass to subsystem */
- retval = cft->write_uint(cgrp, cft, val);
+ strstrip(buffer);
+ if (cft->write_u64) {
+ u64 val = simple_strtoull(buffer, &end, 0);
+ if (*end)
+ return -EINVAL;
+ retval = cft->write_u64(cgrp, cft, val);
+ } else {
+ s64 val = simple_strtoll(buffer, &end, 0);
+ if (*end)
+ return -EINVAL;
+ retval = cft->write_s64(cgrp, cft, val);
+ }
if (!retval)
retval = nbytes;
return retval;
@@ -1419,23 +1436,39 @@
return -ENODEV;
if (cft->write)
return cft->write(cgrp, cft, file, buf, nbytes, ppos);
- if (cft->write_uint)
- return cgroup_write_uint(cgrp, cft, file, buf, nbytes, ppos);
+ if (cft->write_u64 || cft->write_s64)
+ return cgroup_write_X64(cgrp, cft, file, buf, nbytes, ppos);
+ if (cft->trigger) {
+ int ret = cft->trigger(cgrp, (unsigned int)cft->private);
+ return ret ? ret : nbytes;
+ }
return -EINVAL;
}
-static ssize_t cgroup_read_uint(struct cgroup *cgrp, struct cftype *cft,
- struct file *file,
- char __user *buf, size_t nbytes,
- loff_t *ppos)
+static ssize_t cgroup_read_u64(struct cgroup *cgrp, struct cftype *cft,
+ struct file *file,
+ char __user *buf, size_t nbytes,
+ loff_t *ppos)
{
char tmp[64];
- u64 val = cft->read_uint(cgrp, cft);
+ u64 val = cft->read_u64(cgrp, cft);
int len = sprintf(tmp, "%llu\n", (unsigned long long) val);
return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);
}
+static ssize_t cgroup_read_s64(struct cgroup *cgrp, struct cftype *cft,
+ struct file *file,
+ char __user *buf, size_t nbytes,
+ loff_t *ppos)
+{
+ char tmp[64];
+ s64 val = cft->read_s64(cgrp, cft);
+ int len = sprintf(tmp, "%lld\n", (long long) val);
+
+ return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);
+}
+
static ssize_t cgroup_common_file_read(struct cgroup *cgrp,
struct cftype *cft,
struct file *file,
@@ -1490,11 +1523,56 @@
if (cft->read)
return cft->read(cgrp, cft, file, buf, nbytes, ppos);
- if (cft->read_uint)
- return cgroup_read_uint(cgrp, cft, file, buf, nbytes, ppos);
+ if (cft->read_u64)
+ return cgroup_read_u64(cgrp, cft, file, buf, nbytes, ppos);
+ if (cft->read_s64)
+ return cgroup_read_s64(cgrp, cft, file, buf, nbytes, ppos);
return -EINVAL;
}
+/*
+ * seqfile ops/methods for returning structured data. Currently just
+ * supports string->u64 maps, but can be extended in future.
+ */
+
+struct cgroup_seqfile_state {
+ struct cftype *cft;
+ struct cgroup *cgroup;
+};
+
+static int cgroup_map_add(struct cgroup_map_cb *cb, const char *key, u64 value)
+{
+ struct seq_file *sf = cb->state;
+ return seq_printf(sf, "%s %llu\n", key, (unsigned long long)value);
+}
+
+static int cgroup_seqfile_show(struct seq_file *m, void *arg)
+{
+ struct cgroup_seqfile_state *state = m->private;
+ struct cftype *cft = state->cft;
+ if (cft->read_map) {
+ struct cgroup_map_cb cb = {
+ .fill = cgroup_map_add,
+ .state = m,
+ };
+ return cft->read_map(state->cgroup, cft, &cb);
+ }
+ return cft->read_seq_string(state->cgroup, cft, m);
+}
+
+int cgroup_seqfile_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq = file->private_data;
+ kfree(seq->private);
+ return single_release(inode, file);
+}
+
+static struct file_operations cgroup_seqfile_operations = {
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = cgroup_seqfile_release,
+};
+
static int cgroup_file_open(struct inode *inode, struct file *file)
{
int err;
@@ -1507,7 +1585,18 @@
cft = __d_cft(file->f_dentry);
if (!cft)
return -ENODEV;
- if (cft->open)
+ if (cft->read_map || cft->read_seq_string) {
+ struct cgroup_seqfile_state *state =
+ kzalloc(sizeof(*state), GFP_USER);
+ if (!state)
+ return -ENOMEM;
+ state->cft = cft;
+ state->cgroup = __d_cgrp(file->f_dentry->d_parent);
+ file->f_op = &cgroup_seqfile_operations;
+ err = single_open(file, cgroup_seqfile_show, state);
+ if (err < 0)
+ kfree(state);
+ } else if (cft->open)
err = cft->open(inode, file);
else
err = 0;
@@ -1715,7 +1804,7 @@
* The tasklist_lock is not held here, as do_each_thread() and
* while_each_thread() are protected by RCU.
*/
-void cgroup_enable_task_cg_lists(void)
+static void cgroup_enable_task_cg_lists(void)
{
struct task_struct *p, *g;
write_lock(&css_set_lock);
@@ -1913,14 +2002,14 @@
if (heap->size) {
for (i = 0; i < heap->size; i++) {
- struct task_struct *p = heap->ptrs[i];
+ struct task_struct *q = heap->ptrs[i];
if (i == 0) {
- latest_time = p->start_time;
- latest_task = p;
+ latest_time = q->start_time;
+ latest_task = q;
}
/* Process the task per the caller's callback */
- scan->process_task(p, scan);
- put_task_struct(p);
+ scan->process_task(q, scan);
+ put_task_struct(q);
}
/*
* If we had to process any tasks at all, scan again
@@ -2138,11 +2227,6 @@
return notify_on_release(cgrp);
}
-static u64 cgroup_read_releasable(struct cgroup *cgrp, struct cftype *cft)
-{
- return test_bit(CGRP_RELEASABLE, &cgrp->flags);
-}
-
/*
* for the common functions, 'private' gives the type of file
*/
@@ -2158,16 +2242,10 @@
{
.name = "notify_on_release",
- .read_uint = cgroup_read_notify_on_release,
+ .read_u64 = cgroup_read_notify_on_release,
.write = cgroup_common_file_write,
.private = FILE_NOTIFY_ON_RELEASE,
},
-
- {
- .name = "releasable",
- .read_uint = cgroup_read_releasable,
- .private = FILE_RELEASABLE,
- }
};
static struct cftype cft_release_agent = {
@@ -2401,10 +2479,9 @@
return 0;
}
-static void cgroup_init_subsys(struct cgroup_subsys *ss)
+static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
{
struct cgroup_subsys_state *css;
- struct list_head *l;
printk(KERN_INFO "Initializing cgroup subsys %s\n", ss->name);
@@ -2415,34 +2492,19 @@
BUG_ON(IS_ERR(css));
init_cgroup_css(css, ss, dummytop);
- /* Update all cgroup groups to contain a subsys
+ /* Update the init_css_set to contain a subsys
* pointer to this state - since the subsystem is
- * newly registered, all tasks and hence all cgroup
- * groups are in the subsystem's top cgroup. */
- write_lock(&css_set_lock);
- l = &init_css_set.list;
- do {
- struct css_set *cg =
- list_entry(l, struct css_set, list);
- cg->subsys[ss->subsys_id] = dummytop->subsys[ss->subsys_id];
- l = l->next;
- } while (l != &init_css_set.list);
- write_unlock(&css_set_lock);
-
- /* If this subsystem requested that it be notified with fork
- * events, we should send it one now for every process in the
- * system */
- if (ss->fork) {
- struct task_struct *g, *p;
-
- read_lock(&tasklist_lock);
- do_each_thread(g, p) {
- ss->fork(ss, p);
- } while_each_thread(g, p);
- read_unlock(&tasklist_lock);
- }
+ * newly registered, all tasks and hence the
+ * init_css_set is in the subsystem's top cgroup. */
+ init_css_set.subsys[ss->subsys_id] = dummytop->subsys[ss->subsys_id];
need_forkexit_callback |= ss->fork || ss->exit;
+ need_mm_owner_callback |= !!ss->mm_owner_changed;
+
+ /* At system boot, before all subsystems have been
+ * registered, no tasks have been forked, so we don't
+ * need to invoke fork callbacks here. */
+ BUG_ON(!list_empty(&init_task.tasks));
ss->active = 1;
}
@@ -2458,9 +2520,9 @@
int i;
kref_init(&init_css_set.ref);
kref_get(&init_css_set.ref);
- INIT_LIST_HEAD(&init_css_set.list);
INIT_LIST_HEAD(&init_css_set.cg_links);
INIT_LIST_HEAD(&init_css_set.tasks);
+ INIT_HLIST_NODE(&init_css_set.hlist);
css_set_count = 1;
init_cgroup_root(&rootnode);
list_add(&rootnode.root_list, &roots);
@@ -2473,6 +2535,9 @@
list_add(&init_css_set_link.cg_link_list,
&init_css_set.cg_links);
+ for (i = 0; i < CSS_SET_TABLE_SIZE; i++)
+ INIT_HLIST_HEAD(&css_set_table[i]);
+
for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
struct cgroup_subsys *ss = subsys[i];
@@ -2502,7 +2567,7 @@
{
int err;
int i;
- struct proc_dir_entry *entry;
+ struct hlist_head *hhead;
err = bdi_init(&cgroup_backing_dev_info);
if (err)
@@ -2514,13 +2579,15 @@
cgroup_init_subsys(ss);
}
+ /* Add init_css_set to the hash table */
+ hhead = css_set_hash(init_css_set.subsys);
+ hlist_add_head(&init_css_set.hlist, hhead);
+
err = register_filesystem(&cgroup_fs_type);
if (err < 0)
goto out;
- entry = create_proc_entry("cgroups", 0, NULL);
- if (entry)
- entry->proc_fops = &proc_cgroupstats_operations;
+ proc_create("cgroups", 0, NULL, &proc_cgroupstats_operations);
out:
if (err)
@@ -2683,6 +2750,34 @@
}
}
+#ifdef CONFIG_MM_OWNER
+/**
+ * cgroup_mm_owner_callbacks - run callbacks when the mm->owner changes
+ * @p: the new owner
+ *
+ * Called on every change to mm->owner. mm_init_owner() does not
+ * invoke this routine, since it assigns the mm->owner the first time
+ * and does not change it.
+ */
+void cgroup_mm_owner_callbacks(struct task_struct *old, struct task_struct *new)
+{
+ struct cgroup *oldcgrp, *newcgrp;
+
+ if (need_mm_owner_callback) {
+ int i;
+ for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+ struct cgroup_subsys *ss = subsys[i];
+ oldcgrp = task_cgroup(old, ss->subsys_id);
+ newcgrp = task_cgroup(new, ss->subsys_id);
+ if (oldcgrp == newcgrp)
+ continue;
+ if (ss->mm_owner_changed)
+ ss->mm_owner_changed(ss, oldcgrp, newcgrp);
+ }
+ }
+}
+#endif /* CONFIG_MM_OWNER */
+
/**
* cgroup_post_fork - called on a new task after adding it to the task list
* @child: the task in question
diff --git a/kernel/cgroup_debug.c b/kernel/cgroup_debug.c
index 37301e8..c3dc3ab 100644
--- a/kernel/cgroup_debug.c
+++ b/kernel/cgroup_debug.c
@@ -1,5 +1,5 @@
/*
- * kernel/ccontainer_debug.c - Example cgroup subsystem that
+ * kernel/cgroup_debug.c - Example cgroup subsystem that
* exposes debug info
*
* Copyright (C) Google Inc, 2007
@@ -62,25 +62,35 @@
return count;
}
+static u64 releasable_read(struct cgroup *cgrp, struct cftype *cft)
+{
+ return test_bit(CGRP_RELEASABLE, &cgrp->flags);
+}
+
static struct cftype files[] = {
{
.name = "cgroup_refcount",
- .read_uint = cgroup_refcount_read,
+ .read_u64 = cgroup_refcount_read,
},
{
.name = "taskcount",
- .read_uint = taskcount_read,
+ .read_u64 = taskcount_read,
},
{
.name = "current_css_set",
- .read_uint = current_css_set_read,
+ .read_u64 = current_css_set_read,
},
{
.name = "current_css_set_refcount",
- .read_uint = current_css_set_refcount_read,
+ .read_u64 = current_css_set_refcount_read,
},
+
+ {
+ .name = "releasable",
+ .read_u64 = releasable_read,
+ }
};
static int debug_populate(struct cgroup_subsys *ss, struct cgroup *cont)
diff --git a/kernel/compat.c b/kernel/compat.c
index e1ef048..32c254a 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -898,7 +898,7 @@
current->state = TASK_INTERRUPTIBLE;
schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
return -ERESTARTNOHAND;
}
#endif /* __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND */
@@ -955,7 +955,8 @@
__put_user(txc.jitcnt, &utp->jitcnt) ||
__put_user(txc.calcnt, &utp->calcnt) ||
__put_user(txc.errcnt, &utp->errcnt) ||
- __put_user(txc.stbcnt, &utp->stbcnt))
+ __put_user(txc.stbcnt, &utp->stbcnt) ||
+ __put_user(txc.tai, &utp->tai))
ret = -EFAULT;
return ret;
@@ -1080,4 +1081,3 @@
return 0;
}
-
diff --git a/kernel/configs.c b/kernel/configs.c
index e84d3f9..4c34521 100644
--- a/kernel/configs.c
+++ b/kernel/configs.c
@@ -79,12 +79,11 @@
struct proc_dir_entry *entry;
/* create the current config file */
- entry = create_proc_entry("config.gz", S_IFREG | S_IRUGO,
- &proc_root);
+ entry = proc_create("config.gz", S_IFREG | S_IRUGO, NULL,
+ &ikconfig_file_ops);
if (!entry)
return -ENOMEM;
- entry->proc_fops = &ikconfig_file_ops;
entry->size = kernel_config_data_size;
return 0;
@@ -95,7 +94,7 @@
static void __exit ikconfig_cleanup(void)
{
- remove_proc_entry("config.gz", &proc_root);
+ remove_proc_entry("config.gz", NULL);
}
module_init(ikconfig_init);
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 2011ad8d..c77bc3a 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -33,17 +33,13 @@
* an ongoing cpu hotplug operation.
*/
int refcount;
- wait_queue_head_t writer_queue;
} cpu_hotplug;
-#define writer_exists() (cpu_hotplug.active_writer != NULL)
-
void __init cpu_hotplug_init(void)
{
cpu_hotplug.active_writer = NULL;
mutex_init(&cpu_hotplug.lock);
cpu_hotplug.refcount = 0;
- init_waitqueue_head(&cpu_hotplug.writer_queue);
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -65,11 +61,8 @@
if (cpu_hotplug.active_writer == current)
return;
mutex_lock(&cpu_hotplug.lock);
- cpu_hotplug.refcount--;
-
- if (unlikely(writer_exists()) && !cpu_hotplug.refcount)
- wake_up(&cpu_hotplug.writer_queue);
-
+ if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer))
+ wake_up_process(cpu_hotplug.active_writer);
mutex_unlock(&cpu_hotplug.lock);
}
@@ -98,8 +91,8 @@
* Note that during a cpu-hotplug operation, the new readers, if any,
* will be blocked by the cpu_hotplug.lock
*
- * Since cpu_maps_update_begin is always called after invoking
- * cpu_maps_update_begin, we can be sure that only one writer is active.
+ * Since cpu_hotplug_begin() is always called after invoking
+ * cpu_maps_update_begin(), we can be sure that only one writer is active.
*
* Note that theoretically, there is a possibility of a livelock:
* - Refcount goes to zero, last reader wakes up the sleeping
@@ -115,19 +108,16 @@
*/
static void cpu_hotplug_begin(void)
{
- DECLARE_WAITQUEUE(wait, current);
-
- mutex_lock(&cpu_hotplug.lock);
-
cpu_hotplug.active_writer = current;
- add_wait_queue_exclusive(&cpu_hotplug.writer_queue, &wait);
- while (cpu_hotplug.refcount) {
- set_current_state(TASK_UNINTERRUPTIBLE);
+
+ for (;;) {
+ mutex_lock(&cpu_hotplug.lock);
+ if (likely(!cpu_hotplug.refcount))
+ break;
+ __set_current_state(TASK_UNINTERRUPTIBLE);
mutex_unlock(&cpu_hotplug.lock);
schedule();
- mutex_lock(&cpu_hotplug.lock);
}
- remove_wait_queue_locked(&cpu_hotplug.writer_queue, &wait);
}
static void cpu_hotplug_done(void)
@@ -136,7 +126,7 @@
mutex_unlock(&cpu_hotplug.lock);
}
/* Need to know about CPUs going up/down? */
-int __cpuinit register_cpu_notifier(struct notifier_block *nb)
+int __ref register_cpu_notifier(struct notifier_block *nb)
{
int ret;
cpu_maps_update_begin();
@@ -149,7 +139,7 @@
EXPORT_SYMBOL(register_cpu_notifier);
-void unregister_cpu_notifier(struct notifier_block *nb)
+void __ref unregister_cpu_notifier(struct notifier_block *nb)
{
cpu_maps_update_begin();
raw_notifier_chain_unregister(&cpu_chain, nb);
@@ -180,7 +170,7 @@
};
/* Take this CPU down. */
-static int take_cpu_down(void *_param)
+static int __ref take_cpu_down(void *_param)
{
struct take_cpu_down_param *param = _param;
int err;
@@ -199,7 +189,7 @@
}
/* Requires cpu_add_remove_lock to be held */
-static int _cpu_down(unsigned int cpu, int tasks_frozen)
+static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
{
int err, nr_calls = 0;
struct task_struct *p;
@@ -225,7 +215,7 @@
__raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
hcpu, nr_calls, NULL);
printk("%s: attempt to take down CPU %u failed\n",
- __FUNCTION__, cpu);
+ __func__, cpu);
err = -EINVAL;
goto out_release;
}
@@ -274,7 +264,7 @@
return err;
}
-int cpu_down(unsigned int cpu)
+int __ref cpu_down(unsigned int cpu)
{
int err = 0;
@@ -305,7 +295,7 @@
if (ret == NOTIFY_BAD) {
nr_calls--;
printk("%s: attempt to bring up CPU %u failed\n",
- __FUNCTION__, cpu);
+ __func__, cpu);
ret = -EINVAL;
goto out_notify;
}
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 48a976c..8da627d 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -127,6 +127,7 @@
typedef enum {
CS_CPU_EXCLUSIVE,
CS_MEM_EXCLUSIVE,
+ CS_MEM_HARDWALL,
CS_MEMORY_MIGRATE,
CS_SCHED_LOAD_BALANCE,
CS_SPREAD_PAGE,
@@ -144,6 +145,11 @@
return test_bit(CS_MEM_EXCLUSIVE, &cs->flags);
}
+static inline int is_mem_hardwall(const struct cpuset *cs)
+{
+ return test_bit(CS_MEM_HARDWALL, &cs->flags);
+}
+
static inline int is_sched_load_balance(const struct cpuset *cs)
{
return test_bit(CS_SCHED_LOAD_BALANCE, &cs->flags);
@@ -735,7 +741,8 @@
* Return nonzero if this tasks's cpus_allowed mask should be changed (in other
* words, if its mask is not equal to its cpuset's mask).
*/
-int cpuset_test_cpumask(struct task_struct *tsk, struct cgroup_scanner *scan)
+static int cpuset_test_cpumask(struct task_struct *tsk,
+ struct cgroup_scanner *scan)
{
return !cpus_equal(tsk->cpus_allowed,
(cgroup_cs(scan->cg))->cpus_allowed);
@@ -752,7 +759,8 @@
* We don't need to re-check for the cgroup/cpuset membership, since we're
* holding cgroup_lock() at this point.
*/
-void cpuset_change_cpumask(struct task_struct *tsk, struct cgroup_scanner *scan)
+static void cpuset_change_cpumask(struct task_struct *tsk,
+ struct cgroup_scanner *scan)
{
set_cpus_allowed_ptr(tsk, &((cgroup_cs(scan->cg))->cpus_allowed));
}
@@ -1023,19 +1031,6 @@
return task_cs(current) == cpuset_being_rebound;
}
-/*
- * Call with cgroup_mutex held.
- */
-
-static int update_memory_pressure_enabled(struct cpuset *cs, char *buf)
-{
- if (simple_strtoul(buf, NULL, 10) != 0)
- cpuset_memory_pressure_enabled = 1;
- else
- cpuset_memory_pressure_enabled = 0;
- return 0;
-}
-
static int update_relax_domain_level(struct cpuset *cs, char *buf)
{
int val = simple_strtol(buf, NULL, 10);
@@ -1053,25 +1048,20 @@
/*
* update_flag - read a 0 or a 1 in a file and update associated flag
- * bit: the bit to update (CS_CPU_EXCLUSIVE, CS_MEM_EXCLUSIVE,
- * CS_SCHED_LOAD_BALANCE,
- * CS_NOTIFY_ON_RELEASE, CS_MEMORY_MIGRATE,
- * CS_SPREAD_PAGE, CS_SPREAD_SLAB)
- * cs: the cpuset to update
- * buf: the buffer where we read the 0 or 1
+ * bit: the bit to update (see cpuset_flagbits_t)
+ * cs: the cpuset to update
+ * turning_on: whether the flag is being set or cleared
*
* Call with cgroup_mutex held.
*/
-static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
+static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
+ int turning_on)
{
- int turning_on;
struct cpuset trialcs;
int err;
int cpus_nonempty, balance_flag_changed;
- turning_on = (simple_strtoul(buf, NULL, 10) != 0);
-
trialcs = *cs;
if (turning_on)
set_bit(bit, &trialcs.flags);
@@ -1241,6 +1231,7 @@
FILE_MEMLIST,
FILE_CPU_EXCLUSIVE,
FILE_MEM_EXCLUSIVE,
+ FILE_MEM_HARDWALL,
FILE_SCHED_LOAD_BALANCE,
FILE_SCHED_RELAX_DOMAIN_LEVEL,
FILE_MEMORY_PRESSURE_ENABLED,
@@ -1289,35 +1280,9 @@
case FILE_MEMLIST:
retval = update_nodemask(cs, buffer);
break;
- case FILE_CPU_EXCLUSIVE:
- retval = update_flag(CS_CPU_EXCLUSIVE, cs, buffer);
- break;
- case FILE_MEM_EXCLUSIVE:
- retval = update_flag(CS_MEM_EXCLUSIVE, cs, buffer);
- break;
- case FILE_SCHED_LOAD_BALANCE:
- retval = update_flag(CS_SCHED_LOAD_BALANCE, cs, buffer);
- break;
case FILE_SCHED_RELAX_DOMAIN_LEVEL:
retval = update_relax_domain_level(cs, buffer);
break;
- case FILE_MEMORY_MIGRATE:
- retval = update_flag(CS_MEMORY_MIGRATE, cs, buffer);
- break;
- case FILE_MEMORY_PRESSURE_ENABLED:
- retval = update_memory_pressure_enabled(cs, buffer);
- break;
- case FILE_MEMORY_PRESSURE:
- retval = -EACCES;
- break;
- case FILE_SPREAD_PAGE:
- retval = update_flag(CS_SPREAD_PAGE, cs, buffer);
- cs->mems_generation = cpuset_mems_generation++;
- break;
- case FILE_SPREAD_SLAB:
- retval = update_flag(CS_SPREAD_SLAB, cs, buffer);
- cs->mems_generation = cpuset_mems_generation++;
- break;
default:
retval = -EINVAL;
goto out2;
@@ -1332,6 +1297,57 @@
return retval;
}
+static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
+{
+ int retval = 0;
+ struct cpuset *cs = cgroup_cs(cgrp);
+ cpuset_filetype_t type = cft->private;
+
+ cgroup_lock();
+
+ if (cgroup_is_removed(cgrp)) {
+ cgroup_unlock();
+ return -ENODEV;
+ }
+
+ switch (type) {
+ case FILE_CPU_EXCLUSIVE:
+ retval = update_flag(CS_CPU_EXCLUSIVE, cs, val);
+ break;
+ case FILE_MEM_EXCLUSIVE:
+ retval = update_flag(CS_MEM_EXCLUSIVE, cs, val);
+ break;
+ case FILE_MEM_HARDWALL:
+ retval = update_flag(CS_MEM_HARDWALL, cs, val);
+ break;
+ case FILE_SCHED_LOAD_BALANCE:
+ retval = update_flag(CS_SCHED_LOAD_BALANCE, cs, val);
+ break;
+ case FILE_MEMORY_MIGRATE:
+ retval = update_flag(CS_MEMORY_MIGRATE, cs, val);
+ break;
+ case FILE_MEMORY_PRESSURE_ENABLED:
+ cpuset_memory_pressure_enabled = !!val;
+ break;
+ case FILE_MEMORY_PRESSURE:
+ retval = -EACCES;
+ break;
+ case FILE_SPREAD_PAGE:
+ retval = update_flag(CS_SPREAD_PAGE, cs, val);
+ cs->mems_generation = cpuset_mems_generation++;
+ break;
+ case FILE_SPREAD_SLAB:
+ retval = update_flag(CS_SPREAD_SLAB, cs, val);
+ cs->mems_generation = cpuset_mems_generation++;
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ cgroup_unlock();
+ return retval;
+}
+
/*
* These ascii lists should be read in a single call, by using a user
* buffer large enough to hold the entire map. If read in smaller
@@ -1390,33 +1406,9 @@
case FILE_MEMLIST:
s += cpuset_sprintf_memlist(s, cs);
break;
- case FILE_CPU_EXCLUSIVE:
- *s++ = is_cpu_exclusive(cs) ? '1' : '0';
- break;
- case FILE_MEM_EXCLUSIVE:
- *s++ = is_mem_exclusive(cs) ? '1' : '0';
- break;
- case FILE_SCHED_LOAD_BALANCE:
- *s++ = is_sched_load_balance(cs) ? '1' : '0';
- break;
case FILE_SCHED_RELAX_DOMAIN_LEVEL:
s += sprintf(s, "%d", cs->relax_domain_level);
break;
- case FILE_MEMORY_MIGRATE:
- *s++ = is_memory_migrate(cs) ? '1' : '0';
- break;
- case FILE_MEMORY_PRESSURE_ENABLED:
- *s++ = cpuset_memory_pressure_enabled ? '1' : '0';
- break;
- case FILE_MEMORY_PRESSURE:
- s += sprintf(s, "%d", fmeter_getrate(&cs->fmeter));
- break;
- case FILE_SPREAD_PAGE:
- *s++ = is_spread_page(cs) ? '1' : '0';
- break;
- case FILE_SPREAD_SLAB:
- *s++ = is_spread_slab(cs) ? '1' : '0';
- break;
default:
retval = -EINVAL;
goto out;
@@ -1429,121 +1421,137 @@
return retval;
}
-
-
+static u64 cpuset_read_u64(struct cgroup *cont, struct cftype *cft)
+{
+ struct cpuset *cs = cgroup_cs(cont);
+ cpuset_filetype_t type = cft->private;
+ switch (type) {
+ case FILE_CPU_EXCLUSIVE:
+ return is_cpu_exclusive(cs);
+ case FILE_MEM_EXCLUSIVE:
+ return is_mem_exclusive(cs);
+ case FILE_MEM_HARDWALL:
+ return is_mem_hardwall(cs);
+ case FILE_SCHED_LOAD_BALANCE:
+ return is_sched_load_balance(cs);
+ case FILE_MEMORY_MIGRATE:
+ return is_memory_migrate(cs);
+ case FILE_MEMORY_PRESSURE_ENABLED:
+ return cpuset_memory_pressure_enabled;
+ case FILE_MEMORY_PRESSURE:
+ return fmeter_getrate(&cs->fmeter);
+ case FILE_SPREAD_PAGE:
+ return is_spread_page(cs);
+ case FILE_SPREAD_SLAB:
+ return is_spread_slab(cs);
+ default:
+ BUG();
+ }
+}
/*
* for the common functions, 'private' gives the type of file
*/
-static struct cftype cft_cpus = {
- .name = "cpus",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_CPULIST,
-};
+static struct cftype files[] = {
+ {
+ .name = "cpus",
+ .read = cpuset_common_file_read,
+ .write = cpuset_common_file_write,
+ .private = FILE_CPULIST,
+ },
-static struct cftype cft_mems = {
- .name = "mems",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_MEMLIST,
-};
+ {
+ .name = "mems",
+ .read = cpuset_common_file_read,
+ .write = cpuset_common_file_write,
+ .private = FILE_MEMLIST,
+ },
-static struct cftype cft_cpu_exclusive = {
- .name = "cpu_exclusive",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_CPU_EXCLUSIVE,
-};
+ {
+ .name = "cpu_exclusive",
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_CPU_EXCLUSIVE,
+ },
-static struct cftype cft_mem_exclusive = {
- .name = "mem_exclusive",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_MEM_EXCLUSIVE,
-};
+ {
+ .name = "mem_exclusive",
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_MEM_EXCLUSIVE,
+ },
-static struct cftype cft_sched_load_balance = {
- .name = "sched_load_balance",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_SCHED_LOAD_BALANCE,
-};
+ {
+ .name = "mem_hardwall",
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_MEM_HARDWALL,
+ },
-static struct cftype cft_sched_relax_domain_level = {
- .name = "sched_relax_domain_level",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_SCHED_RELAX_DOMAIN_LEVEL,
-};
+ {
+ .name = "sched_load_balance",
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_SCHED_LOAD_BALANCE,
+ },
-static struct cftype cft_memory_migrate = {
- .name = "memory_migrate",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_MEMORY_MIGRATE,
+ {
+ .name = "sched_relax_domain_level",
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_SCHED_RELAX_DOMAIN_LEVEL,
+ },
+
+ {
+ .name = "memory_migrate",
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_MEMORY_MIGRATE,
+ },
+
+ {
+ .name = "memory_pressure",
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_MEMORY_PRESSURE,
+ },
+
+ {
+ .name = "memory_spread_page",
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_SPREAD_PAGE,
+ },
+
+ {
+ .name = "memory_spread_slab",
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
+ .private = FILE_SPREAD_SLAB,
+ },
};
static struct cftype cft_memory_pressure_enabled = {
.name = "memory_pressure_enabled",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
+ .read_u64 = cpuset_read_u64,
+ .write_u64 = cpuset_write_u64,
.private = FILE_MEMORY_PRESSURE_ENABLED,
};
-static struct cftype cft_memory_pressure = {
- .name = "memory_pressure",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_MEMORY_PRESSURE,
-};
-
-static struct cftype cft_spread_page = {
- .name = "memory_spread_page",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_SPREAD_PAGE,
-};
-
-static struct cftype cft_spread_slab = {
- .name = "memory_spread_slab",
- .read = cpuset_common_file_read,
- .write = cpuset_common_file_write,
- .private = FILE_SPREAD_SLAB,
-};
-
static int cpuset_populate(struct cgroup_subsys *ss, struct cgroup *cont)
{
int err;
- if ((err = cgroup_add_file(cont, ss, &cft_cpus)) < 0)
- return err;
- if ((err = cgroup_add_file(cont, ss, &cft_mems)) < 0)
- return err;
- if ((err = cgroup_add_file(cont, ss, &cft_cpu_exclusive)) < 0)
- return err;
- if ((err = cgroup_add_file(cont, ss, &cft_mem_exclusive)) < 0)
- return err;
- if ((err = cgroup_add_file(cont, ss, &cft_memory_migrate)) < 0)
- return err;
- if ((err = cgroup_add_file(cont, ss, &cft_sched_load_balance)) < 0)
- return err;
- if ((err = cgroup_add_file(cont, ss,
- &cft_sched_relax_domain_level)) < 0)
- return err;
- if ((err = cgroup_add_file(cont, ss, &cft_memory_pressure)) < 0)
- return err;
- if ((err = cgroup_add_file(cont, ss, &cft_spread_page)) < 0)
- return err;
- if ((err = cgroup_add_file(cont, ss, &cft_spread_slab)) < 0)
+ err = cgroup_add_files(cont, ss, files, ARRAY_SIZE(files));
+ if (err)
return err;
/* memory_pressure_enabled is in root cpuset only */
- if (err == 0 && !cont->parent)
+ if (!cont->parent)
err = cgroup_add_file(cont, ss,
- &cft_memory_pressure_enabled);
- return 0;
+ &cft_memory_pressure_enabled);
+ return err;
}
/*
@@ -1643,7 +1651,7 @@
cpuset_update_task_memory_state();
if (is_sched_load_balance(cs))
- update_flag(CS_SCHED_LOAD_BALANCE, cs, "0");
+ update_flag(CS_SCHED_LOAD_BALANCE, cs, 0);
number_of_cpusets--;
kfree(cs);
@@ -1708,7 +1716,8 @@
* Called by cgroup_scan_tasks() for each task in a cgroup.
* Return nonzero to stop the walk through the tasks.
*/
-void cpuset_do_move_task(struct task_struct *tsk, struct cgroup_scanner *scan)
+static void cpuset_do_move_task(struct task_struct *tsk,
+ struct cgroup_scanner *scan)
{
struct cpuset_hotplug_scanner *chsp;
@@ -1970,14 +1979,14 @@
}
/*
- * nearest_exclusive_ancestor() - Returns the nearest mem_exclusive
- * ancestor to the specified cpuset. Call holding callback_mutex.
- * If no ancestor is mem_exclusive (an unusual configuration), then
- * returns the root cpuset.
+ * nearest_hardwall_ancestor() - Returns the nearest mem_exclusive or
+ * mem_hardwall ancestor to the specified cpuset. Call holding
+ * callback_mutex. If no ancestor is mem_exclusive or mem_hardwall
+ * (an unusual configuration), then returns the root cpuset.
*/
-static const struct cpuset *nearest_exclusive_ancestor(const struct cpuset *cs)
+static const struct cpuset *nearest_hardwall_ancestor(const struct cpuset *cs)
{
- while (!is_mem_exclusive(cs) && cs->parent)
+ while (!(is_mem_exclusive(cs) || is_mem_hardwall(cs)) && cs->parent)
cs = cs->parent;
return cs;
}
@@ -1991,7 +2000,7 @@
* __GFP_THISNODE is set, 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.
+ * hardwalled cpuset ancestor to this tasks cpuset, yes.
* If the task has been OOM killed and has access to memory reserves
* as specified by the TIF_MEMDIE flag, yes.
* Otherwise, no.
@@ -2014,7 +2023,7 @@
* and do not allow allocations outside the current tasks cpuset
* unless the task has been OOM killed as is marked TIF_MEMDIE.
* GFP_KERNEL allocations are not so marked, so can escape to the
- * nearest enclosing mem_exclusive ancestor cpuset.
+ * nearest enclosing hardwalled ancestor cpuset.
*
* Scanning up parent cpusets requires callback_mutex. The
* __alloc_pages() routine only calls here with __GFP_HARDWALL bit
@@ -2037,7 +2046,7 @@
* in_interrupt - any node ok (current task context irrelevant)
* GFP_ATOMIC - any node ok
* TIF_MEMDIE - any node ok
- * GFP_KERNEL - any node in enclosing mem_exclusive cpuset ok
+ * GFP_KERNEL - any node in enclosing hardwalled cpuset ok
* GFP_USER - only nodes in current tasks mems allowed ok.
*
* Rule:
@@ -2074,7 +2083,7 @@
mutex_lock(&callback_mutex);
task_lock(current);
- cs = nearest_exclusive_ancestor(task_cs(current));
+ cs = nearest_hardwall_ancestor(task_cs(current));
task_unlock(current);
allowed = node_isset(node, cs->mems_allowed);
diff --git a/kernel/dma.c b/kernel/dma.c
index 6a82bb7..d2c60a8 100644
--- a/kernel/dma.c
+++ b/kernel/dma.c
@@ -149,12 +149,7 @@
static int __init proc_dma_init(void)
{
- struct proc_dir_entry *e;
-
- e = create_proc_entry("dma", 0, NULL);
- if (e)
- e->proc_fops = &proc_dma_operations;
-
+ proc_create("dma", 0, NULL, &proc_dma_operations);
return 0;
}
diff --git a/kernel/exit.c b/kernel/exit.c
index 2a9d98c..1510f78 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -19,6 +19,7 @@
#include <linux/acct.h>
#include <linux/tsacct_kern.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/binfmts.h>
#include <linux/nsproxy.h>
#include <linux/pid_namespace.h>
@@ -52,6 +53,11 @@
static void exit_mm(struct task_struct * tsk);
+static inline int task_detached(struct task_struct *p)
+{
+ return p->exit_signal == -1;
+}
+
static void __unhash_process(struct task_struct *p)
{
nr_threads--;
@@ -160,7 +166,7 @@
zap_leader = 0;
leader = p->group_leader;
if (leader != p && thread_group_empty(leader) && leader->exit_state == EXIT_ZOMBIE) {
- BUG_ON(leader->exit_signal == -1);
+ BUG_ON(task_detached(leader));
do_notify_parent(leader, leader->exit_signal);
/*
* If we were the last child thread and the leader has
@@ -170,7 +176,7 @@
* do_notify_parent() will have marked it self-reaping in
* that case.
*/
- zap_leader = (leader->exit_signal == -1);
+ zap_leader = task_detached(leader);
}
write_unlock_irq(&tasklist_lock);
@@ -329,13 +335,11 @@
pid_t nr = pid_nr(pid);
if (task_session(curr) != pid) {
- detach_pid(curr, PIDTYPE_SID);
- attach_pid(curr, PIDTYPE_SID, pid);
+ change_pid(curr, PIDTYPE_SID, pid);
set_task_session(curr, nr);
}
if (task_pgrp(curr) != pid) {
- detach_pid(curr, PIDTYPE_PGID);
- attach_pid(curr, PIDTYPE_PGID, pid);
+ change_pid(curr, PIDTYPE_PGID, pid);
set_task_pgrp(curr, nr);
}
}
@@ -557,6 +561,88 @@
EXPORT_SYMBOL_GPL(exit_fs);
+#ifdef CONFIG_MM_OWNER
+/*
+ * Task p is exiting and it owned mm, lets find a new owner for it
+ */
+static inline int
+mm_need_new_owner(struct mm_struct *mm, struct task_struct *p)
+{
+ /*
+ * If there are other users of the mm and the owner (us) is exiting
+ * we need to find a new owner to take on the responsibility.
+ */
+ if (!mm)
+ return 0;
+ if (atomic_read(&mm->mm_users) <= 1)
+ return 0;
+ if (mm->owner != p)
+ return 0;
+ return 1;
+}
+
+void mm_update_next_owner(struct mm_struct *mm)
+{
+ struct task_struct *c, *g, *p = current;
+
+retry:
+ if (!mm_need_new_owner(mm, p))
+ return;
+
+ read_lock(&tasklist_lock);
+ /*
+ * Search in the children
+ */
+ list_for_each_entry(c, &p->children, sibling) {
+ if (c->mm == mm)
+ goto assign_new_owner;
+ }
+
+ /*
+ * Search in the siblings
+ */
+ list_for_each_entry(c, &p->parent->children, sibling) {
+ if (c->mm == mm)
+ goto assign_new_owner;
+ }
+
+ /*
+ * Search through everything else. We should not get
+ * here often
+ */
+ do_each_thread(g, c) {
+ if (c->mm == mm)
+ goto assign_new_owner;
+ } while_each_thread(g, c);
+
+ read_unlock(&tasklist_lock);
+ return;
+
+assign_new_owner:
+ BUG_ON(c == p);
+ get_task_struct(c);
+ /*
+ * The task_lock protects c->mm from changing.
+ * We always want mm->owner->mm == mm
+ */
+ task_lock(c);
+ /*
+ * Delay read_unlock() till we have the task_lock()
+ * to ensure that c does not slip away underneath us
+ */
+ read_unlock(&tasklist_lock);
+ if (c->mm != mm) {
+ task_unlock(c);
+ put_task_struct(c);
+ goto retry;
+ }
+ cgroup_mm_owner_callbacks(mm->owner, c);
+ mm->owner = c;
+ task_unlock(c);
+ put_task_struct(c);
+}
+#endif /* CONFIG_MM_OWNER */
+
/*
* Turn us into a lazy TLB process if we
* aren't already..
@@ -596,6 +682,7 @@
/* We don't want this task to be frozen prematurely */
clear_freeze_flag(tsk);
task_unlock(tsk);
+ mm_update_next_owner(mm);
mmput(mm);
}
@@ -610,7 +697,7 @@
if (unlikely(traced)) {
/* Preserve ptrace links if someone else is tracing this child. */
list_del_init(&p->ptrace_list);
- if (p->parent != p->real_parent)
+ if (ptrace_reparented(p))
list_add(&p->ptrace_list, &p->real_parent->ptrace_children);
} else {
/* If this child is being traced, then we're the one tracing it
@@ -634,18 +721,18 @@
/* If this is a threaded reparent there is no need to
* notify anyone anything has happened.
*/
- if (p->real_parent->group_leader == father->group_leader)
+ if (same_thread_group(p->real_parent, father))
return;
/* We don't want people slaying init. */
- if (p->exit_signal != -1)
+ if (!task_detached(p))
p->exit_signal = SIGCHLD;
/* If we'd notified the old parent about this child's death,
* also notify the new parent.
*/
if (!traced && p->exit_state == EXIT_ZOMBIE &&
- p->exit_signal != -1 && thread_group_empty(p))
+ !task_detached(p) && thread_group_empty(p))
do_notify_parent(p, p->exit_signal);
kill_orphaned_pgrp(p, father);
@@ -698,18 +785,18 @@
} else {
/* reparent ptraced task to its real parent */
__ptrace_unlink (p);
- if (p->exit_state == EXIT_ZOMBIE && p->exit_signal != -1 &&
+ if (p->exit_state == EXIT_ZOMBIE && !task_detached(p) &&
thread_group_empty(p))
do_notify_parent(p, p->exit_signal);
}
/*
- * if the ptraced child is a zombie with exit_signal == -1
- * we must collect it before we exit, or it will remain
- * zombie forever since we prevented it from self-reap itself
- * while it was being traced by us, to be able to see it in wait4.
+ * if the ptraced child is a detached zombie we must collect
+ * it before we exit, or it will remain zombie forever since
+ * we prevented it from self-reap itself while it was being
+ * traced by us, to be able to see it in wait4.
*/
- if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && p->exit_signal == -1))
+ if (unlikely(ptrace && p->exit_state == EXIT_ZOMBIE && task_detached(p)))
list_add(&p->ptrace_list, &ptrace_dead);
}
@@ -766,29 +853,30 @@
* we have changed execution domain as these two values started
* the same after a fork.
*/
- if (tsk->exit_signal != SIGCHLD && tsk->exit_signal != -1 &&
+ if (tsk->exit_signal != SIGCHLD && !task_detached(tsk) &&
(tsk->parent_exec_id != tsk->real_parent->self_exec_id ||
- tsk->self_exec_id != tsk->parent_exec_id)
- && !capable(CAP_KILL))
+ tsk->self_exec_id != tsk->parent_exec_id) &&
+ !capable(CAP_KILL))
tsk->exit_signal = SIGCHLD;
-
/* If something other than our normal parent is ptracing us, then
* send it a SIGCHLD instead of honoring exit_signal. exit_signal
* only has special meaning to our real parent.
*/
- if (tsk->exit_signal != -1 && thread_group_empty(tsk)) {
- int signal = tsk->parent == tsk->real_parent ? tsk->exit_signal : SIGCHLD;
+ if (!task_detached(tsk) && thread_group_empty(tsk)) {
+ int signal = ptrace_reparented(tsk) ?
+ SIGCHLD : tsk->exit_signal;
do_notify_parent(tsk, signal);
} else if (tsk->ptrace) {
do_notify_parent(tsk, SIGCHLD);
}
state = EXIT_ZOMBIE;
- if (tsk->exit_signal == -1 && likely(!tsk->ptrace))
+ if (task_detached(tsk) && likely(!tsk->ptrace))
state = EXIT_DEAD;
tsk->exit_state = state;
+ /* mt-exec, de_thread() is waiting for us */
if (thread_group_leader(tsk) &&
tsk->signal->notify_count < 0 &&
tsk->signal->group_exit_task)
@@ -1032,12 +1120,13 @@
NORET_TYPE void
do_group_exit(int exit_code)
{
+ struct signal_struct *sig = current->signal;
+
BUG_ON(exit_code & 0x80); /* core dumps don't get here */
- if (current->signal->flags & SIGNAL_GROUP_EXIT)
- exit_code = current->signal->group_exit_code;
+ if (signal_group_exit(sig))
+ exit_code = sig->group_exit_code;
else if (!thread_group_empty(current)) {
- struct signal_struct *const sig = current->signal;
struct sighand_struct *const sighand = current->sighand;
spin_lock_irq(&sighand->siglock);
if (signal_group_exit(sig))
@@ -1089,7 +1178,7 @@
* Do not consider detached threads that are
* not ptraced:
*/
- if (p->exit_signal == -1 && !p->ptrace)
+ if (task_detached(p) && !p->ptrace)
return 0;
/* Wait for all children (clone and not) if __WALL is set;
@@ -1179,8 +1268,7 @@
return 0;
}
- /* traced means p->ptrace, but not vice versa */
- traced = (p->real_parent != p->parent);
+ traced = ptrace_reparented(p);
if (likely(!traced)) {
struct signal_struct *psig;
@@ -1281,9 +1369,9 @@
* If it's still not detached after that, don't release
* it now.
*/
- if (p->exit_signal != -1) {
+ if (!task_detached(p)) {
do_notify_parent(p, p->exit_signal);
- if (p->exit_signal != -1) {
+ if (!task_detached(p)) {
p->exit_state = EXIT_ZOMBIE;
p = NULL;
}
diff --git a/kernel/fork.c b/kernel/fork.c
index 6067e42..933e60e 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -22,6 +22,7 @@
#include <linux/mempolicy.h>
#include <linux/sem.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/key.h>
#include <linux/binfmts.h>
#include <linux/mman.h>
@@ -381,14 +382,13 @@
mm->ioctx_list = NULL;
mm->free_area_cache = TASK_UNMAPPED_BASE;
mm->cached_hole_size = ~0UL;
- mm_init_cgroup(mm, p);
+ mm_init_owner(mm, p);
if (likely(!mm_alloc_pgd(mm))) {
mm->def_flags = 0;
return mm;
}
- mm_free_cgroup(mm);
free_mm(mm);
return NULL;
}
@@ -432,13 +432,13 @@
if (atomic_dec_and_test(&mm->mm_users)) {
exit_aio(mm);
exit_mmap(mm);
+ set_mm_exe_file(mm, NULL);
if (!list_empty(&mm->mmlist)) {
spin_lock(&mmlist_lock);
list_del(&mm->mmlist);
spin_unlock(&mmlist_lock);
}
put_swap_token(mm);
- mm_free_cgroup(mm);
mmdrop(mm);
}
}
@@ -545,6 +545,8 @@
if (init_new_context(tsk, mm))
goto fail_nocontext;
+ dup_mm_exe_file(oldmm, mm);
+
err = dup_mmap(mm, oldmm);
if (err)
goto free_pt;
@@ -891,7 +893,7 @@
sig->group_exit_code = 0;
sig->group_exit_task = NULL;
sig->group_stop_count = 0;
- sig->curr_target = NULL;
+ sig->curr_target = tsk;
init_sigpending(&sig->shared_pending);
INIT_LIST_HEAD(&sig->posix_timers);
@@ -982,6 +984,13 @@
#endif
}
+#ifdef CONFIG_MM_OWNER
+void mm_init_owner(struct mm_struct *mm, struct task_struct *p)
+{
+ mm->owner = p;
+}
+#endif /* CONFIG_MM_OWNER */
+
/*
* This creates a new process as a copy of the old one,
* but does not actually start it yet.
@@ -1664,18 +1673,6 @@
}
/*
- * Unsharing of semundo for tasks created with CLONE_SYSVSEM is not
- * supported yet
- */
-static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **new_ulistp)
-{
- if (unshare_flags & CLONE_SYSVSEM)
- return -EINVAL;
-
- return 0;
-}
-
-/*
* unshare allows a process to 'unshare' part of the process
* context which was originally shared using clone. copy_*
* functions used by do_fork() cannot be used here directly
@@ -1690,8 +1687,8 @@
struct sighand_struct *new_sigh = NULL;
struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;
struct files_struct *fd, *new_fd = NULL;
- struct sem_undo_list *new_ulist = NULL;
struct nsproxy *new_nsproxy = NULL;
+ int do_sysvsem = 0;
check_unshare_flags(&unshare_flags);
@@ -1703,6 +1700,13 @@
CLONE_NEWNET))
goto bad_unshare_out;
+ /*
+ * CLONE_NEWIPC must also detach from the undolist: after switching
+ * to a new ipc namespace, the semaphore arrays from the old
+ * namespace are unreachable.
+ */
+ if (unshare_flags & (CLONE_NEWIPC|CLONE_SYSVSEM))
+ do_sysvsem = 1;
if ((err = unshare_thread(unshare_flags)))
goto bad_unshare_out;
if ((err = unshare_fs(unshare_flags, &new_fs)))
@@ -1713,13 +1717,17 @@
goto bad_unshare_cleanup_sigh;
if ((err = unshare_fd(unshare_flags, &new_fd)))
goto bad_unshare_cleanup_vm;
- if ((err = unshare_semundo(unshare_flags, &new_ulist)))
- goto bad_unshare_cleanup_fd;
if ((err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy,
new_fs)))
- goto bad_unshare_cleanup_semundo;
+ goto bad_unshare_cleanup_fd;
- if (new_fs || new_mm || new_fd || new_ulist || new_nsproxy) {
+ if (new_fs || new_mm || new_fd || do_sysvsem || new_nsproxy) {
+ if (do_sysvsem) {
+ /*
+ * CLONE_SYSVSEM is equivalent to sys_exit().
+ */
+ exit_sem(current);
+ }
if (new_nsproxy) {
switch_task_namespaces(current, new_nsproxy);
@@ -1755,7 +1763,6 @@
if (new_nsproxy)
put_nsproxy(new_nsproxy);
-bad_unshare_cleanup_semundo:
bad_unshare_cleanup_fd:
if (new_fd)
put_files_struct(new_fd);
diff --git a/kernel/futex.c b/kernel/futex.c
index e43945e..98092c9 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -1266,11 +1266,13 @@
if (!abs_time)
schedule();
else {
- hrtimer_init(&t.timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
+ hrtimer_init_on_stack(&t.timer, CLOCK_MONOTONIC,
+ HRTIMER_MODE_ABS);
hrtimer_init_sleeper(&t, current);
t.timer.expires = *abs_time;
- hrtimer_start(&t.timer, t.timer.expires, HRTIMER_MODE_ABS);
+ hrtimer_start(&t.timer, t.timer.expires,
+ HRTIMER_MODE_ABS);
if (!hrtimer_active(&t.timer))
t.task = NULL;
@@ -1286,6 +1288,8 @@
/* Flag if a timeout occured */
rem = (t.task == NULL);
+
+ destroy_hrtimer_on_stack(&t.timer);
}
}
__set_current_state(TASK_RUNNING);
@@ -1367,7 +1371,8 @@
if (time) {
to = &timeout;
- hrtimer_init(&to->timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ hrtimer_init_on_stack(&to->timer, CLOCK_REALTIME,
+ HRTIMER_MODE_ABS);
hrtimer_init_sleeper(to, current);
to->timer.expires = *time;
}
@@ -1581,6 +1586,8 @@
unqueue_me_pi(&q);
futex_unlock_mm(fshared);
+ if (to)
+ destroy_hrtimer_on_stack(&to->timer);
return ret != -EINTR ? ret : -ERESTARTNOINTR;
out_unlock_release_sem:
@@ -1588,6 +1595,8 @@
out_release_sem:
futex_unlock_mm(fshared);
+ if (to)
+ destroy_hrtimer_on_stack(&to->timer);
return ret;
uaddr_faulted:
@@ -1615,6 +1624,8 @@
if (!ret && (uval != -EFAULT))
goto retry;
+ if (to)
+ destroy_hrtimer_on_stack(&to->timer);
return ret;
}
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index dea4c91..9af1d6a 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -43,6 +43,7 @@
#include <linux/tick.h>
#include <linux/seq_file.h>
#include <linux/err.h>
+#include <linux/debugobjects.h>
#include <asm/uaccess.h>
@@ -342,6 +343,115 @@
return res;
}
+#ifdef CONFIG_DEBUG_OBJECTS_TIMERS
+
+static struct debug_obj_descr hrtimer_debug_descr;
+
+/*
+ * fixup_init is called when:
+ * - an active object is initialized
+ */
+static int hrtimer_fixup_init(void *addr, enum debug_obj_state state)
+{
+ struct hrtimer *timer = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ hrtimer_cancel(timer);
+ debug_object_init(timer, &hrtimer_debug_descr);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * fixup_activate is called when:
+ * - an active object is activated
+ * - an unknown object is activated (might be a statically initialized object)
+ */
+static int hrtimer_fixup_activate(void *addr, enum debug_obj_state state)
+{
+ switch (state) {
+
+ case ODEBUG_STATE_NOTAVAILABLE:
+ WARN_ON_ONCE(1);
+ return 0;
+
+ case ODEBUG_STATE_ACTIVE:
+ WARN_ON(1);
+
+ default:
+ return 0;
+ }
+}
+
+/*
+ * fixup_free is called when:
+ * - an active object is freed
+ */
+static int hrtimer_fixup_free(void *addr, enum debug_obj_state state)
+{
+ struct hrtimer *timer = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ hrtimer_cancel(timer);
+ debug_object_free(timer, &hrtimer_debug_descr);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static struct debug_obj_descr hrtimer_debug_descr = {
+ .name = "hrtimer",
+ .fixup_init = hrtimer_fixup_init,
+ .fixup_activate = hrtimer_fixup_activate,
+ .fixup_free = hrtimer_fixup_free,
+};
+
+static inline void debug_hrtimer_init(struct hrtimer *timer)
+{
+ debug_object_init(timer, &hrtimer_debug_descr);
+}
+
+static inline void debug_hrtimer_activate(struct hrtimer *timer)
+{
+ debug_object_activate(timer, &hrtimer_debug_descr);
+}
+
+static inline void debug_hrtimer_deactivate(struct hrtimer *timer)
+{
+ debug_object_deactivate(timer, &hrtimer_debug_descr);
+}
+
+static inline void debug_hrtimer_free(struct hrtimer *timer)
+{
+ debug_object_free(timer, &hrtimer_debug_descr);
+}
+
+static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
+ enum hrtimer_mode mode);
+
+void hrtimer_init_on_stack(struct hrtimer *timer, clockid_t clock_id,
+ enum hrtimer_mode mode)
+{
+ debug_object_init_on_stack(timer, &hrtimer_debug_descr);
+ __hrtimer_init(timer, clock_id, mode);
+}
+
+void destroy_hrtimer_on_stack(struct hrtimer *timer)
+{
+ debug_object_free(timer, &hrtimer_debug_descr);
+}
+
+#else
+static inline void debug_hrtimer_init(struct hrtimer *timer) { }
+static inline void debug_hrtimer_activate(struct hrtimer *timer) { }
+static inline void debug_hrtimer_deactivate(struct hrtimer *timer) { }
+#endif
+
/*
* Check, whether the timer is on the callback pending list
*/
@@ -567,6 +677,7 @@
/* Timer is expired, act upon the callback mode */
switch(timer->cb_mode) {
case HRTIMER_CB_IRQSAFE_NO_RESTART:
+ debug_hrtimer_deactivate(timer);
/*
* We can call the callback from here. No restart
* happens, so no danger of recursion
@@ -581,6 +692,7 @@
* the tick timer in the softirq ! The calling site
* takes care of this.
*/
+ debug_hrtimer_deactivate(timer);
return 1;
case HRTIMER_CB_IRQSAFE:
case HRTIMER_CB_SOFTIRQ:
@@ -735,6 +847,8 @@
struct hrtimer *entry;
int leftmost = 1;
+ debug_hrtimer_activate(timer);
+
/*
* Find the right place in the rbtree:
*/
@@ -831,6 +945,7 @@
* reprogramming happens in the interrupt handler. This is a
* rare case and less expensive than a smp call.
*/
+ debug_hrtimer_deactivate(timer);
timer_stats_hrtimer_clear_start_info(timer);
reprogram = base->cpu_base == &__get_cpu_var(hrtimer_bases);
__remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE,
@@ -878,6 +993,7 @@
tim = ktime_add_safe(tim, base->resolution);
#endif
}
+
timer->expires = tim;
timer_stats_hrtimer_set_start_info(timer);
@@ -1011,14 +1127,8 @@
}
#endif
-/**
- * hrtimer_init - initialize a timer to the given clock
- * @timer: the timer to be initialized
- * @clock_id: the clock to be used
- * @mode: timer mode abs/rel
- */
-void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
- enum hrtimer_mode mode)
+static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
+ enum hrtimer_mode mode)
{
struct hrtimer_cpu_base *cpu_base;
@@ -1039,6 +1149,19 @@
memset(timer->start_comm, 0, TASK_COMM_LEN);
#endif
}
+
+/**
+ * hrtimer_init - initialize a timer to the given clock
+ * @timer: the timer to be initialized
+ * @clock_id: the clock to be used
+ * @mode: timer mode abs/rel
+ */
+void hrtimer_init(struct hrtimer *timer, clockid_t clock_id,
+ enum hrtimer_mode mode)
+{
+ debug_hrtimer_init(timer);
+ __hrtimer_init(timer, clock_id, mode);
+}
EXPORT_SYMBOL_GPL(hrtimer_init);
/**
@@ -1072,6 +1195,7 @@
timer = list_entry(cpu_base->cb_pending.next,
struct hrtimer, cb_entry);
+ debug_hrtimer_deactivate(timer);
timer_stats_account_hrtimer(timer);
fn = timer->function;
@@ -1120,6 +1244,7 @@
enum hrtimer_restart (*fn)(struct hrtimer *);
int restart;
+ debug_hrtimer_deactivate(timer);
__remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0);
timer_stats_account_hrtimer(timer);
@@ -1378,22 +1503,27 @@
{
struct hrtimer_sleeper t;
struct timespec __user *rmtp;
+ int ret = 0;
- hrtimer_init(&t.timer, restart->nanosleep.index, HRTIMER_MODE_ABS);
+ hrtimer_init_on_stack(&t.timer, restart->nanosleep.index,
+ HRTIMER_MODE_ABS);
t.timer.expires.tv64 = restart->nanosleep.expires;
if (do_nanosleep(&t, HRTIMER_MODE_ABS))
- return 0;
+ goto out;
rmtp = restart->nanosleep.rmtp;
if (rmtp) {
- int ret = update_rmtp(&t.timer, rmtp);
+ ret = update_rmtp(&t.timer, rmtp);
if (ret <= 0)
- return ret;
+ goto out;
}
/* The other values in restart are already filled in */
- return -ERESTART_RESTARTBLOCK;
+ ret = -ERESTART_RESTARTBLOCK;
+out:
+ destroy_hrtimer_on_stack(&t.timer);
+ return ret;
}
long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
@@ -1401,20 +1531,23 @@
{
struct restart_block *restart;
struct hrtimer_sleeper t;
+ int ret = 0;
- hrtimer_init(&t.timer, clockid, mode);
+ hrtimer_init_on_stack(&t.timer, clockid, mode);
t.timer.expires = timespec_to_ktime(*rqtp);
if (do_nanosleep(&t, mode))
- return 0;
+ goto out;
/* Absolute timers do not update the rmtp value and restart: */
- if (mode == HRTIMER_MODE_ABS)
- return -ERESTARTNOHAND;
+ if (mode == HRTIMER_MODE_ABS) {
+ ret = -ERESTARTNOHAND;
+ goto out;
+ }
if (rmtp) {
- int ret = update_rmtp(&t.timer, rmtp);
+ ret = update_rmtp(&t.timer, rmtp);
if (ret <= 0)
- return ret;
+ goto out;
}
restart = ¤t_thread_info()->restart_block;
@@ -1423,7 +1556,10 @@
restart->nanosleep.rmtp = rmtp;
restart->nanosleep.expires = t.timer.expires.tv64;
- return -ERESTART_RESTARTBLOCK;
+ ret = -ERESTART_RESTARTBLOCK;
+out:
+ destroy_hrtimer_on_stack(&t.timer);
+ return ret;
}
asmlinkage long
@@ -1468,6 +1604,7 @@
while ((node = rb_first(&old_base->active))) {
timer = rb_entry(node, struct hrtimer, node);
BUG_ON(hrtimer_callback_running(timer));
+ debug_hrtimer_deactivate(timer);
__remove_hrtimer(timer, old_base, HRTIMER_STATE_INACTIVE, 0);
timer->base = new_base;
/*
diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c
index 6d9204f3..38a25b8 100644
--- a/kernel/irq/devres.c
+++ b/kernel/irq/devres.c
@@ -1,6 +1,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/device.h>
+#include <linux/gfp.h>
/*
* Device resource management aware IRQ request/free implementation.
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 438a014..46d6611 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/random.h>
#include <linux/interrupt.h>
+#include <linux/slab.h>
#include "internals.h"
@@ -149,6 +150,26 @@
}
EXPORT_SYMBOL(disable_irq);
+static void __enable_irq(struct irq_desc *desc, unsigned int irq)
+{
+ switch (desc->depth) {
+ case 0:
+ printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
+ WARN_ON(1);
+ break;
+ case 1: {
+ unsigned int status = desc->status & ~IRQ_DISABLED;
+
+ /* Prevent probing on this irq: */
+ desc->status = status | IRQ_NOPROBE;
+ check_irq_resend(desc, irq);
+ /* fall-through */
+ }
+ default:
+ desc->depth--;
+ }
+}
+
/**
* enable_irq - enable handling of an irq
* @irq: Interrupt to enable
@@ -168,22 +189,7 @@
return;
spin_lock_irqsave(&desc->lock, flags);
- switch (desc->depth) {
- case 0:
- printk(KERN_WARNING "Unbalanced enable for IRQ %d\n", irq);
- WARN_ON(1);
- break;
- case 1: {
- unsigned int status = desc->status & ~IRQ_DISABLED;
-
- /* Prevent probing on this irq: */
- desc->status = status | IRQ_NOPROBE;
- check_irq_resend(desc, irq);
- /* fall-through */
- }
- default:
- desc->depth--;
- }
+ __enable_irq(desc, irq);
spin_unlock_irqrestore(&desc->lock, flags);
}
EXPORT_SYMBOL(enable_irq);
@@ -364,7 +370,7 @@
compat_irq_chip_set_default_handler(desc);
desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING |
- IRQ_INPROGRESS);
+ IRQ_INPROGRESS | IRQ_SPURIOUS_DISABLED);
if (!(desc->status & IRQ_NOAUTOEN)) {
desc->depth = 0;
@@ -380,6 +386,16 @@
/* Reset broken irq detection when installing new handler */
desc->irq_count = 0;
desc->irqs_unhandled = 0;
+
+ /*
+ * Check whether we disabled the irq via the spurious handler
+ * before. Reenable it and give it another chance.
+ */
+ if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) {
+ desc->status &= ~IRQ_SPURIOUS_DISABLED;
+ __enable_irq(desc, irq);
+ }
+
spin_unlock_irqrestore(&desc->lock, flags);
new->irq = irq;
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 088dabb..c66d3f1 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -209,8 +209,8 @@
* Now kill the IRQ
*/
printk(KERN_EMERG "Disabling IRQ #%d\n", irq);
- desc->status |= IRQ_DISABLED;
- desc->depth = 1;
+ desc->status |= IRQ_DISABLED | IRQ_SPURIOUS_DISABLED;
+ desc->depth++;
desc->chip->disable(irq);
}
desc->irqs_unhandled = 0;
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index f091d13..6fc0040 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -472,11 +472,7 @@
static int __init kallsyms_init(void)
{
- struct proc_dir_entry *entry;
-
- entry = create_proc_entry("kallsyms", 0444, NULL);
- if (entry)
- entry->proc_fops = &kallsyms_operations;
+ proc_create("kallsyms", 0444, NULL, &kallsyms_operations);
return 0;
}
__initcall(kallsyms_init);
diff --git a/kernel/kexec.c b/kernel/kexec.c
index cb85c79..1c5fcac 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1217,7 +1217,7 @@
}
/* match ? */
- if (system_ram >= start && system_ram <= end) {
+ if (system_ram >= start && system_ram < end) {
*crash_size = size;
break;
}
diff --git a/kernel/kmod.c b/kernel/kmod.c
index e276404..8df97d3 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -27,6 +27,7 @@
#include <linux/mnt_namespace.h>
#include <linux/completion.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/workqueue.h>
#include <linux/security.h>
#include <linux/mount.h>
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 92cf693..bd1b9ea 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -98,7 +98,7 @@
struct sched_param param = { .sched_priority = 0 };
wait_for_completion(&create->started);
read_lock(&tasklist_lock);
- create->result = find_task_by_pid(pid);
+ create->result = find_task_by_pid_ns(pid, &init_pid_ns);
read_unlock(&tasklist_lock);
/*
* root may have changed our (kthreadd's) priority or CPU mask.
@@ -144,9 +144,9 @@
spin_lock(&kthread_create_lock);
list_add_tail(&create.list, &kthread_create_list);
- wake_up_process(kthreadd_task);
spin_unlock(&kthread_create_lock);
+ wake_up_process(kthreadd_task);
wait_for_completion(&create.done);
if (!IS_ERR(create.result)) {
diff --git a/kernel/latencytop.c b/kernel/latencytop.c
index 7c74dab..5e7b45c 100644
--- a/kernel/latencytop.c
+++ b/kernel/latencytop.c
@@ -233,14 +233,7 @@
static int __init init_lstats_procfs(void)
{
- struct proc_dir_entry *pe;
-
- pe = create_proc_entry("latency_stats", 0644, NULL);
- if (!pe)
- return -ENOMEM;
-
- pe->proc_fops = &lstats_fops;
-
+ proc_create("latency_stats", 0644, NULL, &lstats_fops);
return 0;
}
__initcall(init_lstats_procfs);
diff --git a/kernel/lockdep_proc.c b/kernel/lockdep_proc.c
index 8a135bd..dc5d296 100644
--- a/kernel/lockdep_proc.c
+++ b/kernel/lockdep_proc.c
@@ -660,20 +660,12 @@
static int __init lockdep_proc_init(void)
{
- struct proc_dir_entry *entry;
-
- entry = create_proc_entry("lockdep", S_IRUSR, NULL);
- if (entry)
- entry->proc_fops = &proc_lockdep_operations;
-
- entry = create_proc_entry("lockdep_stats", S_IRUSR, NULL);
- if (entry)
- entry->proc_fops = &proc_lockdep_stats_operations;
+ proc_create("lockdep", S_IRUSR, NULL, &proc_lockdep_operations);
+ proc_create("lockdep_stats", S_IRUSR, NULL,
+ &proc_lockdep_stats_operations);
#ifdef CONFIG_LOCK_STAT
- entry = create_proc_entry("lock_stat", S_IRUSR, NULL);
- if (entry)
- entry->proc_fops = &proc_lock_stat_operations;
+ proc_create("lock_stat", S_IRUSR, NULL, &proc_lock_stat_operations);
#endif
return 0;
diff --git a/kernel/marker.c b/kernel/marker.c
index 005b959..b5a9fe1 100644
--- a/kernel/marker.c
+++ b/kernel/marker.c
@@ -23,12 +23,13 @@
#include <linux/rcupdate.h>
#include <linux/marker.h>
#include <linux/err.h>
+#include <linux/slab.h>
extern struct marker __start___markers[];
extern struct marker __stop___markers[];
/* Set to 1 to enable marker debug output */
-const int marker_debug;
+static const int marker_debug;
/*
* markers_mutex nests inside module_mutex. Markers mutex protects the builtin
diff --git a/kernel/module.c b/kernel/module.c
index 8d6cccc..8674a39 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -164,131 +164,140 @@
return NULL;
}
-static void printk_unused_warning(const char *name)
+static bool always_ok(bool gplok, bool warn, const char *name)
{
- printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
- "however this module is using it.\n", name);
- printk(KERN_WARNING "This symbol will go away in the future.\n");
- printk(KERN_WARNING "Please evalute if this is the right api to use, "
- "and if it really is, submit a report the linux kernel "
- "mailinglist together with submitting your code for "
- "inclusion.\n");
+ return true;
}
-/* Find a symbol, return value, crc and module which owns it */
-static unsigned long __find_symbol(const char *name,
- struct module **owner,
- const unsigned long **crc,
- int gplok)
+static bool printk_unused_warning(bool gplok, bool warn, const char *name)
+{
+ if (warn) {
+ printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
+ "however this module is using it.\n", name);
+ printk(KERN_WARNING
+ "This symbol will go away in the future.\n");
+ printk(KERN_WARNING
+ "Please evalute if this is the right api to use and if "
+ "it really is, submit a report the linux kernel "
+ "mailinglist together with submitting your code for "
+ "inclusion.\n");
+ }
+ return true;
+}
+
+static bool gpl_only_unused_warning(bool gplok, bool warn, const char *name)
+{
+ if (!gplok)
+ return false;
+ return printk_unused_warning(gplok, warn, name);
+}
+
+static bool gpl_only(bool gplok, bool warn, const char *name)
+{
+ return gplok;
+}
+
+static bool warn_if_not_gpl(bool gplok, bool warn, const char *name)
+{
+ if (!gplok && warn) {
+ printk(KERN_WARNING "Symbol %s is being used "
+ "by a non-GPL module, which will not "
+ "be allowed in the future\n", name);
+ printk(KERN_WARNING "Please see the file "
+ "Documentation/feature-removal-schedule.txt "
+ "in the kernel source tree for more details.\n");
+ }
+ return true;
+}
+
+struct symsearch {
+ const struct kernel_symbol *start, *stop;
+ const unsigned long *crcs;
+ bool (*check)(bool gplok, bool warn, const char *name);
+};
+
+/* Look through this array of symbol tables for a symbol match which
+ * passes the check function. */
+static const struct kernel_symbol *search_symarrays(const struct symsearch *arr,
+ unsigned int num,
+ const char *name,
+ bool gplok,
+ bool warn,
+ const unsigned long **crc)
+{
+ unsigned int i;
+ const struct kernel_symbol *ks;
+
+ for (i = 0; i < num; i++) {
+ ks = lookup_symbol(name, arr[i].start, arr[i].stop);
+ if (!ks || !arr[i].check(gplok, warn, name))
+ continue;
+
+ if (crc)
+ *crc = symversion(arr[i].crcs, ks - arr[i].start);
+ return ks;
+ }
+ return NULL;
+}
+
+/* Find a symbol, return value, (optional) crc and (optional) module
+ * which owns it */
+static unsigned long find_symbol(const char *name,
+ struct module **owner,
+ const unsigned long **crc,
+ bool gplok,
+ bool warn)
{
struct module *mod;
const struct kernel_symbol *ks;
+ const struct symsearch arr[] = {
+ { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
+ always_ok },
+ { __start___ksymtab_gpl, __stop___ksymtab_gpl,
+ __start___kcrctab_gpl, gpl_only },
+ { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
+ __start___kcrctab_gpl_future, warn_if_not_gpl },
+ { __start___ksymtab_unused, __stop___ksymtab_unused,
+ __start___kcrctab_unused, printk_unused_warning },
+ { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
+ __start___kcrctab_unused_gpl, gpl_only_unused_warning },
+ };
/* Core kernel first. */
- *owner = NULL;
- ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
+ ks = search_symarrays(arr, ARRAY_SIZE(arr), name, gplok, warn, crc);
if (ks) {
- *crc = symversion(__start___kcrctab, (ks - __start___ksymtab));
- return ks->value;
- }
- if (gplok) {
- ks = lookup_symbol(name, __start___ksymtab_gpl,
- __stop___ksymtab_gpl);
- if (ks) {
- *crc = symversion(__start___kcrctab_gpl,
- (ks - __start___ksymtab_gpl));
- return ks->value;
- }
- }
- ks = lookup_symbol(name, __start___ksymtab_gpl_future,
- __stop___ksymtab_gpl_future);
- if (ks) {
- if (!gplok) {
- printk(KERN_WARNING "Symbol %s is being used "
- "by a non-GPL module, which will not "
- "be allowed in the future\n", name);
- printk(KERN_WARNING "Please see the file "
- "Documentation/feature-removal-schedule.txt "
- "in the kernel source tree for more "
- "details.\n");
- }
- *crc = symversion(__start___kcrctab_gpl_future,
- (ks - __start___ksymtab_gpl_future));
- return ks->value;
- }
-
- ks = lookup_symbol(name, __start___ksymtab_unused,
- __stop___ksymtab_unused);
- if (ks) {
- printk_unused_warning(name);
- *crc = symversion(__start___kcrctab_unused,
- (ks - __start___ksymtab_unused));
- return ks->value;
- }
-
- if (gplok)
- ks = lookup_symbol(name, __start___ksymtab_unused_gpl,
- __stop___ksymtab_unused_gpl);
- if (ks) {
- printk_unused_warning(name);
- *crc = symversion(__start___kcrctab_unused_gpl,
- (ks - __start___ksymtab_unused_gpl));
+ if (owner)
+ *owner = NULL;
return ks->value;
}
/* Now try modules. */
list_for_each_entry(mod, &modules, list) {
- *owner = mod;
- ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
- if (ks) {
- *crc = symversion(mod->crcs, (ks - mod->syms));
- return ks->value;
- }
+ struct symsearch arr[] = {
+ { mod->syms, mod->syms + mod->num_syms, mod->crcs,
+ always_ok },
+ { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
+ mod->gpl_crcs, gpl_only },
+ { mod->gpl_future_syms,
+ mod->gpl_future_syms + mod->num_gpl_future_syms,
+ mod->gpl_future_crcs, warn_if_not_gpl },
+ { mod->unused_syms,
+ mod->unused_syms + mod->num_unused_syms,
+ mod->unused_crcs, printk_unused_warning },
+ { mod->unused_gpl_syms,
+ mod->unused_gpl_syms + mod->num_unused_gpl_syms,
+ mod->unused_gpl_crcs, gpl_only_unused_warning },
+ };
- if (gplok) {
- ks = lookup_symbol(name, mod->gpl_syms,
- mod->gpl_syms + mod->num_gpl_syms);
- if (ks) {
- *crc = symversion(mod->gpl_crcs,
- (ks - mod->gpl_syms));
- return ks->value;
- }
- }
- ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);
+ ks = search_symarrays(arr, ARRAY_SIZE(arr),
+ name, gplok, warn, crc);
if (ks) {
- printk_unused_warning(name);
- *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));
- return ks->value;
- }
-
- if (gplok) {
- ks = lookup_symbol(name, mod->unused_gpl_syms,
- mod->unused_gpl_syms + mod->num_unused_gpl_syms);
- if (ks) {
- printk_unused_warning(name);
- *crc = symversion(mod->unused_gpl_crcs,
- (ks - mod->unused_gpl_syms));
- return ks->value;
- }
- }
- ks = lookup_symbol(name, mod->gpl_future_syms,
- (mod->gpl_future_syms +
- mod->num_gpl_future_syms));
- if (ks) {
- if (!gplok) {
- printk(KERN_WARNING "Symbol %s is being used "
- "by a non-GPL module, which will not "
- "be allowed in the future\n", name);
- printk(KERN_WARNING "Please see the file "
- "Documentation/feature-removal-schedule.txt "
- "in the kernel source tree for more "
- "details.\n");
- }
- *crc = symversion(mod->gpl_future_crcs,
- (ks - mod->gpl_future_syms));
+ if (owner)
+ *owner = mod;
return ks->value;
}
}
+
DEBUGP("Failed to find symbol %s\n", name);
return -ENOENT;
}
@@ -736,12 +745,13 @@
if (!forced && module_refcount(mod) != 0)
wait_for_zero_refcount(mod);
+ mutex_unlock(&module_mutex);
/* Final destruction now noone is using it. */
- if (mod->exit != NULL) {
- mutex_unlock(&module_mutex);
+ if (mod->exit != NULL)
mod->exit();
- mutex_lock(&module_mutex);
- }
+ blocking_notifier_call_chain(&module_notify_list,
+ MODULE_STATE_GOING, mod);
+ mutex_lock(&module_mutex);
/* Store the name of the last unloaded module for diagnostic purposes */
strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
free_module(mod);
@@ -777,10 +787,9 @@
void __symbol_put(const char *symbol)
{
struct module *owner;
- const unsigned long *crc;
preempt_disable();
- if (IS_ERR_VALUE(__find_symbol(symbol, &owner, &crc, 1)))
+ if (IS_ERR_VALUE(find_symbol(symbol, &owner, NULL, true, false)))
BUG();
module_put(owner);
preempt_enable();
@@ -924,13 +933,10 @@
struct module *mod)
{
const unsigned long *crc;
- struct module *owner;
- if (IS_ERR_VALUE(__find_symbol("struct_module",
- &owner, &crc, 1)))
+ if (IS_ERR_VALUE(find_symbol("struct_module", NULL, &crc, true, false)))
BUG();
- return check_version(sechdrs, versindex, "struct_module", mod,
- crc);
+ return check_version(sechdrs, versindex, "struct_module", mod, crc);
}
/* First part is kernel version, which we ignore. */
@@ -974,8 +980,8 @@
unsigned long ret;
const unsigned long *crc;
- ret = __find_symbol(name, &owner, &crc,
- !(mod->taints & TAINT_PROPRIETARY_MODULE));
+ ret = find_symbol(name, &owner, &crc,
+ !(mod->taints & TAINT_PROPRIETARY_MODULE), true);
if (!IS_ERR_VALUE(ret)) {
/* use_module can fail due to OOM,
or module initialization or unloading */
@@ -991,6 +997,20 @@
* J. Corbet <corbet@lwn.net>
*/
#if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS)
+struct module_sect_attr
+{
+ struct module_attribute mattr;
+ char *name;
+ unsigned long address;
+};
+
+struct module_sect_attrs
+{
+ struct attribute_group grp;
+ unsigned int nsections;
+ struct module_sect_attr attrs[0];
+};
+
static ssize_t module_sect_show(struct module_attribute *mattr,
struct module *mod, char *buf)
{
@@ -1001,7 +1021,7 @@
static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
{
- int section;
+ unsigned int section;
for (section = 0; section < sect_attrs->nsections; section++)
kfree(sect_attrs->attrs[section].name);
@@ -1362,10 +1382,9 @@
{
struct module *owner;
unsigned long value;
- const unsigned long *crc;
preempt_disable();
- value = __find_symbol(symbol, &owner, &crc, 1);
+ value = find_symbol(symbol, &owner, NULL, true, true);
if (IS_ERR_VALUE(value))
value = 0;
else if (strong_try_module_get(owner))
@@ -1382,33 +1401,33 @@
*/
static int verify_export_symbols(struct module *mod)
{
- const char *name = NULL;
- unsigned long i, ret = 0;
+ unsigned int i;
struct module *owner;
- const unsigned long *crc;
+ const struct kernel_symbol *s;
+ struct {
+ const struct kernel_symbol *sym;
+ unsigned int num;
+ } arr[] = {
+ { mod->syms, mod->num_syms },
+ { mod->gpl_syms, mod->num_gpl_syms },
+ { mod->gpl_future_syms, mod->num_gpl_future_syms },
+ { mod->unused_syms, mod->num_unused_syms },
+ { mod->unused_gpl_syms, mod->num_unused_gpl_syms },
+ };
- for (i = 0; i < mod->num_syms; i++)
- if (!IS_ERR_VALUE(__find_symbol(mod->syms[i].name,
- &owner, &crc, 1))) {
- name = mod->syms[i].name;
- ret = -ENOEXEC;
- goto dup;
+ for (i = 0; i < ARRAY_SIZE(arr); i++) {
+ for (s = arr[i].sym; s < arr[i].sym + arr[i].num; s++) {
+ if (!IS_ERR_VALUE(find_symbol(s->name, &owner,
+ NULL, true, false))) {
+ printk(KERN_ERR
+ "%s: exports duplicate symbol %s"
+ " (owned by %s)\n",
+ mod->name, s->name, module_name(owner));
+ return -ENOEXEC;
+ }
}
-
- for (i = 0; i < mod->num_gpl_syms; i++)
- if (!IS_ERR_VALUE(__find_symbol(mod->gpl_syms[i].name,
- &owner, &crc, 1))) {
- name = mod->gpl_syms[i].name;
- ret = -ENOEXEC;
- goto dup;
- }
-
-dup:
- if (ret)
- printk(KERN_ERR "%s: exports duplicate symbol %s (owned by %s)\n",
- mod->name, name, module_name(owner));
-
- return ret;
+ }
+ return 0;
}
/* Change all symbols so that st_value encodes the pointer directly. */
@@ -1814,8 +1833,9 @@
unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
#endif
- /* Don't keep modinfo section */
+ /* Don't keep modinfo and version sections. */
sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
+ sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
#ifdef CONFIG_KALLSYMS
/* Keep symbol and string tables for decoding later. */
sechdrs[symindex].sh_flags |= SHF_ALLOC;
@@ -1977,7 +1997,8 @@
mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
if (unusedgplcrcindex)
- mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;
+ mod->unused_gpl_crcs
+ = (void *)sechdrs[unusedgplcrcindex].sh_addr;
#ifdef CONFIG_MODVERSIONS
if ((mod->num_syms && !crcindex) ||
@@ -2171,6 +2192,8 @@
mod->state = MODULE_STATE_GOING;
synchronize_sched();
module_put(mod);
+ blocking_notifier_call_chain(&module_notify_list,
+ MODULE_STATE_GOING, mod);
mutex_lock(&module_mutex);
free_module(mod);
mutex_unlock(&module_mutex);
diff --git a/kernel/notifier.c b/kernel/notifier.c
index 643360d..823be115 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -31,6 +31,21 @@
return 0;
}
+static int notifier_chain_cond_register(struct notifier_block **nl,
+ struct notifier_block *n)
+{
+ while ((*nl) != NULL) {
+ if ((*nl) == n)
+ return 0;
+ if (n->priority > (*nl)->priority)
+ break;
+ nl = &((*nl)->next);
+ }
+ n->next = *nl;
+ rcu_assign_pointer(*nl, n);
+ return 0;
+}
+
static int notifier_chain_unregister(struct notifier_block **nl,
struct notifier_block *n)
{
@@ -205,6 +220,29 @@
EXPORT_SYMBOL_GPL(blocking_notifier_chain_register);
/**
+ * blocking_notifier_chain_cond_register - Cond add notifier to a blocking notifier chain
+ * @nh: Pointer to head of the blocking notifier chain
+ * @n: New entry in notifier chain
+ *
+ * Adds a notifier to a blocking notifier chain, only if not already
+ * present in the chain.
+ * Must be called in process context.
+ *
+ * Currently always returns zero.
+ */
+int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh,
+ struct notifier_block *n)
+{
+ int ret;
+
+ down_write(&nh->rwsem);
+ ret = notifier_chain_cond_register(&nh->head, n);
+ up_write(&nh->rwsem);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(blocking_notifier_chain_cond_register);
+
+/**
* blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain
* @nh: Pointer to head of the blocking notifier chain
* @n: Entry to remove from notifier chain
diff --git a/kernel/ns_cgroup.c b/kernel/ns_cgroup.c
index aead4d6..48d7ed6 100644
--- a/kernel/ns_cgroup.c
+++ b/kernel/ns_cgroup.c
@@ -7,6 +7,8 @@
#include <linux/module.h>
#include <linux/cgroup.h>
#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/nsproxy.h>
struct ns_cgroup {
struct cgroup_subsys_state css;
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index f5d332c..adc7851 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -139,6 +139,18 @@
goto out;
}
+ /*
+ * CLONE_NEWIPC must detach from the undolist: after switching
+ * to a new ipc namespace, the semaphore arrays from the old
+ * namespace are unreachable. In clone parlance, CLONE_SYSVSEM
+ * means share undolist with parent, so we must forbid using
+ * it along with CLONE_NEWIPC.
+ */
+ if ((flags & CLONE_NEWIPC) && (flags & CLONE_SYSVSEM)) {
+ err = -EINVAL;
+ goto out;
+ }
+
new_ns = create_new_namespaces(flags, tsk, tsk->fs);
if (IS_ERR(new_ns)) {
err = PTR_ERR(new_ns);
diff --git a/kernel/panic.c b/kernel/panic.c
index 24af9f8..425567f 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -153,6 +153,8 @@
* 'M' - System experienced a machine check exception.
* 'B' - System has hit bad_page.
* 'U' - Userspace-defined naughtiness.
+ * 'A' - ACPI table overridden.
+ * 'W' - Taint on warning.
*
* The string is overwritten by the next call to print_taint().
*/
@@ -161,7 +163,7 @@
{
static char buf[20];
if (tainted) {
- snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c",
+ snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c%c",
tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G',
tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
@@ -170,7 +172,8 @@
tainted & TAINT_BAD_PAGE ? 'B' : ' ',
tainted & TAINT_USER ? 'U' : ' ',
tainted & TAINT_DIE ? 'D' : ' ',
- tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ');
+ tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ',
+ tainted & TAINT_WARN ? 'W' : ' ');
}
else
snprintf(buf, sizeof(buf), "Not tainted");
@@ -312,6 +315,7 @@
print_modules();
dump_stack();
print_oops_end_marker();
+ add_taint(TAINT_WARN);
}
EXPORT_SYMBOL(warn_on_slowpath);
#endif
diff --git a/kernel/pid.c b/kernel/pid.c
index 4776915..20d59fa 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -111,10 +111,11 @@
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock);
-static void free_pidmap(struct pid_namespace *pid_ns, int pid)
+static void free_pidmap(struct upid *upid)
{
- struct pidmap *map = pid_ns->pidmap + pid / BITS_PER_PAGE;
- int offset = pid & BITS_PER_PAGE_MASK;
+ int nr = upid->nr;
+ struct pidmap *map = upid->ns->pidmap + nr / BITS_PER_PAGE;
+ int offset = nr & BITS_PER_PAGE_MASK;
clear_bit(offset, map->page);
atomic_inc(&map->nr_free);
@@ -232,7 +233,7 @@
spin_unlock_irqrestore(&pidmap_lock, flags);
for (i = 0; i <= pid->level; i++)
- free_pidmap(pid->numbers[i].ns, pid->numbers[i].nr);
+ free_pidmap(pid->numbers + i);
call_rcu(&pid->rcu, delayed_put_pid);
}
@@ -278,8 +279,8 @@
return pid;
out_free:
- for (i++; i <= ns->level; i++)
- free_pidmap(pid->numbers[i].ns, pid->numbers[i].nr);
+ while (++i <= ns->level)
+ free_pidmap(pid->numbers + i);
kmem_cache_free(ns->pid_cachep, pid);
pid = NULL;
@@ -316,7 +317,7 @@
/*
* attach_pid() must be called with the tasklist_lock write-held.
*/
-int attach_pid(struct task_struct *task, enum pid_type type,
+void attach_pid(struct task_struct *task, enum pid_type type,
struct pid *pid)
{
struct pid_link *link;
@@ -324,11 +325,10 @@
link = &task->pids[type];
link->pid = pid;
hlist_add_head_rcu(&link->node, &pid->tasks[type]);
-
- return 0;
}
-void detach_pid(struct task_struct *task, enum pid_type type)
+static void __change_pid(struct task_struct *task, enum pid_type type,
+ struct pid *new)
{
struct pid_link *link;
struct pid *pid;
@@ -338,7 +338,7 @@
pid = link->pid;
hlist_del_rcu(&link->node);
- link->pid = NULL;
+ link->pid = new;
for (tmp = PIDTYPE_MAX; --tmp >= 0; )
if (!hlist_empty(&pid->tasks[tmp]))
@@ -347,13 +347,24 @@
free_pid(pid);
}
+void detach_pid(struct task_struct *task, enum pid_type type)
+{
+ __change_pid(task, type, NULL);
+}
+
+void change_pid(struct task_struct *task, enum pid_type type,
+ struct pid *pid)
+{
+ __change_pid(task, type, pid);
+ attach_pid(task, type, pid);
+}
+
/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */
void transfer_pid(struct task_struct *old, struct task_struct *new,
enum pid_type type)
{
new->pids[type].pid = old->pids[type].pid;
hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node);
- old->pids[type].pid = NULL;
}
struct task_struct *pid_task(struct pid *pid, enum pid_type type)
@@ -380,12 +391,6 @@
EXPORT_SYMBOL(find_task_by_pid_type_ns);
-struct task_struct *find_task_by_pid(pid_t nr)
-{
- return find_task_by_pid_type_ns(PIDTYPE_PID, nr, &init_pid_ns);
-}
-EXPORT_SYMBOL(find_task_by_pid);
-
struct task_struct *find_task_by_vpid(pid_t vnr)
{
return find_task_by_pid_type_ns(PIDTYPE_PID, vnr,
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index 5ca37fa..98702b4 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -66,7 +66,7 @@
return NULL;
}
-static struct pid_namespace *create_pid_namespace(int level)
+static struct pid_namespace *create_pid_namespace(unsigned int level)
{
struct pid_namespace *ns;
int i;
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index ae5c6c1..f1525ad 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -4,8 +4,9 @@
#include <linux/sched.h>
#include <linux/posix-timers.h>
-#include <asm/uaccess.h>
#include <linux/errno.h>
+#include <linux/math64.h>
+#include <asm/uaccess.h>
static int check_clock(const clockid_t which_clock)
{
@@ -47,12 +48,10 @@
union cpu_time_count cpu,
struct timespec *tp)
{
- if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) {
- tp->tv_sec = div_long_long_rem(cpu.sched,
- NSEC_PER_SEC, &tp->tv_nsec);
- } else {
+ if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED)
+ *tp = ns_to_timespec(cpu.sched);
+ else
cputime_to_timespec(cpu.cpu, tp);
- }
}
static inline int cpu_time_before(const clockid_t which_clock,
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index 8476956..dbd8398 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -310,8 +310,7 @@
if (timr->it_sigev_notify & SIGEV_THREAD_ID) {
struct task_struct *leader;
- int ret = send_sigqueue(timr->it_sigev_signo, timr->sigq,
- timr->it_process);
+ int ret = send_sigqueue(timr->sigq, timr->it_process, 0);
if (likely(ret >= 0))
return ret;
@@ -322,8 +321,7 @@
timr->it_process = leader;
}
- return send_group_sigqueue(timr->it_sigev_signo, timr->sigq,
- timr->it_process);
+ return send_sigqueue(timr->sigq, timr->it_process, 1);
}
EXPORT_SYMBOL_GPL(posix_timer_event);
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 6233f3b..b45da40 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -19,16 +19,6 @@
will issue the hlt instruction if nothing is to be done, thereby
sending the processor to sleep and saving power.
-config PM_LEGACY
- bool "Legacy Power Management API (DEPRECATED)"
- depends on PM
- default n
- ---help---
- Support for pm_register() and friends. This old API is obsoleted
- by the driver model.
-
- If unsure, say N.
-
config PM_DEBUG
bool "Power Management Debug Support"
depends on PM
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index f7dfff2..597823b 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -4,7 +4,6 @@
endif
obj-y := main.o
-obj-$(CONFIG_PM_LEGACY) += pm.o
obj-$(CONFIG_PM_SLEEP) += process.o console.o
obj-$(CONFIG_HIBERNATION) += swsusp.o disk.o snapshot.o swap.o user.o
diff --git a/kernel/power/pm.c b/kernel/power/pm.c
deleted file mode 100644
index 60c73fa..0000000
--- a/kernel/power/pm.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * pm.c - Power management interface
- *
- * Copyright (C) 2000 Andrew Henroid
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/pm.h>
-#include <linux/pm_legacy.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-/*
- * Locking notes:
- * pm_devs_lock can be a semaphore providing pm ops are not called
- * from an interrupt handler (already a bad idea so no change here). Each
- * change must be protected so that an unlink of an entry doesn't clash
- * with a pm send - which is permitted to sleep in the current architecture
- *
- * Module unloads clashing with pm events now work out safely, the module
- * unload path will block until the event has been sent. It may well block
- * until a resume but that will be fine.
- */
-
-static DEFINE_MUTEX(pm_devs_lock);
-static LIST_HEAD(pm_devs);
-
-/**
- * pm_register - register a device with power management
- * @type: device type
- * @id: device ID
- * @callback: callback function
- *
- * Add a device to the list of devices that wish to be notified about
- * power management events. A &pm_dev structure is returned on success,
- * on failure the return is %NULL.
- *
- * The callback function will be called in process context and
- * it may sleep.
- */
-
-struct pm_dev *pm_register(pm_dev_t type,
- unsigned long id,
- pm_callback callback)
-{
- struct pm_dev *dev = kzalloc(sizeof(struct pm_dev), GFP_KERNEL);
- if (dev) {
- dev->type = type;
- dev->id = id;
- dev->callback = callback;
-
- mutex_lock(&pm_devs_lock);
- list_add(&dev->entry, &pm_devs);
- mutex_unlock(&pm_devs_lock);
- }
- return dev;
-}
-
-/**
- * pm_send - send request to a single device
- * @dev: device to send to
- * @rqst: power management request
- * @data: data for the callback
- *
- * Issue a power management request to a given device. The
- * %PM_SUSPEND and %PM_RESUME events are handled specially. The
- * data field must hold the intended next state. No call is made
- * if the state matches.
- *
- * BUGS: what stops two power management requests occurring in parallel
- * and conflicting.
- *
- * WARNING: Calling pm_send directly is not generally recommended, in
- * particular there is no locking against the pm_dev going away. The
- * caller must maintain all needed locking or have 'inside knowledge'
- * on the safety. Also remember that this function is not locked against
- * pm_unregister. This means that you must handle SMP races on callback
- * execution and unload yourself.
- */
-
-static int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
-{
- int status = 0;
- unsigned long prev_state, next_state;
-
- if (in_interrupt())
- BUG();
-
- switch (rqst) {
- case PM_SUSPEND:
- case PM_RESUME:
- prev_state = dev->state;
- next_state = (unsigned long) data;
- if (prev_state != next_state) {
- if (dev->callback)
- status = (*dev->callback)(dev, rqst, data);
- if (!status) {
- dev->state = next_state;
- dev->prev_state = prev_state;
- }
- }
- else {
- dev->prev_state = prev_state;
- }
- break;
- default:
- if (dev->callback)
- status = (*dev->callback)(dev, rqst, data);
- break;
- }
- return status;
-}
-
-/*
- * Undo incomplete request
- */
-static void pm_undo_all(struct pm_dev *last)
-{
- struct list_head *entry = last->entry.prev;
- while (entry != &pm_devs) {
- struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
- if (dev->state != dev->prev_state) {
- /* previous state was zero (running) resume or
- * previous state was non-zero (suspended) suspend
- */
- pm_request_t undo = (dev->prev_state
- ? PM_SUSPEND:PM_RESUME);
- pm_send(dev, undo, (void*) dev->prev_state);
- }
- entry = entry->prev;
- }
-}
-
-/**
- * pm_send_all - send request to all managed devices
- * @rqst: power management request
- * @data: data for the callback
- *
- * Issue a power management request to a all devices. The
- * %PM_SUSPEND events are handled specially. Any device is
- * permitted to fail a suspend by returning a non zero (error)
- * value from its callback function. If any device vetoes a
- * suspend request then all other devices that have suspended
- * during the processing of this request are restored to their
- * previous state.
- *
- * WARNING: This function takes the pm_devs_lock. The lock is not dropped until
- * the callbacks have completed. This prevents races against pm locking
- * functions, races against module unload pm_unregister code. It does
- * mean however that you must not issue pm_ functions within the callback
- * or you will deadlock and users will hate you.
- *
- * Zero is returned on success. If a suspend fails then the status
- * from the device that vetoes the suspend is returned.
- *
- * BUGS: what stops two power management requests occurring in parallel
- * and conflicting.
- */
-
-int pm_send_all(pm_request_t rqst, void *data)
-{
- struct list_head *entry;
-
- mutex_lock(&pm_devs_lock);
- entry = pm_devs.next;
- while (entry != &pm_devs) {
- struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
- if (dev->callback) {
- int status = pm_send(dev, rqst, data);
- if (status) {
- /* return devices to previous state on
- * failed suspend request
- */
- if (rqst == PM_SUSPEND)
- pm_undo_all(dev);
- mutex_unlock(&pm_devs_lock);
- return status;
- }
- }
- entry = entry->next;
- }
- mutex_unlock(&pm_devs_lock);
- return 0;
-}
-
-EXPORT_SYMBOL(pm_register);
-EXPORT_SYMBOL(pm_send_all);
-
diff --git a/kernel/printk.c b/kernel/printk.c
index bdd4ea8..8fb01c3 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -111,6 +111,9 @@
char name[8]; /* Name of the driver */
int index; /* Minor dev. to use */
char *options; /* Options for the driver */
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+ char *brl_options; /* Options for braille driver */
+#endif
};
#define MAX_CMDLINECONSOLES 8
@@ -808,15 +811,60 @@
#endif
+static int __add_preferred_console(char *name, int idx, char *options,
+ char *brl_options)
+{
+ struct console_cmdline *c;
+ int i;
+
+ /*
+ * See if this tty is not yet registered, and
+ * if we have a slot free.
+ */
+ for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
+ if (strcmp(console_cmdline[i].name, name) == 0 &&
+ console_cmdline[i].index == idx) {
+ if (!brl_options)
+ selected_console = i;
+ return 0;
+ }
+ if (i == MAX_CMDLINECONSOLES)
+ return -E2BIG;
+ if (!brl_options)
+ selected_console = i;
+ c = &console_cmdline[i];
+ strlcpy(c->name, name, sizeof(c->name));
+ c->options = options;
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+ c->brl_options = brl_options;
+#endif
+ c->index = idx;
+ return 0;
+}
/*
* Set up a list of consoles. Called from init/main.c
*/
static int __init console_setup(char *str)
{
char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for index */
- char *s, *options;
+ char *s, *options, *brl_options = NULL;
int idx;
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+ if (!memcmp(str, "brl,", 4)) {
+ brl_options = "";
+ str += 4;
+ } else if (!memcmp(str, "brl=", 4)) {
+ brl_options = str + 4;
+ str = strchr(brl_options, ',');
+ if (!str) {
+ printk(KERN_ERR "need port name after brl=\n");
+ return 1;
+ }
+ *(str++) = 0;
+ }
+#endif
+
/*
* Decode str into name, index, options.
*/
@@ -841,7 +889,7 @@
idx = simple_strtoul(s, NULL, 10);
*s = 0;
- add_preferred_console(buf, idx, options);
+ __add_preferred_console(buf, idx, options, brl_options);
return 1;
}
__setup("console=", console_setup);
@@ -861,28 +909,7 @@
*/
int add_preferred_console(char *name, int idx, char *options)
{
- struct console_cmdline *c;
- int i;
-
- /*
- * See if this tty is not yet registered, and
- * if we have a slot free.
- */
- for (i = 0; i < MAX_CMDLINECONSOLES && console_cmdline[i].name[0]; i++)
- if (strcmp(console_cmdline[i].name, name) == 0 &&
- console_cmdline[i].index == idx) {
- selected_console = i;
- return 0;
- }
- if (i == MAX_CMDLINECONSOLES)
- return -E2BIG;
- selected_console = i;
- c = &console_cmdline[i];
- memcpy(c->name, name, sizeof(c->name));
- c->name[sizeof(c->name) - 1] = 0;
- c->options = options;
- c->index = idx;
- return 0;
+ return __add_preferred_console(name, idx, options, NULL);
}
int update_console_cmdline(char *name, int idx, char *name_new, int idx_new, char *options)
@@ -894,7 +921,7 @@
if (strcmp(console_cmdline[i].name, name) == 0 &&
console_cmdline[i].index == idx) {
c = &console_cmdline[i];
- memcpy(c->name, name_new, sizeof(c->name));
+ strlcpy(c->name, name_new, sizeof(c->name));
c->name[sizeof(c->name) - 1] = 0;
c->options = options;
c->index = idx_new;
@@ -1163,6 +1190,16 @@
continue;
if (console->index < 0)
console->index = console_cmdline[i].index;
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+ if (console_cmdline[i].brl_options) {
+ console->flags |= CON_BRL;
+ braille_register_console(console,
+ console_cmdline[i].index,
+ console_cmdline[i].options,
+ console_cmdline[i].brl_options);
+ return;
+ }
+#endif
if (console->setup &&
console->setup(console, console_cmdline[i].options) != 0)
break;
@@ -1221,6 +1258,11 @@
struct console *a, *b;
int res = 1;
+#ifdef CONFIG_A11Y_BRAILLE_CONSOLE
+ if (console->flags & CON_BRL)
+ return braille_unregister_console(console);
+#endif
+
acquire_console_sem();
if (console_drivers == console) {
console_drivers=console->next;
@@ -1272,8 +1314,8 @@
*/
void tty_write_message(struct tty_struct *tty, char *msg)
{
- if (tty && tty->driver->write)
- tty->driver->write(tty, msg, strlen(msg));
+ if (tty && tty->ops->write)
+ tty->ops->write(tty, msg, strlen(msg));
return;
}
@@ -1287,31 +1329,7 @@
*/
int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
{
- static DEFINE_SPINLOCK(ratelimit_lock);
- static unsigned toks = 10 * 5 * HZ;
- static unsigned long last_msg;
- static int missed;
- unsigned long flags;
- unsigned long now = jiffies;
-
- spin_lock_irqsave(&ratelimit_lock, flags);
- toks += now - last_msg;
- last_msg = now;
- if (toks > (ratelimit_burst * ratelimit_jiffies))
- toks = ratelimit_burst * ratelimit_jiffies;
- if (toks >= ratelimit_jiffies) {
- int lost = missed;
-
- missed = 0;
- toks -= ratelimit_jiffies;
- spin_unlock_irqrestore(&ratelimit_lock, flags);
- if (lost)
- printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
- return 1;
- }
- missed++;
- spin_unlock_irqrestore(&ratelimit_lock, flags);
- return 0;
+ return __ratelimit(ratelimit_jiffies, ratelimit_burst);
}
EXPORT_SYMBOL(__printk_ratelimit);
diff --git a/kernel/profile.c b/kernel/profile.c
index 606d738..ae7ead8 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -587,10 +587,10 @@
return 0;
if (create_hash_tables())
return -1;
- entry = create_proc_entry("profile", S_IWUSR | S_IRUGO, NULL);
+ entry = proc_create("profile", S_IWUSR | S_IRUGO,
+ NULL, &proc_profile_operations);
if (!entry)
return 0;
- entry->proc_fops = &proc_profile_operations;
entry->size = (1+prof_len) * sizeof(atomic_t);
hotcpu_notifier(profile_cpu_callback, 0);
return 0;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index dac4b4e..6c19e94 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -73,7 +73,7 @@
BUG_ON(!child->ptrace);
child->ptrace = 0;
- if (!list_empty(&child->ptrace_list)) {
+ if (ptrace_reparented(child)) {
list_del_init(&child->ptrace_list);
remove_parent(child);
child->parent = child->real_parent;
@@ -168,8 +168,6 @@
audit_ptrace(task);
retval = -EPERM;
- if (task->pid <= 1)
- goto out;
if (same_thread_group(task, current))
goto out;
@@ -208,8 +206,7 @@
__ptrace_link(task, current);
- force_sig_specific(SIGSTOP, task);
-
+ send_sig_info(SIGSTOP, SEND_SIG_FORCED, task);
bad:
write_unlock_irqrestore(&tasklist_lock, flags);
task_unlock(task);
@@ -522,12 +519,6 @@
{
struct task_struct *child;
- /*
- * Tracing init is not allowed.
- */
- if (pid == 1)
- return ERR_PTR(-EPERM);
-
read_lock(&tasklist_lock);
child = find_task_by_vpid(pid);
if (child)
@@ -543,7 +534,6 @@
#define arch_ptrace_attach(child) do { } while (0)
#endif
-#ifndef __ARCH_SYS_PTRACE
asmlinkage long sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
@@ -591,7 +581,6 @@
unlock_kernel();
return ret;
}
-#endif /* __ARCH_SYS_PTRACE */
int generic_ptrace_peekdata(struct task_struct *tsk, long addr, long data)
{
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 47894f9..33acc424 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -45,6 +45,7 @@
#include <linux/byteorder/swabb.h>
#include <linux/stat.h>
#include <linux/srcu.h>
+#include <linux/slab.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and "
diff --git a/kernel/relay.c b/kernel/relay.c
index d6204a4..7de644c 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -65,6 +65,35 @@
.close = relay_file_mmap_close,
};
+/*
+ * allocate an array of pointers of struct page
+ */
+static struct page **relay_alloc_page_array(unsigned int n_pages)
+{
+ struct page **array;
+ size_t pa_size = n_pages * sizeof(struct page *);
+
+ if (pa_size > PAGE_SIZE) {
+ array = vmalloc(pa_size);
+ if (array)
+ memset(array, 0, pa_size);
+ } else {
+ array = kzalloc(pa_size, GFP_KERNEL);
+ }
+ return array;
+}
+
+/*
+ * free an array of pointers of struct page
+ */
+static void relay_free_page_array(struct page **array)
+{
+ if (is_vmalloc_addr(array))
+ vfree(array);
+ else
+ kfree(array);
+}
+
/**
* relay_mmap_buf: - mmap channel buffer to process address space
* @buf: relay channel buffer
@@ -109,7 +138,7 @@
*size = PAGE_ALIGN(*size);
n_pages = *size >> PAGE_SHIFT;
- buf->page_array = kcalloc(n_pages, sizeof(struct page *), GFP_KERNEL);
+ buf->page_array = relay_alloc_page_array(n_pages);
if (!buf->page_array)
return NULL;
@@ -130,7 +159,7 @@
depopulate:
for (j = 0; j < i; j++)
__free_page(buf->page_array[j]);
- kfree(buf->page_array);
+ relay_free_page_array(buf->page_array);
return NULL;
}
@@ -189,7 +218,7 @@
vunmap(buf->start);
for (i = 0; i < buf->page_count; i++)
__free_page(buf->page_array[i]);
- kfree(buf->page_array);
+ relay_free_page_array(buf->page_array);
}
chan->buf[buf->cpu] = NULL;
kfree(buf->padding);
@@ -1162,7 +1191,7 @@
ret = 0;
spliced = 0;
- while (len) {
+ while (len && !spliced) {
ret = subbuf_splice_actor(in, ppos, pipe, len, flags, &nonpad_ret);
if (ret < 0)
break;
diff --git a/kernel/res_counter.c b/kernel/res_counter.c
index efbfc0f..d3c61b4 100644
--- a/kernel/res_counter.c
+++ b/kernel/res_counter.c
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/parser.h>
#include <linux/fs.h>
+#include <linux/slab.h>
#include <linux/res_counter.h>
#include <linux/uaccess.h>
@@ -27,6 +28,8 @@
}
counter->usage += val;
+ if (counter->usage > counter->max_usage)
+ counter->max_usage = counter->usage;
return 0;
}
@@ -65,6 +68,8 @@
switch (member) {
case RES_USAGE:
return &counter->usage;
+ case RES_MAX_USAGE:
+ return &counter->max_usage;
case RES_LIMIT:
return &counter->limit;
case RES_FAILCNT:
@@ -92,6 +97,11 @@
pos, buf, s - buf);
}
+u64 res_counter_read_u64(struct res_counter *counter, int member)
+{
+ return *res_counter_member(counter, member);
+}
+
ssize_t res_counter_write(struct res_counter *counter, int member,
const char __user *userbuf, size_t nbytes, loff_t *pos,
int (*write_strategy)(char *st_buf, unsigned long long *val))
diff --git a/kernel/resource.c b/kernel/resource.c
index cee12cc..74af2d7 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -131,14 +131,8 @@
static int __init ioresources_init(void)
{
- struct proc_dir_entry *entry;
-
- entry = create_proc_entry("ioports", 0, NULL);
- if (entry)
- entry->proc_fops = &proc_ioports_operations;
- entry = create_proc_entry("iomem", 0, NULL);
- if (entry)
- entry->proc_fops = &proc_iomem_operations;
+ proc_create("ioports", 0, NULL, &proc_ioports_operations);
+ proc_create("iomem", 0, NULL, &proc_iomem_operations);
return 0;
}
__initcall(ioresources_init);
diff --git a/kernel/sched.c b/kernel/sched.c
index 740fb40..34bcc5b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -8025,7 +8025,7 @@
se->my_q = cfs_rq;
se->load.weight = tg->shares;
- se->load.inv_weight = div64_64(1ULL<<32, se->load.weight);
+ se->load.inv_weight = div64_u64(1ULL<<32, se->load.weight);
se->parent = parent;
}
#endif
@@ -8692,7 +8692,7 @@
dequeue_entity(cfs_rq, se, 0);
se->load.weight = shares;
- se->load.inv_weight = div64_64((1ULL<<32), shares);
+ se->load.inv_weight = div64_u64((1ULL<<32), shares);
if (on_rq)
enqueue_entity(cfs_rq, se, 0);
@@ -8787,7 +8787,7 @@
if (runtime == RUNTIME_INF)
return 1ULL << 16;
- return div64_64(runtime << 16, period);
+ return div64_u64(runtime << 16, period);
}
#ifdef CONFIG_CGROUP_SCHED
@@ -9057,13 +9057,13 @@
}
#ifdef CONFIG_FAIR_GROUP_SCHED
-static int cpu_shares_write_uint(struct cgroup *cgrp, struct cftype *cftype,
+static int cpu_shares_write_u64(struct cgroup *cgrp, struct cftype *cftype,
u64 shareval)
{
return sched_group_set_shares(cgroup_tg(cgrp), shareval);
}
-static u64 cpu_shares_read_uint(struct cgroup *cgrp, struct cftype *cft)
+static u64 cpu_shares_read_u64(struct cgroup *cgrp, struct cftype *cft)
{
struct task_group *tg = cgroup_tg(cgrp);
@@ -9073,48 +9073,14 @@
#ifdef CONFIG_RT_GROUP_SCHED
static ssize_t cpu_rt_runtime_write(struct cgroup *cgrp, struct cftype *cft,
- struct file *file,
- const char __user *userbuf,
- size_t nbytes, loff_t *unused_ppos)
+ s64 val)
{
- char buffer[64];
- int retval = 0;
- s64 val;
- char *end;
-
- if (!nbytes)
- return -EINVAL;
- if (nbytes >= sizeof(buffer))
- return -E2BIG;
- if (copy_from_user(buffer, userbuf, nbytes))
- return -EFAULT;
-
- buffer[nbytes] = 0; /* nul-terminate */
-
- /* strip newline if necessary */
- if (nbytes && (buffer[nbytes-1] == '\n'))
- buffer[nbytes-1] = 0;
- val = simple_strtoll(buffer, &end, 0);
- if (*end)
- return -EINVAL;
-
- /* Pass to subsystem */
- retval = sched_group_set_rt_runtime(cgroup_tg(cgrp), val);
- if (!retval)
- retval = nbytes;
- return retval;
+ return sched_group_set_rt_runtime(cgroup_tg(cgrp), val);
}
-static ssize_t cpu_rt_runtime_read(struct cgroup *cgrp, struct cftype *cft,
- struct file *file,
- char __user *buf, size_t nbytes,
- loff_t *ppos)
+static s64 cpu_rt_runtime_read(struct cgroup *cgrp, struct cftype *cft)
{
- char tmp[64];
- long val = sched_group_rt_runtime(cgroup_tg(cgrp));
- int len = sprintf(tmp, "%ld\n", val);
-
- return simple_read_from_buffer(buf, nbytes, ppos, tmp, len);
+ return sched_group_rt_runtime(cgroup_tg(cgrp));
}
static int cpu_rt_period_write_uint(struct cgroup *cgrp, struct cftype *cftype,
@@ -9133,20 +9099,20 @@
#ifdef CONFIG_FAIR_GROUP_SCHED
{
.name = "shares",
- .read_uint = cpu_shares_read_uint,
- .write_uint = cpu_shares_write_uint,
+ .read_u64 = cpu_shares_read_u64,
+ .write_u64 = cpu_shares_write_u64,
},
#endif
#ifdef CONFIG_RT_GROUP_SCHED
{
.name = "rt_runtime_us",
- .read = cpu_rt_runtime_read,
- .write = cpu_rt_runtime_write,
+ .read_s64 = cpu_rt_runtime_read,
+ .write_s64 = cpu_rt_runtime_write,
},
{
.name = "rt_period_us",
- .read_uint = cpu_rt_period_read_uint,
- .write_uint = cpu_rt_period_write_uint,
+ .read_u64 = cpu_rt_period_read_uint,
+ .write_u64 = cpu_rt_period_write_uint,
},
#endif
};
@@ -9277,8 +9243,8 @@
static struct cftype files[] = {
{
.name = "usage",
- .read_uint = cpuusage_read,
- .write_uint = cpuusage_write,
+ .read_u64 = cpuusage_read,
+ .write_u64 = cpuusage_write,
},
};
diff --git a/kernel/sched_debug.c b/kernel/sched_debug.c
index f3f4af4..6b4a125 100644
--- a/kernel/sched_debug.c
+++ b/kernel/sched_debug.c
@@ -277,12 +277,9 @@
{
struct proc_dir_entry *pe;
- pe = create_proc_entry("sched_debug", 0644, NULL);
+ pe = proc_create("sched_debug", 0644, NULL, &sched_debug_fops);
if (!pe)
return -ENOMEM;
-
- pe->proc_fops = &sched_debug_fops;
-
return 0;
}
@@ -360,8 +357,8 @@
avg_per_cpu = p->se.sum_exec_runtime;
if (p->se.nr_migrations) {
- avg_per_cpu = div64_64(avg_per_cpu,
- p->se.nr_migrations);
+ avg_per_cpu = div64_u64(avg_per_cpu,
+ p->se.nr_migrations);
} else {
avg_per_cpu = -1LL;
}
diff --git a/kernel/signal.c b/kernel/signal.c
index 64ad0ed..72bb4f5 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -39,11 +39,19 @@
static struct kmem_cache *sigqueue_cachep;
+static int __sig_ignored(struct task_struct *t, int sig)
+{
+ void __user *handler;
+
+ /* Is it explicitly or implicitly ignored? */
+
+ handler = t->sighand->action[sig - 1].sa.sa_handler;
+ return handler == SIG_IGN ||
+ (handler == SIG_DFL && sig_kernel_ignore(sig));
+}
static int sig_ignored(struct task_struct *t, int sig)
{
- void __user * handler;
-
/*
* Tracers always want to know about signals..
*/
@@ -58,10 +66,7 @@
if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig))
return 0;
- /* Is it explicitly or implicitly ignored? */
- handler = t->sighand->action[sig-1].sa.sa_handler;
- return handler == SIG_IGN ||
- (handler == SIG_DFL && sig_kernel_ignore(sig));
+ return __sig_ignored(t, sig);
}
/*
@@ -372,7 +377,7 @@
*/
int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
{
- int signr = 0;
+ int signr;
/* We only dequeue private signals from ourselves, we don't let
* signalfd steal them
@@ -405,8 +410,12 @@
}
}
}
+
recalc_sigpending();
- if (signr && unlikely(sig_kernel_stop(signr))) {
+ if (!signr)
+ return 0;
+
+ if (unlikely(sig_kernel_stop(signr))) {
/*
* Set a marker that we have dequeued a stop signal. Our
* caller might release the siglock and then the pending
@@ -422,9 +431,7 @@
if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT))
tsk->signal->flags |= SIGNAL_STOP_DEQUEUED;
}
- if (signr &&
- ((info->si_code & __SI_MASK) == __SI_TIMER) &&
- info->si_sys_private) {
+ if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) {
/*
* Release the siglock to ensure proper locking order
* of timer locks outside of siglocks. Note, we leave
@@ -526,21 +533,34 @@
static int check_kill_permission(int sig, struct siginfo *info,
struct task_struct *t)
{
- int error = -EINVAL;
+ struct pid *sid;
+ int error;
+
if (!valid_signal(sig))
+ return -EINVAL;
+
+ if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info)))
+ return 0;
+
+ error = audit_signal_info(sig, t); /* Let audit system see the signal */
+ if (error)
return error;
- if (info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info))) {
- error = audit_signal_info(sig, t); /* Let audit system see the signal */
- if (error)
- return error;
- error = -EPERM;
- if (((sig != SIGCONT) ||
- (task_session_nr(current) != task_session_nr(t)))
- && (current->euid ^ t->suid) && (current->euid ^ t->uid)
- && (current->uid ^ t->suid) && (current->uid ^ t->uid)
- && !capable(CAP_KILL))
- return error;
+ if ((current->euid ^ t->suid) && (current->euid ^ t->uid) &&
+ (current->uid ^ t->suid) && (current->uid ^ t->uid) &&
+ !capable(CAP_KILL)) {
+ switch (sig) {
+ case SIGCONT:
+ sid = task_session(t);
+ /*
+ * We don't return the error if sid == NULL. The
+ * task was unhashed, the caller must notice this.
+ */
+ if (!sid || sid == task_session(current))
+ break;
+ default:
+ return -EPERM;
+ }
}
return security_task_kill(t, info, sig, 0);
@@ -550,62 +570,44 @@
static void do_notify_parent_cldstop(struct task_struct *tsk, int why);
/*
- * Handle magic process-wide effects of stop/continue signals.
- * Unlike the signal actions, these happen immediately at signal-generation
+ * Handle magic process-wide effects of stop/continue signals. Unlike
+ * the signal actions, these happen immediately at signal-generation
* time regardless of blocking, ignoring, or handling. This does the
* actual continuing for SIGCONT, but not the actual stopping for stop
- * signals. The process stop is done as a signal action for SIG_DFL.
+ * signals. The process stop is done as a signal action for SIG_DFL.
+ *
+ * Returns true if the signal should be actually delivered, otherwise
+ * it should be dropped.
*/
-static void handle_stop_signal(int sig, struct task_struct *p)
+static int prepare_signal(int sig, struct task_struct *p)
{
+ struct signal_struct *signal = p->signal;
struct task_struct *t;
- if (p->signal->flags & SIGNAL_GROUP_EXIT)
+ if (unlikely(signal->flags & SIGNAL_GROUP_EXIT)) {
/*
- * The process is in the middle of dying already.
+ * The process is in the middle of dying, nothing to do.
*/
- return;
-
- if (sig_kernel_stop(sig)) {
+ } else if (sig_kernel_stop(sig)) {
/*
* This is a stop signal. Remove SIGCONT from all queues.
*/
- rm_from_queue(sigmask(SIGCONT), &p->signal->shared_pending);
+ rm_from_queue(sigmask(SIGCONT), &signal->shared_pending);
t = p;
do {
rm_from_queue(sigmask(SIGCONT), &t->pending);
- t = next_thread(t);
- } while (t != p);
+ } while_each_thread(p, t);
} else if (sig == SIGCONT) {
+ unsigned int why;
/*
* Remove all stop signals from all queues,
* and wake all threads.
*/
- if (unlikely(p->signal->group_stop_count > 0)) {
- /*
- * There was a group stop in progress. We'll
- * pretend it finished before we got here. We are
- * obliged to report it to the parent: if the
- * SIGSTOP happened "after" this SIGCONT, then it
- * would have cleared this pending SIGCONT. If it
- * happened "before" this SIGCONT, then the parent
- * got the SIGCHLD about the stop finishing before
- * the continue happened. We do the notification
- * now, and it's as if the stop had finished and
- * the SIGCHLD was pending on entry to this kill.
- */
- p->signal->group_stop_count = 0;
- p->signal->flags = SIGNAL_STOP_CONTINUED;
- spin_unlock(&p->sighand->siglock);
- do_notify_parent_cldstop(p, CLD_STOPPED);
- spin_lock(&p->sighand->siglock);
- }
- rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending);
+ rm_from_queue(SIG_KERNEL_STOP_MASK, &signal->shared_pending);
t = p;
do {
unsigned int state;
rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending);
-
/*
* If there is a handler for SIGCONT, we must make
* sure that no thread returns to user mode before
@@ -615,7 +617,7 @@
* running the handler. With the TIF_SIGPENDING
* flag set, the thread will pause and acquire the
* siglock that we hold now and until we've queued
- * the pending signal.
+ * the pending signal.
*
* Wake up the stopped thread _after_ setting
* TIF_SIGPENDING
@@ -626,49 +628,163 @@
state |= TASK_INTERRUPTIBLE;
}
wake_up_state(t, state);
+ } while_each_thread(p, t);
- t = next_thread(t);
- } while (t != p);
+ /*
+ * Notify the parent with CLD_CONTINUED if we were stopped.
+ *
+ * If we were in the middle of a group stop, we pretend it
+ * was already finished, and then continued. Since SIGCHLD
+ * doesn't queue we report only CLD_STOPPED, as if the next
+ * CLD_CONTINUED was dropped.
+ */
+ why = 0;
+ if (signal->flags & SIGNAL_STOP_STOPPED)
+ why |= SIGNAL_CLD_CONTINUED;
+ else if (signal->group_stop_count)
+ why |= SIGNAL_CLD_STOPPED;
- if (p->signal->flags & SIGNAL_STOP_STOPPED) {
+ if (why) {
/*
- * We were in fact stopped, and are now continued.
- * Notify the parent with CLD_CONTINUED.
+ * The first thread which returns from finish_stop()
+ * will take ->siglock, notice SIGNAL_CLD_MASK, and
+ * notify its parent. See get_signal_to_deliver().
*/
- p->signal->flags = SIGNAL_STOP_CONTINUED;
- p->signal->group_exit_code = 0;
- spin_unlock(&p->sighand->siglock);
- do_notify_parent_cldstop(p, CLD_CONTINUED);
- spin_lock(&p->sighand->siglock);
+ signal->flags = why | SIGNAL_STOP_CONTINUED;
+ signal->group_stop_count = 0;
+ signal->group_exit_code = 0;
} else {
/*
* We are not stopped, but there could be a stop
* signal in the middle of being processed after
* being removed from the queue. Clear that too.
*/
- p->signal->flags = 0;
+ signal->flags &= ~SIGNAL_STOP_DEQUEUED;
}
- } else if (sig == SIGKILL) {
- /*
- * Make sure that any pending stop signal already dequeued
- * is undone by the wakeup for SIGKILL.
- */
- p->signal->flags = 0;
}
+
+ return !sig_ignored(p, sig);
+}
+
+/*
+ * Test if P wants to take SIG. After we've checked all threads with this,
+ * it's equivalent to finding no threads not blocking SIG. Any threads not
+ * blocking SIG were ruled out because they are not running and already
+ * have pending signals. Such threads will dequeue from the shared queue
+ * as soon as they're available, so putting the signal on the shared queue
+ * will be equivalent to sending it to one such thread.
+ */
+static inline int wants_signal(int sig, struct task_struct *p)
+{
+ if (sigismember(&p->blocked, sig))
+ return 0;
+ if (p->flags & PF_EXITING)
+ return 0;
+ if (sig == SIGKILL)
+ return 1;
+ if (task_is_stopped_or_traced(p))
+ return 0;
+ return task_curr(p) || !signal_pending(p);
+}
+
+static void complete_signal(int sig, struct task_struct *p, int group)
+{
+ struct signal_struct *signal = p->signal;
+ struct task_struct *t;
+
+ /*
+ * Now find a thread we can wake up to take the signal off the queue.
+ *
+ * If the main thread wants the signal, it gets first crack.
+ * Probably the least surprising to the average bear.
+ */
+ if (wants_signal(sig, p))
+ t = p;
+ else if (!group || thread_group_empty(p))
+ /*
+ * There is just one thread and it does not need to be woken.
+ * It will dequeue unblocked signals before it runs again.
+ */
+ return;
+ else {
+ /*
+ * Otherwise try to find a suitable thread.
+ */
+ t = signal->curr_target;
+ while (!wants_signal(sig, t)) {
+ t = next_thread(t);
+ if (t == signal->curr_target)
+ /*
+ * No thread needs to be woken.
+ * Any eligible threads will see
+ * the signal in the queue soon.
+ */
+ return;
+ }
+ signal->curr_target = t;
+ }
+
+ /*
+ * Found a killable thread. If the signal will be fatal,
+ * then start taking the whole group down immediately.
+ */
+ if (sig_fatal(p, sig) &&
+ !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) &&
+ !sigismember(&t->real_blocked, sig) &&
+ (sig == SIGKILL || !(t->ptrace & PT_PTRACED))) {
+ /*
+ * This signal will be fatal to the whole group.
+ */
+ if (!sig_kernel_coredump(sig)) {
+ /*
+ * Start a group exit and wake everybody up.
+ * This way we don't have other threads
+ * running and doing things after a slower
+ * thread has the fatal signal pending.
+ */
+ signal->flags = SIGNAL_GROUP_EXIT;
+ signal->group_exit_code = sig;
+ signal->group_stop_count = 0;
+ t = p;
+ do {
+ sigaddset(&t->pending.signal, SIGKILL);
+ signal_wake_up(t, 1);
+ } while_each_thread(p, t);
+ return;
+ }
+ }
+
+ /*
+ * The signal is already in the shared-pending queue.
+ * Tell the chosen thread to wake up and dequeue it.
+ */
+ signal_wake_up(t, sig == SIGKILL);
+ return;
+}
+
+static inline int legacy_queue(struct sigpending *signals, int sig)
+{
+ return (sig < SIGRTMIN) && sigismember(&signals->signal, sig);
}
static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
- struct sigpending *signals)
+ int group)
{
- struct sigqueue * q = NULL;
- int ret = 0;
+ struct sigpending *pending;
+ struct sigqueue *q;
+ assert_spin_locked(&t->sighand->siglock);
+ if (!prepare_signal(sig, t))
+ return 0;
+
+ pending = group ? &t->signal->shared_pending : &t->pending;
/*
- * Deliver the signal to listening signalfds. This must be called
- * with the sighand lock held.
+ * Short-circuit ignored signals and support queuing
+ * exactly one non-rt signal, so that we can get more
+ * detailed information about the cause of the signal.
*/
- signalfd_notify(t, sig);
-
+ if (legacy_queue(pending, sig))
+ return 0;
/*
* fast-pathed signals for kernel-internal things like SIGSTOP
* or SIGKILL.
@@ -688,7 +804,7 @@
(is_si_special(info) ||
info->si_code >= 0)));
if (q) {
- list_add_tail(&q->list, &signals->list);
+ list_add_tail(&q->list, &pending->list);
switch ((unsigned long) info) {
case (unsigned long) SEND_SIG_NOINFO:
q->info.si_signo = sig;
@@ -718,13 +834,12 @@
}
out_set:
- sigaddset(&signals->signal, sig);
- return ret;
+ signalfd_notify(t, sig);
+ sigaddset(&pending->signal, sig);
+ complete_signal(sig, t, group);
+ return 0;
}
-#define LEGACY_QUEUE(sigptr, sig) \
- (((sig) < SIGRTMIN) && sigismember(&(sigptr)->signal, (sig)))
-
int print_fatal_signals;
static void print_fatal_signal(struct pt_regs *regs, int signr)
@@ -757,29 +872,16 @@
__setup("print-fatal-signals=", setup_print_fatal_signals);
+int
+__group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
+{
+ return send_signal(sig, info, p, 1);
+}
+
static int
specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
{
- int ret = 0;
-
- BUG_ON(!irqs_disabled());
- assert_spin_locked(&t->sighand->siglock);
-
- /* Short-circuit ignored signals. */
- if (sig_ignored(t, sig))
- goto out;
-
- /* Support queueing exactly one non-rt signal, so that we
- can get more detailed information about the cause of
- the signal. */
- if (LEGACY_QUEUE(&t->pending, sig))
- goto out;
-
- ret = send_signal(sig, info, t, &t->pending);
- if (!ret && !sigismember(&t->blocked, sig))
- signal_wake_up(t, sig == SIGKILL);
-out:
- return ret;
+ return send_signal(sig, info, t, 0);
}
/*
@@ -790,7 +892,8 @@
* since we do not want to have a signal handler that was blocked
* be invoked when user space had explicitly blocked it.
*
- * We don't want to have recursive SIGSEGV's etc, for example.
+ * We don't want to have recursive SIGSEGV's etc, for example,
+ * that is why we also clear SIGNAL_UNKILLABLE.
*/
int
force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
@@ -810,6 +913,8 @@
recalc_sigpending_and_wake(t);
}
}
+ if (action->sa.sa_handler == SIG_DFL)
+ t->signal->flags &= ~SIGNAL_UNKILLABLE;
ret = specific_send_sig_info(sig, info, t);
spin_unlock_irqrestore(&t->sighand->siglock, flags);
@@ -823,134 +928,6 @@
}
/*
- * Test if P wants to take SIG. After we've checked all threads with this,
- * it's equivalent to finding no threads not blocking SIG. Any threads not
- * blocking SIG were ruled out because they are not running and already
- * have pending signals. Such threads will dequeue from the shared queue
- * as soon as they're available, so putting the signal on the shared queue
- * will be equivalent to sending it to one such thread.
- */
-static inline int wants_signal(int sig, struct task_struct *p)
-{
- if (sigismember(&p->blocked, sig))
- return 0;
- if (p->flags & PF_EXITING)
- return 0;
- if (sig == SIGKILL)
- return 1;
- if (task_is_stopped_or_traced(p))
- return 0;
- return task_curr(p) || !signal_pending(p);
-}
-
-static void
-__group_complete_signal(int sig, struct task_struct *p)
-{
- struct task_struct *t;
-
- /*
- * Now find a thread we can wake up to take the signal off the queue.
- *
- * If the main thread wants the signal, it gets first crack.
- * Probably the least surprising to the average bear.
- */
- if (wants_signal(sig, p))
- t = p;
- else if (thread_group_empty(p))
- /*
- * There is just one thread and it does not need to be woken.
- * It will dequeue unblocked signals before it runs again.
- */
- return;
- else {
- /*
- * Otherwise try to find a suitable thread.
- */
- t = p->signal->curr_target;
- if (t == NULL)
- /* restart balancing at this thread */
- t = p->signal->curr_target = p;
-
- while (!wants_signal(sig, t)) {
- t = next_thread(t);
- if (t == p->signal->curr_target)
- /*
- * No thread needs to be woken.
- * Any eligible threads will see
- * the signal in the queue soon.
- */
- return;
- }
- p->signal->curr_target = t;
- }
-
- /*
- * Found a killable thread. If the signal will be fatal,
- * then start taking the whole group down immediately.
- */
- if (sig_fatal(p, sig) && !(p->signal->flags & SIGNAL_GROUP_EXIT) &&
- !sigismember(&t->real_blocked, sig) &&
- (sig == SIGKILL || !(t->ptrace & PT_PTRACED))) {
- /*
- * This signal will be fatal to the whole group.
- */
- if (!sig_kernel_coredump(sig)) {
- /*
- * Start a group exit and wake everybody up.
- * This way we don't have other threads
- * running and doing things after a slower
- * thread has the fatal signal pending.
- */
- p->signal->flags = SIGNAL_GROUP_EXIT;
- p->signal->group_exit_code = sig;
- p->signal->group_stop_count = 0;
- t = p;
- do {
- sigaddset(&t->pending.signal, SIGKILL);
- signal_wake_up(t, 1);
- } while_each_thread(p, t);
- return;
- }
- }
-
- /*
- * The signal is already in the shared-pending queue.
- * Tell the chosen thread to wake up and dequeue it.
- */
- signal_wake_up(t, sig == SIGKILL);
- return;
-}
-
-int
-__group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
-{
- int ret = 0;
-
- assert_spin_locked(&p->sighand->siglock);
- handle_stop_signal(sig, p);
-
- /* Short-circuit ignored signals. */
- if (sig_ignored(p, sig))
- return ret;
-
- if (LEGACY_QUEUE(&p->signal->shared_pending, sig))
- /* This is a non-RT signal and we already have one queued. */
- return ret;
-
- /*
- * Put this signal on the shared-pending queue, or fail with EAGAIN.
- * We always use the shared queue for process-wide signals,
- * to avoid several races.
- */
- ret = send_signal(sig, info, p, &p->signal->shared_pending);
- if (unlikely(ret))
- return ret;
-
- __group_complete_signal(sig, p);
- return 0;
-}
-
-/*
* Nuke all other threads in the group.
*/
void zap_other_threads(struct task_struct *p)
@@ -978,13 +955,11 @@
}
EXPORT_SYMBOL(__fatal_signal_pending);
-/*
- * Must be called under rcu_read_lock() or with tasklist_lock read-held.
- */
struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long *flags)
{
struct sighand_struct *sighand;
+ rcu_read_lock();
for (;;) {
sighand = rcu_dereference(tsk->sighand);
if (unlikely(sighand == NULL))
@@ -995,6 +970,7 @@
break;
spin_unlock_irqrestore(&sighand->siglock, *flags);
}
+ rcu_read_unlock();
return sighand;
}
@@ -1043,9 +1019,6 @@
struct task_struct *p;
rcu_read_lock();
- if (unlikely(sig_needs_tasklist(sig)))
- read_lock(&tasklist_lock);
-
retry:
p = pid_task(pid, PIDTYPE_PID);
if (p) {
@@ -1059,10 +1032,8 @@
*/
goto retry;
}
-
- if (unlikely(sig_needs_tasklist(sig)))
- read_unlock(&tasklist_lock);
rcu_read_unlock();
+
return error;
}
@@ -1159,8 +1130,7 @@
*/
/*
- * These two are the most common entry points. They send a signal
- * just to the specific thread.
+ * The caller must ensure the task can't exit.
*/
int
send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
@@ -1175,17 +1145,9 @@
if (!valid_signal(sig))
return -EINVAL;
- /*
- * 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.
- */
- read_lock(&tasklist_lock);
spin_lock_irqsave(&p->sighand->siglock, flags);
ret = specific_send_sig_info(sig, info, p);
spin_unlock_irqrestore(&p->sighand->siglock, flags);
- read_unlock(&tasklist_lock);
return ret;
}
@@ -1291,28 +1253,24 @@
__sigqueue_free(q);
}
-int send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
+int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group)
{
+ int sig = q->info.si_signo;
+ struct sigpending *pending;
unsigned long flags;
- int ret = 0;
+ int ret;
BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
- /*
- * The rcu based delayed sighand destroy makes it possible to
- * run this without tasklist lock held. The task struct itself
- * cannot go away as create_timer did get_task_struct().
- *
- * We return -1, when the task is marked exiting, so
- * posix_timer_event can redirect it to the group leader
- */
- rcu_read_lock();
+ ret = -1;
+ if (!likely(lock_task_sighand(t, &flags)))
+ goto ret;
- if (!likely(lock_task_sighand(p, &flags))) {
- ret = -1;
- goto out_err;
- }
+ ret = 1; /* the signal is ignored */
+ if (!prepare_signal(sig, t))
+ goto out;
+ ret = 0;
if (unlikely(!list_empty(&q->list))) {
/*
* If an SI_TIMER entry is already queue just increment
@@ -1322,77 +1280,15 @@
q->info.si_overrun++;
goto out;
}
- /* Short-circuit ignored signals. */
- if (sig_ignored(p, sig)) {
- ret = 1;
- goto out;
- }
- /*
- * Deliver the signal to listening signalfds. This must be called
- * with the sighand lock held.
- */
- signalfd_notify(p, sig);
- list_add_tail(&q->list, &p->pending.list);
- sigaddset(&p->pending.signal, sig);
- if (!sigismember(&p->blocked, sig))
- signal_wake_up(p, sig == SIGKILL);
-
+ signalfd_notify(t, sig);
+ pending = group ? &t->signal->shared_pending : &t->pending;
+ list_add_tail(&q->list, &pending->list);
+ sigaddset(&pending->signal, sig);
+ complete_signal(sig, t, group);
out:
- unlock_task_sighand(p, &flags);
-out_err:
- rcu_read_unlock();
-
- return ret;
-}
-
-int
-send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
-{
- unsigned long flags;
- int ret = 0;
-
- BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
-
- read_lock(&tasklist_lock);
- /* Since it_lock is held, p->sighand cannot be NULL. */
- spin_lock_irqsave(&p->sighand->siglock, flags);
- handle_stop_signal(sig, p);
-
- /* Short-circuit ignored signals. */
- if (sig_ignored(p, sig)) {
- ret = 1;
- goto out;
- }
-
- if (unlikely(!list_empty(&q->list))) {
- /*
- * If an SI_TIMER entry is already queue just increment
- * the overrun count. Other uses should not try to
- * send the signal multiple times.
- */
- BUG_ON(q->info.si_code != SI_TIMER);
- q->info.si_overrun++;
- goto out;
- }
- /*
- * Deliver the signal to listening signalfds. This must be called
- * with the sighand lock held.
- */
- signalfd_notify(p, sig);
-
- /*
- * Put this signal on the shared-pending queue.
- * We always use the shared queue for process-wide signals,
- * to avoid several races.
- */
- list_add_tail(&q->list, &p->signal->shared_pending.list);
- sigaddset(&p->signal->shared_pending.signal, sig);
-
- __group_complete_signal(sig, p);
-out:
- spin_unlock_irqrestore(&p->sighand->siglock, flags);
- read_unlock(&tasklist_lock);
+ unlock_task_sighand(t, &flags);
+ret:
return ret;
}
@@ -1723,8 +1619,9 @@
} else {
struct task_struct *t;
- if (!likely(sig->flags & SIGNAL_STOP_DEQUEUED) ||
- unlikely(sig->group_exit_task))
+ if (unlikely((sig->flags & (SIGNAL_STOP_DEQUEUED | SIGNAL_UNKILLABLE))
+ != SIGNAL_STOP_DEQUEUED) ||
+ unlikely(signal_group_exit(sig)))
return 0;
/*
* There is no group stop already in progress.
@@ -1799,8 +1696,9 @@
int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
struct pt_regs *regs, void *cookie)
{
- sigset_t *mask = ¤t->blocked;
- int signr = 0;
+ struct sighand_struct *sighand = current->sighand;
+ struct signal_struct *signal = current->signal;
+ int signr;
relock:
/*
@@ -1811,16 +1709,32 @@
*/
try_to_freeze();
- spin_lock_irq(¤t->sighand->siglock);
+ spin_lock_irq(&sighand->siglock);
+ /*
+ * Every stopped thread goes here after wakeup. Check to see if
+ * we should notify the parent, prepare_signal(SIGCONT) encodes
+ * the CLD_ si_code into SIGNAL_CLD_MASK bits.
+ */
+ if (unlikely(signal->flags & SIGNAL_CLD_MASK)) {
+ int why = (signal->flags & SIGNAL_STOP_CONTINUED)
+ ? CLD_CONTINUED : CLD_STOPPED;
+ signal->flags &= ~SIGNAL_CLD_MASK;
+ spin_unlock_irq(&sighand->siglock);
+
+ read_lock(&tasklist_lock);
+ do_notify_parent_cldstop(current->group_leader, why);
+ read_unlock(&tasklist_lock);
+ goto relock;
+ }
+
for (;;) {
struct k_sigaction *ka;
- if (unlikely(current->signal->group_stop_count > 0) &&
+ if (unlikely(signal->group_stop_count > 0) &&
do_signal_stop(0))
goto relock;
- signr = dequeue_signal(current, mask, info);
-
+ signr = dequeue_signal(current, ¤t->blocked, info);
if (!signr)
break; /* will return 0 */
@@ -1830,7 +1744,7 @@
continue;
}
- ka = ¤t->sighand->action[signr-1];
+ ka = &sighand->action[signr-1];
if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */
continue;
if (ka->sa.sa_handler != SIG_DFL) {
@@ -1852,7 +1766,8 @@
/*
* Global init gets no signals it doesn't want.
*/
- if (is_global_init(current))
+ if (unlikely(signal->flags & SIGNAL_UNKILLABLE) &&
+ !signal_group_exit(signal))
continue;
if (sig_kernel_stop(signr)) {
@@ -1867,14 +1782,14 @@
* We need to check for that and bail out if necessary.
*/
if (signr != SIGSTOP) {
- spin_unlock_irq(¤t->sighand->siglock);
+ spin_unlock_irq(&sighand->siglock);
/* signals can be posted during this window */
if (is_current_pgrp_orphaned())
goto relock;
- spin_lock_irq(¤t->sighand->siglock);
+ spin_lock_irq(&sighand->siglock);
}
if (likely(do_signal_stop(signr))) {
@@ -1889,15 +1804,16 @@
continue;
}
- spin_unlock_irq(¤t->sighand->siglock);
+ spin_unlock_irq(&sighand->siglock);
/*
* Anything else is fatal, maybe with a core dump.
*/
current->flags |= PF_SIGNALED;
- if ((signr != SIGKILL) && print_fatal_signals)
- print_fatal_signal(regs, signr);
+
if (sig_kernel_coredump(signr)) {
+ if (print_fatal_signals)
+ print_fatal_signal(regs, signr);
/*
* If it was able to dump core, this kills all
* other threads in the group and synchronizes with
@@ -1915,7 +1831,7 @@
do_group_exit(signr);
/* NOTREACHED */
}
- spin_unlock_irq(¤t->sighand->siglock);
+ spin_unlock_irq(&sighand->siglock);
return signr;
}
@@ -2259,6 +2175,7 @@
int error;
struct siginfo info;
struct task_struct *p;
+ unsigned long flags;
error = -ESRCH;
info.si_signo = sig;
@@ -2267,22 +2184,24 @@
info.si_pid = task_tgid_vnr(current);
info.si_uid = current->uid;
- read_lock(&tasklist_lock);
+ rcu_read_lock();
p = find_task_by_vpid(pid);
if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) {
error = check_kill_permission(sig, &info, p);
/*
* The null signal is a permissions and process existence
* probe. No signal is actually delivered.
+ *
+ * If lock_task_sighand() fails we pretend the task dies
+ * after receiving the signal. The window is tiny, and the
+ * signal is private anyway.
*/
- if (!error && sig && p->sighand) {
- spin_lock_irq(&p->sighand->siglock);
- handle_stop_signal(sig, p);
+ if (!error && sig && lock_task_sighand(p, &flags)) {
error = specific_send_sig_info(sig, &info, p);
- spin_unlock_irq(&p->sighand->siglock);
+ unlock_task_sighand(p, &flags);
}
}
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
return error;
}
@@ -2339,13 +2258,14 @@
int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
{
+ struct task_struct *t = current;
struct k_sigaction *k;
sigset_t mask;
if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig)))
return -EINVAL;
- k = ¤t->sighand->action[sig-1];
+ k = &t->sighand->action[sig-1];
spin_lock_irq(¤t->sighand->siglock);
if (oact)
@@ -2366,9 +2286,7 @@
* (for example, SIGCHLD), shall cause the pending signal to
* be discarded, whether or not it is blocked"
*/
- if (act->sa.sa_handler == SIG_IGN ||
- (act->sa.sa_handler == SIG_DFL && sig_kernel_ignore(sig))) {
- struct task_struct *t = current;
+ if (__sig_ignored(t, sig)) {
sigemptyset(&mask);
sigaddset(&mask, sig);
rm_from_queue_full(&mask, &t->signal->shared_pending);
@@ -2623,7 +2541,7 @@
current->state = TASK_INTERRUPTIBLE;
schedule();
- set_thread_flag(TIF_RESTORE_SIGMASK);
+ set_restore_sigmask();
return -ERESTARTNOHAND;
}
#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 3c44956..36e0617 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -589,16 +589,20 @@
local_irq_disable();
/* Find end, append list for that CPU. */
- *__get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).head;
- __get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).tail;
- per_cpu(tasklet_vec, cpu).head = NULL;
- per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
+ if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) {
+ *(__get_cpu_var(tasklet_vec).tail) = per_cpu(tasklet_vec, cpu).head;
+ __get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).tail;
+ per_cpu(tasklet_vec, cpu).head = NULL;
+ per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
+ }
raise_softirq_irqoff(TASKLET_SOFTIRQ);
- *__get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).head;
- __get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).tail;
- per_cpu(tasklet_hi_vec, cpu).head = NULL;
- per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
+ if (&per_cpu(tasklet_hi_vec, cpu).head != per_cpu(tasklet_hi_vec, cpu).tail) {
+ *__get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).head;
+ __get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).tail;
+ per_cpu(tasklet_hi_vec, cpu).head = NULL;
+ per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
+ }
raise_softirq_irqoff(HI_SOFTIRQ);
local_irq_enable();
diff --git a/kernel/sys.c b/kernel/sys.c
index f2a4513..895d2d4 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -978,8 +978,7 @@
goto out;
if (task_pgrp(p) != pgrp) {
- detach_pid(p, PIDTYPE_PGID);
- attach_pid(p, PIDTYPE_PGID, pgrp);
+ change_pid(p, PIDTYPE_PGID, pgrp);
set_task_pgrp(p, pid_nr(pgrp));
}
@@ -992,54 +991,67 @@
asmlinkage long sys_getpgid(pid_t pid)
{
- if (!pid)
- return task_pgrp_vnr(current);
- else {
- int retval;
- struct task_struct *p;
+ struct task_struct *p;
+ struct pid *grp;
+ int retval;
- read_lock(&tasklist_lock);
- p = find_task_by_vpid(pid);
+ rcu_read_lock();
+ if (!pid)
+ grp = task_pgrp(current);
+ else {
retval = -ESRCH;
- if (p) {
- retval = security_task_getpgid(p);
- if (!retval)
- retval = task_pgrp_vnr(p);
- }
- read_unlock(&tasklist_lock);
- return retval;
+ p = find_task_by_vpid(pid);
+ if (!p)
+ goto out;
+ grp = task_pgrp(p);
+ if (!grp)
+ goto out;
+
+ retval = security_task_getpgid(p);
+ if (retval)
+ goto out;
}
+ retval = pid_vnr(grp);
+out:
+ rcu_read_unlock();
+ return retval;
}
#ifdef __ARCH_WANT_SYS_GETPGRP
asmlinkage long sys_getpgrp(void)
{
- /* SMP - assuming writes are word atomic this is fine */
- return task_pgrp_vnr(current);
+ return sys_getpgid(0);
}
#endif
asmlinkage long sys_getsid(pid_t pid)
{
- if (!pid)
- return task_session_vnr(current);
- else {
- int retval;
- struct task_struct *p;
+ struct task_struct *p;
+ struct pid *sid;
+ int retval;
- rcu_read_lock();
- p = find_task_by_vpid(pid);
+ rcu_read_lock();
+ if (!pid)
+ sid = task_session(current);
+ else {
retval = -ESRCH;
- if (p) {
- retval = security_task_getsid(p);
- if (!retval)
- retval = task_session_vnr(p);
- }
- rcu_read_unlock();
- return retval;
+ p = find_task_by_vpid(pid);
+ if (!p)
+ goto out;
+ sid = task_session(p);
+ if (!sid)
+ goto out;
+
+ retval = security_task_getsid(p);
+ if (retval)
+ goto out;
}
+ retval = pid_vnr(sid);
+out:
+ rcu_read_unlock();
+ return retval;
}
asmlinkage long sys_setsid(void)
@@ -1545,6 +1557,19 @@
*
*/
+static void accumulate_thread_rusage(struct task_struct *t, struct rusage *r,
+ cputime_t *utimep, cputime_t *stimep)
+{
+ *utimep = cputime_add(*utimep, t->utime);
+ *stimep = cputime_add(*stimep, t->stime);
+ r->ru_nvcsw += t->nvcsw;
+ r->ru_nivcsw += t->nivcsw;
+ r->ru_minflt += t->min_flt;
+ r->ru_majflt += t->maj_flt;
+ r->ru_inblock += task_io_get_inblock(t);
+ r->ru_oublock += task_io_get_oublock(t);
+}
+
static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
{
struct task_struct *t;
@@ -1554,12 +1579,14 @@
memset((char *) r, 0, sizeof *r);
utime = stime = cputime_zero;
- rcu_read_lock();
- if (!lock_task_sighand(p, &flags)) {
- rcu_read_unlock();
- return;
+ if (who == RUSAGE_THREAD) {
+ accumulate_thread_rusage(p, r, &utime, &stime);
+ goto out;
}
+ if (!lock_task_sighand(p, &flags))
+ return;
+
switch (who) {
case RUSAGE_BOTH:
case RUSAGE_CHILDREN:
@@ -1586,14 +1613,7 @@
r->ru_oublock += p->signal->oublock;
t = p;
do {
- utime = cputime_add(utime, t->utime);
- stime = cputime_add(stime, t->stime);
- r->ru_nvcsw += t->nvcsw;
- r->ru_nivcsw += t->nivcsw;
- r->ru_minflt += t->min_flt;
- r->ru_majflt += t->maj_flt;
- r->ru_inblock += task_io_get_inblock(t);
- r->ru_oublock += task_io_get_oublock(t);
+ accumulate_thread_rusage(t, r, &utime, &stime);
t = next_thread(t);
} while (t != p);
break;
@@ -1601,10 +1621,9 @@
default:
BUG();
}
-
unlock_task_sighand(p, &flags);
- rcu_read_unlock();
+out:
cputime_to_timeval(utime, &r->ru_utime);
cputime_to_timeval(stime, &r->ru_stime);
}
@@ -1618,7 +1637,8 @@
asmlinkage long sys_getrusage(int who, struct rusage __user *ru)
{
- if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN)
+ if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN &&
+ who != RUSAGE_THREAD)
return -EINVAL;
return getrusage(current, who, ru);
}
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index fd33648..d7ffdc5 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -38,6 +38,7 @@
#include <linux/writeback.h>
#include <linux/hugetlb.h>
#include <linux/initrd.h>
+#include <linux/key.h>
#include <linux/times.h>
#include <linux/limits.h>
#include <linux/dcache.h>
@@ -144,12 +145,6 @@
extern int max_lock_depth;
#endif
-#ifdef CONFIG_SYSCTL_SYSCALL
-static int parse_table(int __user *, int, void __user *, size_t __user *,
- void __user *, size_t, struct ctl_table *);
-#endif
-
-
#ifdef CONFIG_PROC_SYSCTL
static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
@@ -809,6 +804,14 @@
.proc_handler = &proc_dostring,
.strategy = &sysctl_string,
},
+#ifdef CONFIG_KEYS
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "keys",
+ .mode = 0555,
+ .child = key_sysctls,
+ },
+#endif
/*
* NOTE: do not add new entries to this table unless you have read
* Documentation/sysctl/ctl_unnumbered.txt
@@ -1430,6 +1433,76 @@
}
#ifdef CONFIG_SYSCTL_SYSCALL
+/* Perform the actual read/write of a sysctl table entry. */
+static int do_sysctl_strategy(struct ctl_table_root *root,
+ struct ctl_table *table,
+ int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen)
+{
+ int op = 0, rc;
+
+ if (oldval)
+ op |= 004;
+ if (newval)
+ op |= 002;
+ if (sysctl_perm(root, table, op))
+ return -EPERM;
+
+ if (table->strategy) {
+ rc = table->strategy(table, name, nlen, oldval, oldlenp,
+ newval, newlen);
+ if (rc < 0)
+ return rc;
+ if (rc > 0)
+ return 0;
+ }
+
+ /* If there is no strategy routine, or if the strategy returns
+ * zero, proceed with automatic r/w */
+ if (table->data && table->maxlen) {
+ rc = sysctl_data(table, name, nlen, oldval, oldlenp,
+ newval, newlen);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static int parse_table(int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen,
+ struct ctl_table_root *root,
+ struct ctl_table *table)
+{
+ int n;
+repeat:
+ if (!nlen)
+ return -ENOTDIR;
+ if (get_user(n, name))
+ return -EFAULT;
+ for ( ; table->ctl_name || table->procname; table++) {
+ if (!table->ctl_name)
+ continue;
+ if (n == table->ctl_name) {
+ int error;
+ if (table->child) {
+ if (sysctl_perm(root, table, 001))
+ return -EPERM;
+ name++;
+ nlen--;
+ table = table->child;
+ goto repeat;
+ }
+ error = do_sysctl_strategy(root, table, name, nlen,
+ oldval, oldlenp,
+ newval, newlen);
+ return error;
+ }
+ }
+ return -ENOTDIR;
+}
+
int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -1447,7 +1520,8 @@
for (head = sysctl_head_next(NULL); head;
head = sysctl_head_next(head)) {
error = parse_table(name, nlen, oldval, oldlenp,
- newval, newlen, head->ctl_table);
+ newval, newlen,
+ head->root, head->ctl_table);
if (error != -ENOTDIR) {
sysctl_head_finish(head);
break;
@@ -1493,85 +1567,23 @@
return -EACCES;
}
-int sysctl_perm(struct ctl_table *table, int op)
+int sysctl_perm(struct ctl_table_root *root, struct ctl_table *table, int op)
{
int error;
+ int mode;
+
error = security_sysctl(table, op);
if (error)
return error;
- return test_perm(table->mode, op);
+
+ if (root->permissions)
+ mode = root->permissions(root, current->nsproxy, table);
+ else
+ mode = table->mode;
+
+ return test_perm(mode, op);
}
-#ifdef CONFIG_SYSCTL_SYSCALL
-static int parse_table(int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen,
- struct ctl_table *table)
-{
- int n;
-repeat:
- if (!nlen)
- return -ENOTDIR;
- if (get_user(n, name))
- return -EFAULT;
- for ( ; table->ctl_name || table->procname; table++) {
- if (!table->ctl_name)
- continue;
- if (n == table->ctl_name) {
- int error;
- if (table->child) {
- if (sysctl_perm(table, 001))
- return -EPERM;
- name++;
- nlen--;
- table = table->child;
- goto repeat;
- }
- error = do_sysctl_strategy(table, name, nlen,
- oldval, oldlenp,
- newval, newlen);
- return error;
- }
- }
- return -ENOTDIR;
-}
-
-/* Perform the actual read/write of a sysctl table entry. */
-int do_sysctl_strategy (struct ctl_table *table,
- int __user *name, int nlen,
- void __user *oldval, size_t __user *oldlenp,
- void __user *newval, size_t newlen)
-{
- int op = 0, rc;
-
- if (oldval)
- op |= 004;
- if (newval)
- op |= 002;
- if (sysctl_perm(table, op))
- return -EPERM;
-
- if (table->strategy) {
- rc = table->strategy(table, name, nlen, oldval, oldlenp,
- newval, newlen);
- if (rc < 0)
- return rc;
- if (rc > 0)
- return 0;
- }
-
- /* If there is no strategy routine, or if the strategy returns
- * zero, proceed with automatic r/w */
- if (table->data && table->maxlen) {
- rc = sysctl_data(table, name, nlen, oldval, oldlenp,
- newval, newlen);
- if (rc < 0)
- return rc;
- }
- return 0;
-}
-#endif /* CONFIG_SYSCTL_SYSCALL */
-
static void sysctl_set_parent(struct ctl_table *parent, struct ctl_table *table)
{
for (; table->ctl_name || table->procname; table++) {
@@ -1583,9 +1595,13 @@
static __init int sysctl_init(void)
{
- int err;
sysctl_set_parent(NULL, root_table);
- err = sysctl_check_table(current->nsproxy, root_table);
+#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
+ {
+ int err;
+ err = sysctl_check_table(current->nsproxy, root_table);
+ }
+#endif
return 0;
}
@@ -1712,10 +1728,12 @@
header->unregistering = NULL;
header->root = root;
sysctl_set_parent(NULL, header->ctl_table);
+#ifdef CONFIG_SYSCTL_SYSCALL_CHECK
if (sysctl_check_table(namespaces, header->ctl_table)) {
kfree(header);
return NULL;
}
+#endif
spin_lock(&sysctl_lock);
header_list = lookup_header_list(root, namespaces);
list_add_tail(&header->ctl_entry, header_list);
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 07e86a8..4a23517 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -183,7 +183,7 @@
if (!tsk) {
rcu_read_lock();
- tsk = find_task_by_pid(pid);
+ tsk = find_task_by_vpid(pid);
if (tsk)
get_task_struct(tsk);
rcu_read_unlock();
@@ -230,7 +230,7 @@
*/
rcu_read_lock();
if (!first)
- first = find_task_by_pid(tgid);
+ first = find_task_by_vpid(tgid);
if (!first || !lock_task_sighand(first, &flags))
goto out;
@@ -547,7 +547,7 @@
if (!stats)
goto err;
- rc = fill_pid(tsk->pid, tsk, stats);
+ rc = fill_pid(-1, tsk, stats);
if (rc < 0)
goto err;
diff --git a/kernel/time.c b/kernel/time.c
index 35d373a..cbe0d5a 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -35,6 +35,8 @@
#include <linux/syscalls.h>
#include <linux/security.h>
#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/math64.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -390,13 +392,17 @@
struct timespec ns_to_timespec(const s64 nsec)
{
struct timespec ts;
+ s32 rem;
if (!nsec)
return (struct timespec) {0, 0};
- ts.tv_sec = div_long_long_rem_signed(nsec, NSEC_PER_SEC, &ts.tv_nsec);
- if (unlikely(nsec < 0))
- set_normalized_timespec(&ts, ts.tv_sec, ts.tv_nsec);
+ ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem);
+ if (unlikely(rem < 0)) {
+ ts.tv_sec--;
+ rem += NSEC_PER_SEC;
+ }
+ ts.tv_nsec = rem;
return ts;
}
@@ -526,8 +532,10 @@
* Convert jiffies to nanoseconds and separate with
* one divide.
*/
- u64 nsec = (u64)jiffies * TICK_NSEC;
- value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &value->tv_nsec);
+ u32 rem;
+ value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
+ NSEC_PER_SEC, &rem);
+ value->tv_nsec = rem;
}
EXPORT_SYMBOL(jiffies_to_timespec);
@@ -565,12 +573,11 @@
* Convert jiffies to nanoseconds and separate with
* one divide.
*/
- u64 nsec = (u64)jiffies * TICK_NSEC;
- long tv_usec;
+ u32 rem;
- value->tv_sec = div_long_long_rem(nsec, NSEC_PER_SEC, &tv_usec);
- tv_usec /= NSEC_PER_USEC;
- value->tv_usec = tv_usec;
+ value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
+ NSEC_PER_SEC, &rem);
+ value->tv_usec = rem / NSEC_PER_USEC;
}
EXPORT_SYMBOL(jiffies_to_timeval);
@@ -586,9 +593,7 @@
return x / (HZ / USER_HZ);
# endif
#else
- u64 tmp = (u64)x * TICK_NSEC;
- do_div(tmp, (NSEC_PER_SEC / USER_HZ));
- return (long)tmp;
+ return div_u64((u64)x * TICK_NSEC, NSEC_PER_SEC / USER_HZ);
#endif
}
EXPORT_SYMBOL(jiffies_to_clock_t);
@@ -600,16 +605,12 @@
return ~0UL;
return x * (HZ / USER_HZ);
#else
- u64 jif;
-
/* Don't worry about loss of precision here .. */
if (x >= ~0UL / HZ * USER_HZ)
return ~0UL;
/* .. but do try to contain it here */
- jif = x * (u64) HZ;
- do_div(jif, USER_HZ);
- return jif;
+ return div_u64((u64)x * HZ, USER_HZ);
#endif
}
EXPORT_SYMBOL(clock_t_to_jiffies);
@@ -618,10 +619,9 @@
{
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
# if HZ < USER_HZ
- x *= USER_HZ;
- do_div(x, HZ);
+ x = div_u64(x * USER_HZ, HZ);
# elif HZ > USER_HZ
- do_div(x, HZ / USER_HZ);
+ x = div_u64(x, HZ / USER_HZ);
# else
/* Nothing to do */
# endif
@@ -631,8 +631,7 @@
* but even this doesn't overflow in hundreds of years
* in 64 bits, so..
*/
- x *= TICK_NSEC;
- do_div(x, (NSEC_PER_SEC / USER_HZ));
+ x = div_u64(x * TICK_NSEC, (NSEC_PER_SEC / USER_HZ));
#endif
return x;
}
@@ -641,21 +640,17 @@
u64 nsec_to_clock_t(u64 x)
{
#if (NSEC_PER_SEC % USER_HZ) == 0
- do_div(x, (NSEC_PER_SEC / USER_HZ));
+ return div_u64(x, NSEC_PER_SEC / USER_HZ);
#elif (USER_HZ % 512) == 0
- x *= USER_HZ/512;
- do_div(x, (NSEC_PER_SEC / 512));
+ return div_u64(x * USER_HZ / 512, NSEC_PER_SEC / 512);
#else
/*
* max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024,
* overflow after 64.99 years.
* exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ...
*/
- x *= 9;
- do_div(x, (unsigned long)((9ull * NSEC_PER_SEC + (USER_HZ/2)) /
- USER_HZ));
+ return div_u64(x * 9, (9ull * NSEC_PER_SEC + (USER_HZ / 2)) / USER_HZ);
#endif
- return x;
}
#if (BITS_PER_LONG < 64)
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
index 5fd9b94..5125ddd 100644
--- a/kernel/time/ntp.c
+++ b/kernel/time/ntp.c
@@ -15,7 +15,8 @@
#include <linux/jiffies.h>
#include <linux/hrtimer.h>
#include <linux/capability.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
+#include <linux/clocksource.h>
#include <asm/timex.h>
/*
@@ -23,11 +24,14 @@
*/
unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */
unsigned long tick_nsec; /* ACTHZ period (nsec) */
-static u64 tick_length, tick_length_base;
+u64 tick_length;
+static u64 tick_length_base;
+
+static struct hrtimer leap_timer;
#define MAX_TICKADJ 500 /* microsecs */
#define MAX_TICKADJ_SCALED (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \
- TICK_LENGTH_SHIFT) / NTP_INTERVAL_FREQ)
+ NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ)
/*
* phase-lock loop variables
@@ -35,11 +39,12 @@
/* TIME_ERROR prevents overwriting the CMOS clock */
static int time_state = TIME_OK; /* clock synchronization status */
int time_status = STA_UNSYNC; /* clock status bits */
-static s64 time_offset; /* time adjustment (ns) */
+static long time_tai; /* TAI offset (s) */
+static s64 time_offset; /* time adjustment (ns) */
static long time_constant = 2; /* pll time constant */
long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */
long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */
-long time_freq; /* frequency offset (scaled ppm)*/
+static s64 time_freq; /* frequency offset (scaled ns/s)*/
static long time_reftime; /* time at last adjustment (s) */
long time_adjust;
static long ntp_tick_adj;
@@ -47,16 +52,56 @@
static void ntp_update_frequency(void)
{
u64 second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ)
- << TICK_LENGTH_SHIFT;
- second_length += (s64)ntp_tick_adj << TICK_LENGTH_SHIFT;
- second_length += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC);
+ << NTP_SCALE_SHIFT;
+ second_length += (s64)ntp_tick_adj << NTP_SCALE_SHIFT;
+ second_length += time_freq;
tick_length_base = second_length;
- do_div(second_length, HZ);
- tick_nsec = second_length >> TICK_LENGTH_SHIFT;
+ tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT;
+ tick_length_base = div_u64(tick_length_base, NTP_INTERVAL_FREQ);
+}
- do_div(tick_length_base, NTP_INTERVAL_FREQ);
+static void ntp_update_offset(long offset)
+{
+ long mtemp;
+ s64 freq_adj;
+
+ if (!(time_status & STA_PLL))
+ return;
+
+ if (!(time_status & STA_NANO))
+ offset *= NSEC_PER_USEC;
+
+ /*
+ * Scale the phase adjustment and
+ * clamp to the operating range.
+ */
+ offset = min(offset, MAXPHASE);
+ offset = max(offset, -MAXPHASE);
+
+ /*
+ * Select how the frequency is to be controlled
+ * and in which mode (PLL or FLL).
+ */
+ if (time_status & STA_FREQHOLD || time_reftime == 0)
+ time_reftime = xtime.tv_sec;
+ mtemp = xtime.tv_sec - time_reftime;
+ time_reftime = xtime.tv_sec;
+
+ freq_adj = (s64)offset * mtemp;
+ freq_adj <<= NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant);
+ time_status &= ~STA_MODE;
+ if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
+ freq_adj += div_s64((s64)offset << (NTP_SCALE_SHIFT - SHIFT_FLL),
+ mtemp);
+ time_status |= STA_MODE;
+ }
+ freq_adj += time_freq;
+ freq_adj = min(freq_adj, MAXFREQ_SCALED);
+ time_freq = max(freq_adj, -MAXFREQ_SCALED);
+
+ time_offset = div_s64((s64)offset << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ);
}
/**
@@ -78,6 +123,54 @@
}
/*
+ * Leap second processing. If in leap-insert state at the end of the
+ * day, the system clock is set back one second; if in leap-delete
+ * state, the system clock is set ahead one second.
+ */
+static enum hrtimer_restart ntp_leap_second(struct hrtimer *timer)
+{
+ enum hrtimer_restart res = HRTIMER_NORESTART;
+
+ write_seqlock_irq(&xtime_lock);
+
+ switch (time_state) {
+ case TIME_OK:
+ break;
+ case TIME_INS:
+ xtime.tv_sec--;
+ wall_to_monotonic.tv_sec++;
+ time_state = TIME_OOP;
+ printk(KERN_NOTICE "Clock: "
+ "inserting leap second 23:59:60 UTC\n");
+ leap_timer.expires = ktime_add_ns(leap_timer.expires,
+ NSEC_PER_SEC);
+ res = HRTIMER_RESTART;
+ break;
+ case TIME_DEL:
+ xtime.tv_sec++;
+ time_tai--;
+ wall_to_monotonic.tv_sec--;
+ time_state = TIME_WAIT;
+ printk(KERN_NOTICE "Clock: "
+ "deleting leap second 23:59:59 UTC\n");
+ break;
+ case TIME_OOP:
+ time_tai++;
+ time_state = TIME_WAIT;
+ /* fall through */
+ case TIME_WAIT:
+ if (!(time_status & (STA_INS | STA_DEL)))
+ time_state = TIME_OK;
+ break;
+ }
+ update_vsyscall(&xtime, clock);
+
+ write_sequnlock_irq(&xtime_lock);
+
+ return res;
+}
+
+/*
* this routine handles the overflow of the microsecond field
*
* The tricky bits of code to handle the accurate clock support
@@ -87,63 +180,23 @@
*/
void second_overflow(void)
{
- long time_adj;
+ s64 time_adj;
/* Bump the maxerror field */
- time_maxerror += MAXFREQ >> SHIFT_USEC;
+ time_maxerror += MAXFREQ / NSEC_PER_USEC;
if (time_maxerror > NTP_PHASE_LIMIT) {
time_maxerror = NTP_PHASE_LIMIT;
time_status |= STA_UNSYNC;
}
/*
- * Leap second processing. If in leap-insert state at the end of the
- * day, the system clock is set back one second; if in leap-delete
- * state, the system clock is set ahead one second. The microtime()
- * routine or external clock driver will insure that reported time is
- * always monotonic. The ugly divides should be replaced.
- */
- switch (time_state) {
- case TIME_OK:
- if (time_status & STA_INS)
- time_state = TIME_INS;
- else if (time_status & STA_DEL)
- time_state = TIME_DEL;
- break;
- case TIME_INS:
- if (xtime.tv_sec % 86400 == 0) {
- xtime.tv_sec--;
- wall_to_monotonic.tv_sec++;
- time_state = TIME_OOP;
- printk(KERN_NOTICE "Clock: inserting leap second "
- "23:59:60 UTC\n");
- }
- break;
- case TIME_DEL:
- if ((xtime.tv_sec + 1) % 86400 == 0) {
- xtime.tv_sec++;
- wall_to_monotonic.tv_sec--;
- time_state = TIME_WAIT;
- printk(KERN_NOTICE "Clock: deleting leap second "
- "23:59:59 UTC\n");
- }
- break;
- case TIME_OOP:
- time_state = TIME_WAIT;
- break;
- case TIME_WAIT:
- if (!(time_status & (STA_INS | STA_DEL)))
- time_state = TIME_OK;
- }
-
- /*
* Compute the phase adjustment for the next second. The offset is
* reduced by a fixed factor times the time constant.
*/
tick_length = tick_length_base;
time_adj = shift_right(time_offset, SHIFT_PLL + time_constant);
time_offset -= time_adj;
- tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE);
+ tick_length += time_adj;
if (unlikely(time_adjust)) {
if (time_adjust > MAX_TICKADJ) {
@@ -154,25 +207,12 @@
tick_length -= MAX_TICKADJ_SCALED;
} else {
tick_length += (s64)(time_adjust * NSEC_PER_USEC /
- NTP_INTERVAL_FREQ) << TICK_LENGTH_SHIFT;
+ NTP_INTERVAL_FREQ) << NTP_SCALE_SHIFT;
time_adjust = 0;
}
}
}
-/*
- * Return how long ticks are at the moment, that is, how much time
- * update_wall_time_one_tick will add to xtime next time we call it
- * (assuming no calls to do_adjtimex in the meantime).
- * The return value is in fixed-point nanoseconds shifted by the
- * specified number of bits to the right of the binary point.
- * This function has no side-effects.
- */
-u64 current_tick_length(void)
-{
- return tick_length;
-}
-
#ifdef CONFIG_GENERIC_CMOS_UPDATE
/* Disable the cmos update - used by virtualization and embedded */
@@ -236,8 +276,8 @@
*/
int do_adjtimex(struct timex *txc)
{
- long mtemp, save_adjust, rem;
- s64 freq_adj, temp64;
+ struct timespec ts;
+ long save_adjust, sec;
int result;
/* In order to modify anything, you gotta be super-user! */
@@ -247,147 +287,132 @@
/* Now we validate the data before disabling interrupts */
if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT) {
- /* singleshot must not be used with any other mode bits */
- if (txc->modes != ADJ_OFFSET_SINGLESHOT &&
- txc->modes != ADJ_OFFSET_SS_READ)
+ /* singleshot must not be used with any other mode bits */
+ if (txc->modes & ~ADJ_OFFSET_SS_READ)
return -EINVAL;
}
- if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
- /* adjustment Offset limited to +- .512 seconds */
- if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
- return -EINVAL;
-
/* if the quartz is off by more than 10% something is VERY wrong ! */
if (txc->modes & ADJ_TICK)
if (txc->tick < 900000/USER_HZ ||
txc->tick > 1100000/USER_HZ)
return -EINVAL;
+ if (time_state != TIME_OK && txc->modes & ADJ_STATUS)
+ hrtimer_cancel(&leap_timer);
+ getnstimeofday(&ts);
+
write_seqlock_irq(&xtime_lock);
- result = time_state; /* mostly `TIME_OK' */
/* Save for later - semantics of adjtime is to return old value */
save_adjust = time_adjust;
-#if 0 /* STA_CLOCKERR is never set yet */
- time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */
-#endif
/* If there are input parameters, then process them */
- if (txc->modes)
- {
- if (txc->modes & ADJ_STATUS) /* only set allowed bits */
- time_status = (txc->status & ~STA_RONLY) |
- (time_status & STA_RONLY);
-
- if (txc->modes & ADJ_FREQUENCY) { /* p. 22 */
- if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
- result = -EINVAL;
- goto leave;
- }
- time_freq = ((s64)txc->freq * NSEC_PER_USEC)
- >> (SHIFT_USEC - SHIFT_NSEC);
- }
-
- if (txc->modes & ADJ_MAXERROR) {
- if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
- result = -EINVAL;
- goto leave;
- }
- time_maxerror = txc->maxerror;
- }
-
- if (txc->modes & ADJ_ESTERROR) {
- if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
- result = -EINVAL;
- goto leave;
- }
- time_esterror = txc->esterror;
- }
-
- if (txc->modes & ADJ_TIMECONST) { /* p. 24 */
- if (txc->constant < 0) { /* NTP v4 uses values > 6 */
- result = -EINVAL;
- goto leave;
- }
- time_constant = min(txc->constant + 4, (long)MAXTC);
- }
-
- if (txc->modes & ADJ_OFFSET) { /* values checked earlier */
- if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
- /* adjtime() is independent from ntp_adjtime() */
- time_adjust = txc->offset;
- }
- else if (time_status & STA_PLL) {
- time_offset = txc->offset * NSEC_PER_USEC;
-
- /*
- * Scale the phase adjustment and
- * clamp to the operating range.
- */
- time_offset = min(time_offset, (s64)MAXPHASE * NSEC_PER_USEC);
- time_offset = max(time_offset, (s64)-MAXPHASE * NSEC_PER_USEC);
-
- /*
- * Select whether the frequency is to be controlled
- * and in which mode (PLL or FLL). Clamp to the operating
- * range. Ugly multiply/divide should be replaced someday.
- */
-
- if (time_status & STA_FREQHOLD || time_reftime == 0)
- time_reftime = xtime.tv_sec;
- mtemp = xtime.tv_sec - time_reftime;
- time_reftime = xtime.tv_sec;
-
- freq_adj = time_offset * mtemp;
- freq_adj = shift_right(freq_adj, time_constant * 2 +
- (SHIFT_PLL + 2) * 2 - SHIFT_NSEC);
- if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
- u64 utemp64;
- temp64 = time_offset << (SHIFT_NSEC - SHIFT_FLL);
- if (time_offset < 0) {
- utemp64 = -temp64;
- do_div(utemp64, mtemp);
- freq_adj -= utemp64;
- } else {
- utemp64 = temp64;
- do_div(utemp64, mtemp);
- freq_adj += utemp64;
+ if (txc->modes) {
+ if (txc->modes & ADJ_STATUS) {
+ if ((time_status & STA_PLL) &&
+ !(txc->status & STA_PLL)) {
+ time_state = TIME_OK;
+ time_status = STA_UNSYNC;
}
- }
- freq_adj += time_freq;
- freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC);
- time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC);
- time_offset = div_long_long_rem_signed(time_offset,
- NTP_INTERVAL_FREQ,
- &rem);
- time_offset <<= SHIFT_UPDATE;
- } /* STA_PLL */
- } /* txc->modes & ADJ_OFFSET */
- if (txc->modes & ADJ_TICK)
- tick_usec = txc->tick;
+ /* only set allowed bits */
+ time_status &= STA_RONLY;
+ time_status |= txc->status & ~STA_RONLY;
- if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
- ntp_update_frequency();
- } /* txc->modes */
-leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
+ switch (time_state) {
+ case TIME_OK:
+ start_timer:
+ sec = ts.tv_sec;
+ if (time_status & STA_INS) {
+ time_state = TIME_INS;
+ sec += 86400 - sec % 86400;
+ hrtimer_start(&leap_timer, ktime_set(sec, 0), HRTIMER_MODE_ABS);
+ } else if (time_status & STA_DEL) {
+ time_state = TIME_DEL;
+ sec += 86400 - (sec + 1) % 86400;
+ hrtimer_start(&leap_timer, ktime_set(sec, 0), HRTIMER_MODE_ABS);
+ }
+ break;
+ case TIME_INS:
+ case TIME_DEL:
+ time_state = TIME_OK;
+ goto start_timer;
+ break;
+ case TIME_WAIT:
+ if (!(time_status & (STA_INS | STA_DEL)))
+ time_state = TIME_OK;
+ break;
+ case TIME_OOP:
+ hrtimer_restart(&leap_timer);
+ break;
+ }
+ }
+
+ if (txc->modes & ADJ_NANO)
+ time_status |= STA_NANO;
+ if (txc->modes & ADJ_MICRO)
+ time_status &= ~STA_NANO;
+
+ if (txc->modes & ADJ_FREQUENCY) {
+ time_freq = (s64)txc->freq * PPM_SCALE;
+ time_freq = min(time_freq, MAXFREQ_SCALED);
+ time_freq = max(time_freq, -MAXFREQ_SCALED);
+ }
+
+ if (txc->modes & ADJ_MAXERROR)
+ time_maxerror = txc->maxerror;
+ if (txc->modes & ADJ_ESTERROR)
+ time_esterror = txc->esterror;
+
+ if (txc->modes & ADJ_TIMECONST) {
+ time_constant = txc->constant;
+ if (!(time_status & STA_NANO))
+ time_constant += 4;
+ time_constant = min(time_constant, (long)MAXTC);
+ time_constant = max(time_constant, 0l);
+ }
+
+ if (txc->modes & ADJ_TAI && txc->constant > 0)
+ time_tai = txc->constant;
+
+ if (txc->modes & ADJ_OFFSET) {
+ if (txc->modes == ADJ_OFFSET_SINGLESHOT)
+ /* adjtime() is independent from ntp_adjtime() */
+ time_adjust = txc->offset;
+ else
+ ntp_update_offset(txc->offset);
+ }
+ if (txc->modes & ADJ_TICK)
+ tick_usec = txc->tick;
+
+ if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
+ ntp_update_frequency();
+ }
+
+ result = time_state; /* mostly `TIME_OK' */
+ if (time_status & (STA_UNSYNC|STA_CLOCKERR))
result = TIME_ERROR;
if ((txc->modes == ADJ_OFFSET_SINGLESHOT) ||
- (txc->modes == ADJ_OFFSET_SS_READ))
+ (txc->modes == ADJ_OFFSET_SS_READ))
txc->offset = save_adjust;
- else
- txc->offset = ((long)shift_right(time_offset, SHIFT_UPDATE)) *
- NTP_INTERVAL_FREQ / 1000;
- txc->freq = (time_freq / NSEC_PER_USEC) <<
- (SHIFT_USEC - SHIFT_NSEC);
+ else {
+ txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
+ NTP_SCALE_SHIFT);
+ if (!(time_status & STA_NANO))
+ txc->offset /= NSEC_PER_USEC;
+ }
+ txc->freq = shift_right((s32)(time_freq >> PPM_SCALE_INV_SHIFT) *
+ (s64)PPM_SCALE_INV,
+ NTP_SCALE_SHIFT);
txc->maxerror = time_maxerror;
txc->esterror = time_esterror;
txc->status = time_status;
txc->constant = time_constant;
txc->precision = 1;
- txc->tolerance = MAXFREQ;
+ txc->tolerance = MAXFREQ_SCALED / PPM_SCALE;
txc->tick = tick_usec;
+ txc->tai = time_tai;
/* PPS is not implemented, so these are zero */
txc->ppsfreq = 0;
@@ -399,9 +424,15 @@
txc->errcnt = 0;
txc->stbcnt = 0;
write_sequnlock_irq(&xtime_lock);
- do_gettimeofday(&txc->time);
+
+ txc->time.tv_sec = ts.tv_sec;
+ txc->time.tv_usec = ts.tv_nsec;
+ if (!(time_status & STA_NANO))
+ txc->time.tv_usec /= NSEC_PER_USEC;
+
notify_cmos_timer();
- return(result);
+
+ return result;
}
static int __init ntp_tick_adj_setup(char *str)
@@ -411,3 +442,10 @@
}
__setup("ntp_tick_adj=", ntp_tick_adj_setup);
+
+void __init ntp_init(void)
+{
+ ntp_clear();
+ hrtimer_init(&leap_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ leap_timer.function = ntp_leap_second;
+}
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 2d6087c..e91c29f 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -53,7 +53,7 @@
timespec_add_ns(&xtime_cache, nsec);
}
-static struct clocksource *clock; /* pointer to current clocksource */
+struct clocksource *clock;
#ifdef CONFIG_GENERIC_TIME
@@ -246,7 +246,7 @@
write_seqlock_irqsave(&xtime_lock, flags);
- ntp_clear();
+ ntp_init();
clock = clocksource_get_next();
clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
@@ -371,7 +371,7 @@
* here. This is tuned so that an error of about 1 msec is adjusted
* within about 1 sec (or 2^20 nsec in 2^SHIFT_HZ ticks).
*/
- error2 = clock->error >> (TICK_LENGTH_SHIFT + 22 - 2 * SHIFT_HZ);
+ error2 = clock->error >> (NTP_SCALE_SHIFT + 22 - 2 * SHIFT_HZ);
error2 = abs(error2);
for (look_ahead = 0; error2 > 0; look_ahead++)
error2 >>= 2;
@@ -380,8 +380,7 @@
* Now calculate the error in (1 << look_ahead) ticks, but first
* remove the single look ahead already included in the error.
*/
- tick_error = current_tick_length() >>
- (TICK_LENGTH_SHIFT - clock->shift + 1);
+ tick_error = tick_length >> (NTP_SCALE_SHIFT - clock->shift + 1);
tick_error -= clock->xtime_interval >> 1;
error = ((error - tick_error) >> look_ahead) + tick_error;
@@ -412,7 +411,7 @@
s64 error, interval = clock->cycle_interval;
int adj;
- error = clock->error >> (TICK_LENGTH_SHIFT - clock->shift - 1);
+ error = clock->error >> (NTP_SCALE_SHIFT - clock->shift - 1);
if (error > interval) {
error >>= 2;
if (likely(error <= interval))
@@ -434,7 +433,7 @@
clock->xtime_interval += interval;
clock->xtime_nsec -= offset;
clock->error -= (interval - offset) <<
- (TICK_LENGTH_SHIFT - clock->shift);
+ (NTP_SCALE_SHIFT - clock->shift);
}
/**
@@ -473,8 +472,8 @@
}
/* accumulate error between NTP and clock interval */
- clock->error += current_tick_length();
- clock->error -= clock->xtime_interval << (TICK_LENGTH_SHIFT - clock->shift);
+ clock->error += tick_length;
+ clock->error -= clock->xtime_interval << (NTP_SCALE_SHIFT - clock->shift);
}
/* correct the clock when NTP error is too big */
diff --git a/kernel/time/timer_list.c b/kernel/time/timer_list.c
index 67fe8fc..a40e20f 100644
--- a/kernel/time/timer_list.c
+++ b/kernel/time/timer_list.c
@@ -278,12 +278,9 @@
{
struct proc_dir_entry *pe;
- pe = create_proc_entry("timer_list", 0644, NULL);
+ pe = proc_create("timer_list", 0644, NULL, &timer_list_fops);
if (!pe)
return -ENOMEM;
-
- pe->proc_fops = &timer_list_fops;
-
return 0;
}
__initcall(init_timer_list_procfs);
diff --git a/kernel/time/timer_stats.c b/kernel/time/timer_stats.c
index 417da8c..c994530 100644
--- a/kernel/time/timer_stats.c
+++ b/kernel/time/timer_stats.c
@@ -415,12 +415,9 @@
{
struct proc_dir_entry *pe;
- pe = create_proc_entry("timer_stats", 0644, NULL);
+ pe = proc_create("timer_stats", 0644, NULL, &tstats_fops);
if (!pe)
return -ENOMEM;
-
- pe->proc_fops = &tstats_fops;
-
return 0;
}
__initcall(init_tstats_procfs);
diff --git a/kernel/timer.c b/kernel/timer.c
index f3d35d4..ceacc66 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -320,6 +320,140 @@
static void timer_stats_account_timer(struct timer_list *timer) {}
#endif
+#ifdef CONFIG_DEBUG_OBJECTS_TIMERS
+
+static struct debug_obj_descr timer_debug_descr;
+
+/*
+ * fixup_init is called when:
+ * - an active object is initialized
+ */
+static int timer_fixup_init(void *addr, enum debug_obj_state state)
+{
+ struct timer_list *timer = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ del_timer_sync(timer);
+ debug_object_init(timer, &timer_debug_descr);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * fixup_activate is called when:
+ * - an active object is activated
+ * - an unknown object is activated (might be a statically initialized object)
+ */
+static int timer_fixup_activate(void *addr, enum debug_obj_state state)
+{
+ struct timer_list *timer = addr;
+
+ switch (state) {
+
+ case ODEBUG_STATE_NOTAVAILABLE:
+ /*
+ * This is not really a fixup. The timer was
+ * statically initialized. We just make sure that it
+ * is tracked in the object tracker.
+ */
+ if (timer->entry.next == NULL &&
+ timer->entry.prev == TIMER_ENTRY_STATIC) {
+ debug_object_init(timer, &timer_debug_descr);
+ debug_object_activate(timer, &timer_debug_descr);
+ return 0;
+ } else {
+ WARN_ON_ONCE(1);
+ }
+ return 0;
+
+ case ODEBUG_STATE_ACTIVE:
+ WARN_ON(1);
+
+ default:
+ return 0;
+ }
+}
+
+/*
+ * fixup_free is called when:
+ * - an active object is freed
+ */
+static int timer_fixup_free(void *addr, enum debug_obj_state state)
+{
+ struct timer_list *timer = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ del_timer_sync(timer);
+ debug_object_free(timer, &timer_debug_descr);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static struct debug_obj_descr timer_debug_descr = {
+ .name = "timer_list",
+ .fixup_init = timer_fixup_init,
+ .fixup_activate = timer_fixup_activate,
+ .fixup_free = timer_fixup_free,
+};
+
+static inline void debug_timer_init(struct timer_list *timer)
+{
+ debug_object_init(timer, &timer_debug_descr);
+}
+
+static inline void debug_timer_activate(struct timer_list *timer)
+{
+ debug_object_activate(timer, &timer_debug_descr);
+}
+
+static inline void debug_timer_deactivate(struct timer_list *timer)
+{
+ debug_object_deactivate(timer, &timer_debug_descr);
+}
+
+static inline void debug_timer_free(struct timer_list *timer)
+{
+ debug_object_free(timer, &timer_debug_descr);
+}
+
+static void __init_timer(struct timer_list *timer);
+
+void init_timer_on_stack(struct timer_list *timer)
+{
+ debug_object_init_on_stack(timer, &timer_debug_descr);
+ __init_timer(timer);
+}
+EXPORT_SYMBOL_GPL(init_timer_on_stack);
+
+void destroy_timer_on_stack(struct timer_list *timer)
+{
+ debug_object_free(timer, &timer_debug_descr);
+}
+EXPORT_SYMBOL_GPL(destroy_timer_on_stack);
+
+#else
+static inline void debug_timer_init(struct timer_list *timer) { }
+static inline void debug_timer_activate(struct timer_list *timer) { }
+static inline void debug_timer_deactivate(struct timer_list *timer) { }
+#endif
+
+static void __init_timer(struct timer_list *timer)
+{
+ timer->entry.next = NULL;
+ timer->base = __raw_get_cpu_var(tvec_bases);
+#ifdef CONFIG_TIMER_STATS
+ timer->start_site = NULL;
+ timer->start_pid = -1;
+ memset(timer->start_comm, 0, TASK_COMM_LEN);
+#endif
+}
+
/**
* init_timer - initialize a timer.
* @timer: the timer to be initialized
@@ -329,13 +463,8 @@
*/
void init_timer(struct timer_list *timer)
{
- timer->entry.next = NULL;
- timer->base = __raw_get_cpu_var(tvec_bases);
-#ifdef CONFIG_TIMER_STATS
- timer->start_site = NULL;
- timer->start_pid = -1;
- memset(timer->start_comm, 0, TASK_COMM_LEN);
-#endif
+ debug_timer_init(timer);
+ __init_timer(timer);
}
EXPORT_SYMBOL(init_timer);
@@ -351,6 +480,8 @@
{
struct list_head *entry = &timer->entry;
+ debug_timer_deactivate(timer);
+
__list_del(entry->prev, entry->next);
if (clear_pending)
entry->next = NULL;
@@ -405,6 +536,8 @@
ret = 1;
}
+ debug_timer_activate(timer);
+
new_base = __get_cpu_var(tvec_bases);
if (base != new_base) {
@@ -450,6 +583,7 @@
BUG_ON(timer_pending(timer) || !timer->function);
spin_lock_irqsave(&base->lock, flags);
timer_set_base(timer, base);
+ debug_timer_activate(timer);
internal_add_timer(base, timer);
/*
* Check whether the other CPU is idle and needs to be
@@ -1086,11 +1220,14 @@
expire = timeout + jiffies;
- setup_timer(&timer, process_timeout, (unsigned long)current);
+ setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
__mod_timer(&timer, expire);
schedule();
del_singleshot_timer_sync(&timer);
+ /* Remove the timer from the object tracker */
+ destroy_timer_on_stack(&timer);
+
timeout = expire - jiffies;
out:
diff --git a/kernel/user.c b/kernel/user.c
index debce60..865ecf57 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -53,10 +53,6 @@
.files = ATOMIC_INIT(0),
.sigpending = ATOMIC_INIT(0),
.locked_shm = 0,
-#ifdef CONFIG_KEYS
- .uid_keyring = &root_user_keyring,
- .session_keyring = &root_session_keyring,
-#endif
#ifdef CONFIG_USER_SCHED
.tg = &init_task_group,
#endif
@@ -388,7 +384,7 @@
local_irq_restore(flags);
}
-struct user_struct * alloc_uid(struct user_namespace *ns, uid_t uid)
+struct user_struct *alloc_uid(struct user_namespace *ns, uid_t uid)
{
struct hlist_head *hashent = uidhashentry(ns, uid);
struct user_struct *up, *new;
@@ -403,29 +399,15 @@
spin_unlock_irq(&uidhash_lock);
if (!up) {
- new = kmem_cache_alloc(uid_cachep, GFP_KERNEL);
+ new = kmem_cache_zalloc(uid_cachep, GFP_KERNEL);
if (!new)
goto out_unlock;
new->uid = uid;
atomic_set(&new->__count, 1);
- atomic_set(&new->processes, 0);
- atomic_set(&new->files, 0);
- atomic_set(&new->sigpending, 0);
-#ifdef CONFIG_INOTIFY_USER
- atomic_set(&new->inotify_watches, 0);
- atomic_set(&new->inotify_devs, 0);
-#endif
-#ifdef CONFIG_POSIX_MQUEUE
- new->mq_bytes = 0;
-#endif
- new->locked_shm = 0;
-
- if (alloc_uid_keyring(new, current) < 0)
- goto out_free_user;
if (sched_create_user(new) < 0)
- goto out_put_keys;
+ goto out_free_user;
if (uids_user_create(new))
goto out_destoy_sched;
@@ -459,9 +441,6 @@
out_destoy_sched:
sched_destroy_user(new);
-out_put_keys:
- key_put(new->uid_keyring);
- key_put(new->session_keyring);
out_free_user:
kmem_cache_free(uid_cachep, new);
out_unlock:
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 4c90062..a9ab059 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/version.h>
#include <linux/nsproxy.h>
+#include <linux/slab.h>
#include <linux/user_namespace.h>
/*
@@ -73,3 +74,4 @@
release_uids(ns);
kfree(ns);
}
+EXPORT_SYMBOL(free_user_ns);
diff --git a/kernel/utsname.c b/kernel/utsname.c
index 816d7b2..64d398f 100644
--- a/kernel/utsname.c
+++ b/kernel/utsname.c
@@ -14,6 +14,7 @@
#include <linux/utsname.h>
#include <linux/version.h>
#include <linux/err.h>
+#include <linux/slab.h>
/*
* Clone a new ns copying an original utsname, setting refcount to 1
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 00ff4d0..29fc39f 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -158,8 +158,8 @@
*
* Returns 0 if @work was already on a queue, non-zero otherwise.
*
- * We queue the work to the CPU it was submitted, but there is no
- * guarantee that it will be processed by that CPU.
+ * We queue the work to the CPU on which it was submitted, but if the CPU dies
+ * it can be processed by another CPU.
*/
int queue_work(struct workqueue_struct *wq, struct work_struct *work)
{
@@ -195,7 +195,6 @@
int queue_delayed_work(struct workqueue_struct *wq,
struct delayed_work *dwork, unsigned long delay)
{
- timer_stats_timer_set_start_info(&dwork->timer);
if (delay == 0)
return queue_work(wq, &dwork->work);
@@ -219,11 +218,12 @@
struct timer_list *timer = &dwork->timer;
struct work_struct *work = &dwork->work;
- timer_stats_timer_set_start_info(&dwork->timer);
if (!test_and_set_bit(WORK_STRUCT_PENDING, work_data_bits(work))) {
BUG_ON(timer_pending(timer));
BUG_ON(!list_empty(&work->entry));
+ timer_stats_timer_set_start_info(&dwork->timer);
+
/* This stores cwq for the moment, for the timer_fn */
set_wq_data(work, wq_per_cpu(wq, raw_smp_processor_id()));
timer->expires = jiffies + delay;
@@ -247,7 +247,7 @@
if (cwq->run_depth > 3) {
/* morton gets to eat his hat */
printk("%s: recursion depth exceeded: %d\n",
- __FUNCTION__, cwq->run_depth);
+ __func__, cwq->run_depth);
dump_stack();
}
while (!list_empty(&cwq->worklist)) {
@@ -564,7 +564,6 @@
int schedule_delayed_work(struct delayed_work *dwork,
unsigned long delay)
{
- timer_stats_timer_set_start_info(&dwork->timer);
return queue_delayed_work(keventd_wq, dwork, delay);
}
EXPORT_SYMBOL(schedule_delayed_work);
@@ -581,7 +580,6 @@
int schedule_delayed_work_on(int cpu,
struct delayed_work *dwork, unsigned long delay)
{
- timer_stats_timer_set_start_info(&dwork->timer);
return queue_delayed_work_on(cpu, keventd_wq, dwork, delay);
}
EXPORT_SYMBOL(schedule_delayed_work_on);
@@ -772,7 +770,7 @@
}
EXPORT_SYMBOL_GPL(__create_workqueue_key);
-static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq, int cpu)
+static void cleanup_workqueue_thread(struct cpu_workqueue_struct *cwq)
{
/*
* Our caller is either destroy_workqueue() or CPU_DEAD,
@@ -808,19 +806,16 @@
void destroy_workqueue(struct workqueue_struct *wq)
{
const cpumask_t *cpu_map = wq_cpu_map(wq);
- struct cpu_workqueue_struct *cwq;
int cpu;
get_online_cpus();
spin_lock(&workqueue_lock);
list_del(&wq->list);
spin_unlock(&workqueue_lock);
- put_online_cpus();
- for_each_cpu_mask(cpu, *cpu_map) {
- cwq = per_cpu_ptr(wq->cpu_wq, cpu);
- cleanup_workqueue_thread(cwq, cpu);
- }
+ for_each_cpu_mask(cpu, *cpu_map)
+ cleanup_workqueue_thread(per_cpu_ptr(wq->cpu_wq, cpu));
+ put_online_cpus();
free_percpu(wq->cpu_wq);
kfree(wq);
@@ -838,7 +833,6 @@
action &= ~CPU_TASKS_FROZEN;
switch (action) {
-
case CPU_UP_PREPARE:
cpu_set(cpu, cpu_populated_map);
}
@@ -861,11 +855,17 @@
case CPU_UP_CANCELED:
start_workqueue_thread(cwq, -1);
case CPU_DEAD:
- cleanup_workqueue_thread(cwq, cpu);
+ cleanup_workqueue_thread(cwq);
break;
}
}
+ switch (action) {
+ case CPU_UP_CANCELED:
+ case CPU_DEAD:
+ cpu_clear(cpu, cpu_populated_map);
+ }
+
return NOTIFY_OK;
}
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 754cc00..d2099f4 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -194,6 +194,37 @@
(it defaults to deactivated on bootup and will only be activated
if some application like powertop activates it explicitly).
+config DEBUG_OBJECTS
+ bool "Debug object operations"
+ depends on DEBUG_KERNEL
+ help
+ If you say Y here, additional code will be inserted into the
+ kernel to track the life time of various objects and validate
+ the operations on those objects.
+
+config DEBUG_OBJECTS_SELFTEST
+ bool "Debug objects selftest"
+ depends on DEBUG_OBJECTS
+ help
+ This enables the selftest of the object debug code.
+
+config DEBUG_OBJECTS_FREE
+ bool "Debug objects in freed memory"
+ depends on DEBUG_OBJECTS
+ help
+ This enables checks whether a k/v free operation frees an area
+ which contains an object which has not been deactivated
+ properly. This can make kmalloc/kfree-intensive workloads
+ much slower.
+
+config DEBUG_OBJECTS_TIMERS
+ bool "Debug timer objects"
+ depends on DEBUG_OBJECTS
+ help
+ If you say Y here, additional code will be inserted into the
+ timer routines to track the life time of timer objects and
+ validate the timer operations.
+
config DEBUG_SLAB
bool "Debug slab memory allocations"
depends on DEBUG_KERNEL && SLAB
diff --git a/lib/Makefile b/lib/Makefile
index 2d7001b..74b0cfb 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -6,7 +6,7 @@
rbtree.o radix-tree.o dump_stack.o \
idr.o int_sqrt.o extable.o prio_tree.o \
sha1.o irq_regs.o reciprocal_div.o argv_split.o \
- proportions.o prio_heap.o
+ proportions.o prio_heap.o ratelimit.o
lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
@@ -36,6 +36,7 @@
obj-$(CONFIG_PLIST) += plist.o
obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
obj-$(CONFIG_DEBUG_LIST) += list_debug.o
+obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o
ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
lib-y += dec_and_lock.o
diff --git a/lib/debugobjects.c b/lib/debugobjects.c
new file mode 100644
index 0000000..a76a5e1
--- /dev/null
+++ b/lib/debugobjects.c
@@ -0,0 +1,890 @@
+/*
+ * Generic infrastructure for lifetime debugging of objects.
+ *
+ * Started by Thomas Gleixner
+ *
+ * Copyright (C) 2008, Thomas Gleixner <tglx@linutronix.de>
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+#include <linux/debugobjects.h>
+#include <linux/interrupt.h>
+#include <linux/seq_file.h>
+#include <linux/debugfs.h>
+#include <linux/hash.h>
+
+#define ODEBUG_HASH_BITS 14
+#define ODEBUG_HASH_SIZE (1 << ODEBUG_HASH_BITS)
+
+#define ODEBUG_POOL_SIZE 512
+#define ODEBUG_POOL_MIN_LEVEL 256
+
+#define ODEBUG_CHUNK_SHIFT PAGE_SHIFT
+#define ODEBUG_CHUNK_SIZE (1 << ODEBUG_CHUNK_SHIFT)
+#define ODEBUG_CHUNK_MASK (~(ODEBUG_CHUNK_SIZE - 1))
+
+struct debug_bucket {
+ struct hlist_head list;
+ spinlock_t lock;
+};
+
+static struct debug_bucket obj_hash[ODEBUG_HASH_SIZE];
+
+static struct debug_obj obj_static_pool[ODEBUG_POOL_SIZE];
+
+static DEFINE_SPINLOCK(pool_lock);
+
+static HLIST_HEAD(obj_pool);
+
+static int obj_pool_min_free = ODEBUG_POOL_SIZE;
+static int obj_pool_free = ODEBUG_POOL_SIZE;
+static int obj_pool_used;
+static int obj_pool_max_used;
+static struct kmem_cache *obj_cache;
+
+static int debug_objects_maxchain __read_mostly;
+static int debug_objects_fixups __read_mostly;
+static int debug_objects_warnings __read_mostly;
+static int debug_objects_enabled __read_mostly;
+static struct debug_obj_descr *descr_test __read_mostly;
+
+static int __init enable_object_debug(char *str)
+{
+ debug_objects_enabled = 1;
+ return 0;
+}
+early_param("debug_objects", enable_object_debug);
+
+static const char *obj_states[ODEBUG_STATE_MAX] = {
+ [ODEBUG_STATE_NONE] = "none",
+ [ODEBUG_STATE_INIT] = "initialized",
+ [ODEBUG_STATE_INACTIVE] = "inactive",
+ [ODEBUG_STATE_ACTIVE] = "active",
+ [ODEBUG_STATE_DESTROYED] = "destroyed",
+ [ODEBUG_STATE_NOTAVAILABLE] = "not available",
+};
+
+static int fill_pool(void)
+{
+ gfp_t gfp = GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN;
+ struct debug_obj *new;
+
+ if (likely(obj_pool_free >= ODEBUG_POOL_MIN_LEVEL))
+ return obj_pool_free;
+
+ if (unlikely(!obj_cache))
+ return obj_pool_free;
+
+ while (obj_pool_free < ODEBUG_POOL_MIN_LEVEL) {
+
+ new = kmem_cache_zalloc(obj_cache, gfp);
+ if (!new)
+ return obj_pool_free;
+
+ spin_lock(&pool_lock);
+ hlist_add_head(&new->node, &obj_pool);
+ obj_pool_free++;
+ spin_unlock(&pool_lock);
+ }
+ return obj_pool_free;
+}
+
+/*
+ * Lookup an object in the hash bucket.
+ */
+static struct debug_obj *lookup_object(void *addr, struct debug_bucket *b)
+{
+ struct hlist_node *node;
+ struct debug_obj *obj;
+ int cnt = 0;
+
+ hlist_for_each_entry(obj, node, &b->list, node) {
+ cnt++;
+ if (obj->object == addr)
+ return obj;
+ }
+ if (cnt > debug_objects_maxchain)
+ debug_objects_maxchain = cnt;
+
+ return NULL;
+}
+
+/*
+ * Allocate a new object. If the pool is empty and no refill possible,
+ * switch off the debugger.
+ */
+static struct debug_obj *
+alloc_object(void *addr, struct debug_bucket *b, struct debug_obj_descr *descr)
+{
+ struct debug_obj *obj = NULL;
+ int retry = 0;
+
+repeat:
+ spin_lock(&pool_lock);
+ if (obj_pool.first) {
+ obj = hlist_entry(obj_pool.first, typeof(*obj), node);
+
+ obj->object = addr;
+ obj->descr = descr;
+ obj->state = ODEBUG_STATE_NONE;
+ hlist_del(&obj->node);
+
+ hlist_add_head(&obj->node, &b->list);
+
+ obj_pool_used++;
+ if (obj_pool_used > obj_pool_max_used)
+ obj_pool_max_used = obj_pool_used;
+
+ obj_pool_free--;
+ if (obj_pool_free < obj_pool_min_free)
+ obj_pool_min_free = obj_pool_free;
+ }
+ spin_unlock(&pool_lock);
+
+ if (fill_pool() && !obj && !retry++)
+ goto repeat;
+
+ return obj;
+}
+
+/*
+ * Put the object back into the pool or give it back to kmem_cache:
+ */
+static void free_object(struct debug_obj *obj)
+{
+ unsigned long idx = (unsigned long)(obj - obj_static_pool);
+
+ if (obj_pool_free < ODEBUG_POOL_SIZE || idx < ODEBUG_POOL_SIZE) {
+ spin_lock(&pool_lock);
+ hlist_add_head(&obj->node, &obj_pool);
+ obj_pool_free++;
+ obj_pool_used--;
+ spin_unlock(&pool_lock);
+ } else {
+ spin_lock(&pool_lock);
+ obj_pool_used--;
+ spin_unlock(&pool_lock);
+ kmem_cache_free(obj_cache, obj);
+ }
+}
+
+/*
+ * We run out of memory. That means we probably have tons of objects
+ * allocated.
+ */
+static void debug_objects_oom(void)
+{
+ struct debug_bucket *db = obj_hash;
+ struct hlist_node *node, *tmp;
+ struct debug_obj *obj;
+ unsigned long flags;
+ int i;
+
+ printk(KERN_WARNING "ODEBUG: Out of memory. ODEBUG disabled\n");
+
+ for (i = 0; i < ODEBUG_HASH_SIZE; i++, db++) {
+ spin_lock_irqsave(&db->lock, flags);
+ hlist_for_each_entry_safe(obj, node, tmp, &db->list, node) {
+ hlist_del(&obj->node);
+ free_object(obj);
+ }
+ spin_unlock_irqrestore(&db->lock, flags);
+ }
+}
+
+/*
+ * We use the pfn of the address for the hash. That way we can check
+ * for freed objects simply by checking the affected bucket.
+ */
+static struct debug_bucket *get_bucket(unsigned long addr)
+{
+ unsigned long hash;
+
+ hash = hash_long((addr >> ODEBUG_CHUNK_SHIFT), ODEBUG_HASH_BITS);
+ return &obj_hash[hash];
+}
+
+static void debug_print_object(struct debug_obj *obj, char *msg)
+{
+ static int limit;
+
+ if (limit < 5 && obj->descr != descr_test) {
+ limit++;
+ printk(KERN_ERR "ODEBUG: %s %s object type: %s\n", msg,
+ obj_states[obj->state], obj->descr->name);
+ WARN_ON(1);
+ }
+ debug_objects_warnings++;
+}
+
+/*
+ * Try to repair the damage, so we have a better chance to get useful
+ * debug output.
+ */
+static void
+debug_object_fixup(int (*fixup)(void *addr, enum debug_obj_state state),
+ void * addr, enum debug_obj_state state)
+{
+ if (fixup)
+ debug_objects_fixups += fixup(addr, state);
+}
+
+static void debug_object_is_on_stack(void *addr, int onstack)
+{
+ void *stack = current->stack;
+ int is_on_stack;
+ static int limit;
+
+ if (limit > 4)
+ return;
+
+ is_on_stack = (addr >= stack && addr < (stack + THREAD_SIZE));
+
+ if (is_on_stack == onstack)
+ return;
+
+ limit++;
+ if (is_on_stack)
+ printk(KERN_WARNING
+ "ODEBUG: object is on stack, but not annotated\n");
+ else
+ printk(KERN_WARNING
+ "ODEBUG: object is not on stack, but annotated\n");
+ WARN_ON(1);
+}
+
+static void
+__debug_object_init(void *addr, struct debug_obj_descr *descr, int onstack)
+{
+ enum debug_obj_state state;
+ struct debug_bucket *db;
+ struct debug_obj *obj;
+ unsigned long flags;
+
+ db = get_bucket((unsigned long) addr);
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ obj = lookup_object(addr, db);
+ if (!obj) {
+ obj = alloc_object(addr, db, descr);
+ if (!obj) {
+ debug_objects_enabled = 0;
+ spin_unlock_irqrestore(&db->lock, flags);
+ debug_objects_oom();
+ return;
+ }
+ debug_object_is_on_stack(addr, onstack);
+ }
+
+ switch (obj->state) {
+ case ODEBUG_STATE_NONE:
+ case ODEBUG_STATE_INIT:
+ case ODEBUG_STATE_INACTIVE:
+ obj->state = ODEBUG_STATE_INIT;
+ break;
+
+ case ODEBUG_STATE_ACTIVE:
+ debug_print_object(obj, "init");
+ state = obj->state;
+ spin_unlock_irqrestore(&db->lock, flags);
+ debug_object_fixup(descr->fixup_init, addr, state);
+ return;
+
+ case ODEBUG_STATE_DESTROYED:
+ debug_print_object(obj, "init");
+ break;
+ default:
+ break;
+ }
+
+ spin_unlock_irqrestore(&db->lock, flags);
+}
+
+/**
+ * debug_object_init - debug checks when an object is initialized
+ * @addr: address of the object
+ * @descr: pointer to an object specific debug description structure
+ */
+void debug_object_init(void *addr, struct debug_obj_descr *descr)
+{
+ if (!debug_objects_enabled)
+ return;
+
+ __debug_object_init(addr, descr, 0);
+}
+
+/**
+ * debug_object_init_on_stack - debug checks when an object on stack is
+ * initialized
+ * @addr: address of the object
+ * @descr: pointer to an object specific debug description structure
+ */
+void debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr)
+{
+ if (!debug_objects_enabled)
+ return;
+
+ __debug_object_init(addr, descr, 1);
+}
+
+/**
+ * debug_object_activate - debug checks when an object is activated
+ * @addr: address of the object
+ * @descr: pointer to an object specific debug description structure
+ */
+void debug_object_activate(void *addr, struct debug_obj_descr *descr)
+{
+ enum debug_obj_state state;
+ struct debug_bucket *db;
+ struct debug_obj *obj;
+ unsigned long flags;
+
+ if (!debug_objects_enabled)
+ return;
+
+ db = get_bucket((unsigned long) addr);
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ obj = lookup_object(addr, db);
+ if (obj) {
+ switch (obj->state) {
+ case ODEBUG_STATE_INIT:
+ case ODEBUG_STATE_INACTIVE:
+ obj->state = ODEBUG_STATE_ACTIVE;
+ break;
+
+ case ODEBUG_STATE_ACTIVE:
+ debug_print_object(obj, "activate");
+ state = obj->state;
+ spin_unlock_irqrestore(&db->lock, flags);
+ debug_object_fixup(descr->fixup_activate, addr, state);
+ return;
+
+ case ODEBUG_STATE_DESTROYED:
+ debug_print_object(obj, "activate");
+ break;
+ default:
+ break;
+ }
+ spin_unlock_irqrestore(&db->lock, flags);
+ return;
+ }
+
+ spin_unlock_irqrestore(&db->lock, flags);
+ /*
+ * This happens when a static object is activated. We
+ * let the type specific code decide whether this is
+ * true or not.
+ */
+ debug_object_fixup(descr->fixup_activate, addr,
+ ODEBUG_STATE_NOTAVAILABLE);
+}
+
+/**
+ * debug_object_deactivate - debug checks when an object is deactivated
+ * @addr: address of the object
+ * @descr: pointer to an object specific debug description structure
+ */
+void debug_object_deactivate(void *addr, struct debug_obj_descr *descr)
+{
+ struct debug_bucket *db;
+ struct debug_obj *obj;
+ unsigned long flags;
+
+ if (!debug_objects_enabled)
+ return;
+
+ db = get_bucket((unsigned long) addr);
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ obj = lookup_object(addr, db);
+ if (obj) {
+ switch (obj->state) {
+ case ODEBUG_STATE_INIT:
+ case ODEBUG_STATE_INACTIVE:
+ case ODEBUG_STATE_ACTIVE:
+ obj->state = ODEBUG_STATE_INACTIVE;
+ break;
+
+ case ODEBUG_STATE_DESTROYED:
+ debug_print_object(obj, "deactivate");
+ break;
+ default:
+ break;
+ }
+ } else {
+ struct debug_obj o = { .object = addr,
+ .state = ODEBUG_STATE_NOTAVAILABLE,
+ .descr = descr };
+
+ debug_print_object(&o, "deactivate");
+ }
+
+ spin_unlock_irqrestore(&db->lock, flags);
+}
+
+/**
+ * debug_object_destroy - debug checks when an object is destroyed
+ * @addr: address of the object
+ * @descr: pointer to an object specific debug description structure
+ */
+void debug_object_destroy(void *addr, struct debug_obj_descr *descr)
+{
+ enum debug_obj_state state;
+ struct debug_bucket *db;
+ struct debug_obj *obj;
+ unsigned long flags;
+
+ if (!debug_objects_enabled)
+ return;
+
+ db = get_bucket((unsigned long) addr);
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ obj = lookup_object(addr, db);
+ if (!obj)
+ goto out_unlock;
+
+ switch (obj->state) {
+ case ODEBUG_STATE_NONE:
+ case ODEBUG_STATE_INIT:
+ case ODEBUG_STATE_INACTIVE:
+ obj->state = ODEBUG_STATE_DESTROYED;
+ break;
+ case ODEBUG_STATE_ACTIVE:
+ debug_print_object(obj, "destroy");
+ state = obj->state;
+ spin_unlock_irqrestore(&db->lock, flags);
+ debug_object_fixup(descr->fixup_destroy, addr, state);
+ return;
+
+ case ODEBUG_STATE_DESTROYED:
+ debug_print_object(obj, "destroy");
+ break;
+ default:
+ break;
+ }
+out_unlock:
+ spin_unlock_irqrestore(&db->lock, flags);
+}
+
+/**
+ * debug_object_free - debug checks when an object is freed
+ * @addr: address of the object
+ * @descr: pointer to an object specific debug description structure
+ */
+void debug_object_free(void *addr, struct debug_obj_descr *descr)
+{
+ enum debug_obj_state state;
+ struct debug_bucket *db;
+ struct debug_obj *obj;
+ unsigned long flags;
+
+ if (!debug_objects_enabled)
+ return;
+
+ db = get_bucket((unsigned long) addr);
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ obj = lookup_object(addr, db);
+ if (!obj)
+ goto out_unlock;
+
+ switch (obj->state) {
+ case ODEBUG_STATE_ACTIVE:
+ debug_print_object(obj, "free");
+ state = obj->state;
+ spin_unlock_irqrestore(&db->lock, flags);
+ debug_object_fixup(descr->fixup_free, addr, state);
+ return;
+ default:
+ hlist_del(&obj->node);
+ free_object(obj);
+ break;
+ }
+out_unlock:
+ spin_unlock_irqrestore(&db->lock, flags);
+}
+
+#ifdef CONFIG_DEBUG_OBJECTS_FREE
+static void __debug_check_no_obj_freed(const void *address, unsigned long size)
+{
+ unsigned long flags, oaddr, saddr, eaddr, paddr, chunks;
+ struct hlist_node *node, *tmp;
+ struct debug_obj_descr *descr;
+ enum debug_obj_state state;
+ struct debug_bucket *db;
+ struct debug_obj *obj;
+ int cnt;
+
+ saddr = (unsigned long) address;
+ eaddr = saddr + size;
+ paddr = saddr & ODEBUG_CHUNK_MASK;
+ chunks = ((eaddr - paddr) + (ODEBUG_CHUNK_SIZE - 1));
+ chunks >>= ODEBUG_CHUNK_SHIFT;
+
+ for (;chunks > 0; chunks--, paddr += ODEBUG_CHUNK_SIZE) {
+ db = get_bucket(paddr);
+
+repeat:
+ cnt = 0;
+ spin_lock_irqsave(&db->lock, flags);
+ hlist_for_each_entry_safe(obj, node, tmp, &db->list, node) {
+ cnt++;
+ oaddr = (unsigned long) obj->object;
+ if (oaddr < saddr || oaddr >= eaddr)
+ continue;
+
+ switch (obj->state) {
+ case ODEBUG_STATE_ACTIVE:
+ debug_print_object(obj, "free");
+ descr = obj->descr;
+ state = obj->state;
+ spin_unlock_irqrestore(&db->lock, flags);
+ debug_object_fixup(descr->fixup_free,
+ (void *) oaddr, state);
+ goto repeat;
+ default:
+ hlist_del(&obj->node);
+ free_object(obj);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&db->lock, flags);
+ if (cnt > debug_objects_maxchain)
+ debug_objects_maxchain = cnt;
+ }
+}
+
+void debug_check_no_obj_freed(const void *address, unsigned long size)
+{
+ if (debug_objects_enabled)
+ __debug_check_no_obj_freed(address, size);
+}
+#endif
+
+#ifdef CONFIG_DEBUG_FS
+
+static int debug_stats_show(struct seq_file *m, void *v)
+{
+ seq_printf(m, "max_chain :%d\n", debug_objects_maxchain);
+ seq_printf(m, "warnings :%d\n", debug_objects_warnings);
+ seq_printf(m, "fixups :%d\n", debug_objects_fixups);
+ seq_printf(m, "pool_free :%d\n", obj_pool_free);
+ seq_printf(m, "pool_min_free :%d\n", obj_pool_min_free);
+ seq_printf(m, "pool_used :%d\n", obj_pool_used);
+ seq_printf(m, "pool_max_used :%d\n", obj_pool_max_used);
+ return 0;
+}
+
+static int debug_stats_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, debug_stats_show, NULL);
+}
+
+static const struct file_operations debug_stats_fops = {
+ .open = debug_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init debug_objects_init_debugfs(void)
+{
+ struct dentry *dbgdir, *dbgstats;
+
+ if (!debug_objects_enabled)
+ return 0;
+
+ dbgdir = debugfs_create_dir("debug_objects", NULL);
+ if (!dbgdir)
+ return -ENOMEM;
+
+ dbgstats = debugfs_create_file("stats", 0444, dbgdir, NULL,
+ &debug_stats_fops);
+ if (!dbgstats)
+ goto err;
+
+ return 0;
+
+err:
+ debugfs_remove(dbgdir);
+
+ return -ENOMEM;
+}
+__initcall(debug_objects_init_debugfs);
+
+#else
+static inline void debug_objects_init_debugfs(void) { }
+#endif
+
+#ifdef CONFIG_DEBUG_OBJECTS_SELFTEST
+
+/* Random data structure for the self test */
+struct self_test {
+ unsigned long dummy1[6];
+ int static_init;
+ unsigned long dummy2[3];
+};
+
+static __initdata struct debug_obj_descr descr_type_test;
+
+/*
+ * fixup_init is called when:
+ * - an active object is initialized
+ */
+static int __init fixup_init(void *addr, enum debug_obj_state state)
+{
+ struct self_test *obj = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ debug_object_deactivate(obj, &descr_type_test);
+ debug_object_init(obj, &descr_type_test);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * fixup_activate is called when:
+ * - an active object is activated
+ * - an unknown object is activated (might be a statically initialized object)
+ */
+static int __init fixup_activate(void *addr, enum debug_obj_state state)
+{
+ struct self_test *obj = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_NOTAVAILABLE:
+ if (obj->static_init == 1) {
+ debug_object_init(obj, &descr_type_test);
+ debug_object_activate(obj, &descr_type_test);
+ /*
+ * Real code should return 0 here ! This is
+ * not a fixup of some bad behaviour. We
+ * merily call the debug_init function to keep
+ * track of the object.
+ */
+ return 1;
+ } else {
+ /* Real code needs to emit a warning here */
+ }
+ return 0;
+
+ case ODEBUG_STATE_ACTIVE:
+ debug_object_deactivate(obj, &descr_type_test);
+ debug_object_activate(obj, &descr_type_test);
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/*
+ * fixup_destroy is called when:
+ * - an active object is destroyed
+ */
+static int __init fixup_destroy(void *addr, enum debug_obj_state state)
+{
+ struct self_test *obj = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ debug_object_deactivate(obj, &descr_type_test);
+ debug_object_destroy(obj, &descr_type_test);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/*
+ * fixup_free is called when:
+ * - an active object is freed
+ */
+static int __init fixup_free(void *addr, enum debug_obj_state state)
+{
+ struct self_test *obj = addr;
+
+ switch (state) {
+ case ODEBUG_STATE_ACTIVE:
+ debug_object_deactivate(obj, &descr_type_test);
+ debug_object_free(obj, &descr_type_test);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int
+check_results(void *addr, enum debug_obj_state state, int fixups, int warnings)
+{
+ struct debug_bucket *db;
+ struct debug_obj *obj;
+ unsigned long flags;
+ int res = -EINVAL;
+
+ db = get_bucket((unsigned long) addr);
+
+ spin_lock_irqsave(&db->lock, flags);
+
+ obj = lookup_object(addr, db);
+ if (!obj && state != ODEBUG_STATE_NONE) {
+ printk(KERN_ERR "ODEBUG: selftest object not found\n");
+ WARN_ON(1);
+ goto out;
+ }
+ if (obj && obj->state != state) {
+ printk(KERN_ERR "ODEBUG: selftest wrong state: %d != %d\n",
+ obj->state, state);
+ WARN_ON(1);
+ goto out;
+ }
+ if (fixups != debug_objects_fixups) {
+ printk(KERN_ERR "ODEBUG: selftest fixups failed %d != %d\n",
+ fixups, debug_objects_fixups);
+ WARN_ON(1);
+ goto out;
+ }
+ if (warnings != debug_objects_warnings) {
+ printk(KERN_ERR "ODEBUG: selftest warnings failed %d != %d\n",
+ warnings, debug_objects_warnings);
+ WARN_ON(1);
+ goto out;
+ }
+ res = 0;
+out:
+ spin_unlock_irqrestore(&db->lock, flags);
+ if (res)
+ debug_objects_enabled = 0;
+ return res;
+}
+
+static __initdata struct debug_obj_descr descr_type_test = {
+ .name = "selftest",
+ .fixup_init = fixup_init,
+ .fixup_activate = fixup_activate,
+ .fixup_destroy = fixup_destroy,
+ .fixup_free = fixup_free,
+};
+
+static __initdata struct self_test obj = { .static_init = 0 };
+
+static void __init debug_objects_selftest(void)
+{
+ int fixups, oldfixups, warnings, oldwarnings;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ fixups = oldfixups = debug_objects_fixups;
+ warnings = oldwarnings = debug_objects_warnings;
+ descr_test = &descr_type_test;
+
+ debug_object_init(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_INIT, fixups, warnings))
+ goto out;
+ debug_object_activate(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))
+ goto out;
+ debug_object_activate(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_ACTIVE, ++fixups, ++warnings))
+ goto out;
+ debug_object_deactivate(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_INACTIVE, fixups, warnings))
+ goto out;
+ debug_object_destroy(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, warnings))
+ goto out;
+ debug_object_init(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, ++warnings))
+ goto out;
+ debug_object_activate(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, ++warnings))
+ goto out;
+ debug_object_deactivate(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_DESTROYED, fixups, ++warnings))
+ goto out;
+ debug_object_free(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_NONE, fixups, warnings))
+ goto out;
+
+ obj.static_init = 1;
+ debug_object_activate(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_ACTIVE, ++fixups, warnings))
+ goto out;
+ debug_object_init(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_INIT, ++fixups, ++warnings))
+ goto out;
+ debug_object_free(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_NONE, fixups, warnings))
+ goto out;
+
+#ifdef CONFIG_DEBUG_OBJECTS_FREE
+ debug_object_init(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_INIT, fixups, warnings))
+ goto out;
+ debug_object_activate(&obj, &descr_type_test);
+ if (check_results(&obj, ODEBUG_STATE_ACTIVE, fixups, warnings))
+ goto out;
+ __debug_check_no_obj_freed(&obj, sizeof(obj));
+ if (check_results(&obj, ODEBUG_STATE_NONE, ++fixups, ++warnings))
+ goto out;
+#endif
+ printk(KERN_INFO "ODEBUG: selftest passed\n");
+
+out:
+ debug_objects_fixups = oldfixups;
+ debug_objects_warnings = oldwarnings;
+ descr_test = NULL;
+
+ local_irq_restore(flags);
+}
+#else
+static inline void debug_objects_selftest(void) { }
+#endif
+
+/*
+ * Called during early boot to initialize the hash buckets and link
+ * the static object pool objects into the poll list. After this call
+ * the object tracker is fully operational.
+ */
+void __init debug_objects_early_init(void)
+{
+ int i;
+
+ for (i = 0; i < ODEBUG_HASH_SIZE; i++)
+ spin_lock_init(&obj_hash[i].lock);
+
+ for (i = 0; i < ODEBUG_POOL_SIZE; i++)
+ hlist_add_head(&obj_static_pool[i].node, &obj_pool);
+}
+
+/*
+ * Called after the kmem_caches are functional to setup a dedicated
+ * cache pool, which has the SLAB_DEBUG_OBJECTS flag set. This flag
+ * prevents that the debug code is called on kmem_cache_free() for the
+ * debug tracker objects to avoid recursive calls.
+ */
+void __init debug_objects_mem_init(void)
+{
+ if (!debug_objects_enabled)
+ return;
+
+ obj_cache = kmem_cache_create("debug_objects_cache",
+ sizeof (struct debug_obj), 0,
+ SLAB_DEBUG_OBJECTS, NULL);
+
+ if (!obj_cache)
+ debug_objects_enabled = 0;
+ else
+ debug_objects_selftest();
+}
diff --git a/lib/devres.c b/lib/devres.c
index edc27a5..26c87c4 100644
--- a/lib/devres.c
+++ b/lib/devres.c
@@ -20,7 +20,7 @@
*
* Managed ioremap(). Map is automatically unmapped on driver detach.
*/
-void __iomem *devm_ioremap(struct device *dev, unsigned long offset,
+void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
unsigned long size)
{
void __iomem **ptr, *addr;
@@ -49,7 +49,7 @@
* Managed ioremap_nocache(). Map is automatically unmapped on driver
* detach.
*/
-void __iomem *devm_ioremap_nocache(struct device *dev, unsigned long offset,
+void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset,
unsigned long size)
{
void __iomem **ptr, *addr;
diff --git a/lib/div64.c b/lib/div64.c
index b71cf93..bb5bd0c 100644
--- a/lib/div64.c
+++ b/lib/div64.c
@@ -16,9 +16,8 @@
* assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
*/
-#include <linux/types.h>
#include <linux/module.h>
-#include <asm/div64.h>
+#include <linux/math64.h>
/* Not needed on 64bit architectures */
#if BITS_PER_LONG == 32
@@ -58,10 +57,31 @@
EXPORT_SYMBOL(__div64_32);
-/* 64bit divisor, dividend and result. dynamic precision */
-uint64_t div64_64(uint64_t dividend, uint64_t divisor)
+#ifndef div_s64_rem
+s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
{
- uint32_t high, d;
+ u64 quotient;
+
+ if (dividend < 0) {
+ quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
+ *remainder = -*remainder;
+ if (divisor > 0)
+ quotient = -quotient;
+ } else {
+ quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
+ if (divisor < 0)
+ quotient = -quotient;
+ }
+ return quotient;
+}
+EXPORT_SYMBOL(div_s64_rem);
+#endif
+
+/* 64bit divisor, dividend and result. dynamic precision */
+#ifndef div64_u64
+u64 div64_u64(u64 dividend, u64 divisor)
+{
+ u32 high, d;
high = divisor >> 32;
if (high) {
@@ -72,10 +92,9 @@
} else
d = divisor;
- do_div(dividend, d);
-
- return dividend;
+ return div_u64(dividend, d);
}
-EXPORT_SYMBOL(div64_64);
+EXPORT_SYMBOL(div64_u64);
+#endif
#endif /* BITS_PER_LONG == 32 */
diff --git a/lib/find_next_bit.c b/lib/find_next_bit.c
index d3f5784..24c59de 100644
--- a/lib/find_next_bit.c
+++ b/lib/find_next_bit.c
@@ -20,8 +20,8 @@
/*
* Find the next set bit in a memory region.
*/
-unsigned long __find_next_bit(const unsigned long *addr,
- unsigned long size, unsigned long offset)
+unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
@@ -58,14 +58,14 @@
found_middle:
return result + __ffs(tmp);
}
-EXPORT_SYMBOL(__find_next_bit);
+EXPORT_SYMBOL(find_next_bit);
/*
* This implementation of find_{first,next}_zero_bit was stolen from
* Linus' asm-alpha/bitops.h.
*/
-unsigned long __find_next_zero_bit(const unsigned long *addr,
- unsigned long size, unsigned long offset)
+unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
+ unsigned long offset)
{
const unsigned long *p = addr + BITOP_WORD(offset);
unsigned long result = offset & ~(BITS_PER_LONG-1);
@@ -102,15 +102,14 @@
found_middle:
return result + ffz(tmp);
}
-EXPORT_SYMBOL(__find_next_zero_bit);
+EXPORT_SYMBOL(find_next_zero_bit);
#endif /* CONFIG_GENERIC_FIND_NEXT_BIT */
#ifdef CONFIG_GENERIC_FIND_FIRST_BIT
/*
* Find the first set bit in a memory region.
*/
-unsigned long __find_first_bit(const unsigned long *addr,
- unsigned long size)
+unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
{
const unsigned long *p = addr;
unsigned long result = 0;
@@ -131,13 +130,12 @@
found:
return result + __ffs(tmp);
}
-EXPORT_SYMBOL(__find_first_bit);
+EXPORT_SYMBOL(find_first_bit);
/*
* Find the first cleared bit in a memory region.
*/
-unsigned long __find_first_zero_bit(const unsigned long *addr,
- unsigned long size)
+unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size)
{
const unsigned long *p = addr;
unsigned long result = 0;
@@ -158,7 +156,7 @@
found:
return result + ffz(tmp);
}
-EXPORT_SYMBOL(__find_first_zero_bit);
+EXPORT_SYMBOL(find_first_zero_bit);
#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */
#ifdef __BIG_ENDIAN
diff --git a/lib/idr.c b/lib/idr.c
index afbb0b1..7a02e17 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -385,8 +385,8 @@
while (idp->id_free_cnt >= IDR_FREE_MAX) {
p = alloc_layer(idp);
kmem_cache_free(idr_layer_cache, p);
- return;
}
+ return;
}
EXPORT_SYMBOL(idr_remove);
@@ -585,12 +585,11 @@
memset(idr_layer, 0, sizeof(struct idr_layer));
}
-static int init_id_cache(void)
+void __init idr_init_cache(void)
{
- if (!idr_layer_cache)
- idr_layer_cache = kmem_cache_create("idr_layer_cache",
- sizeof(struct idr_layer), 0, 0, idr_cache_ctor);
- return 0;
+ idr_layer_cache = kmem_cache_create("idr_layer_cache",
+ sizeof(struct idr_layer), 0, SLAB_PANIC,
+ idr_cache_ctor);
}
/**
@@ -602,7 +601,6 @@
*/
void idr_init(struct idr *idp)
{
- init_id_cache();
memset(idp, 0, sizeof(struct idr));
spin_lock_init(&idp->lock);
}
diff --git a/lib/inflate.c b/lib/inflate.c
index 845f91d..9762294 100644
--- a/lib/inflate.c
+++ b/lib/inflate.c
@@ -811,6 +811,9 @@
ll = malloc(sizeof(*ll) * (286+30)); /* literal/length and distance code lengths */
#endif
+ if (ll == NULL)
+ return 1;
+
/* make local bit buffer */
b = bb;
k = bk;
diff --git a/lib/iomap.c b/lib/iomap.c
index dd6ca48..37a3ea4 100644
--- a/lib/iomap.c
+++ b/lib/iomap.c
@@ -257,7 +257,7 @@
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
resource_size_t start = pci_resource_start(dev, bar);
- unsigned long len = pci_resource_len(dev, bar);
+ resource_size_t len = pci_resource_len(dev, bar);
unsigned long flags = pci_resource_flags(dev, bar);
if (!len || !start)
diff --git a/lib/klist.c b/lib/klist.c
index 120bd17..cca37f9 100644
--- a/lib/klist.c
+++ b/lib/klist.c
@@ -1,38 +1,37 @@
/*
- * klist.c - Routines for manipulating klists.
+ * klist.c - Routines for manipulating klists.
*
+ * Copyright (C) 2005 Patrick Mochel
*
- * This klist interface provides a couple of structures that wrap around
- * struct list_head to provide explicit list "head" (struct klist) and
- * list "node" (struct klist_node) objects. For struct klist, a spinlock
- * is included that protects access to the actual list itself. struct
- * klist_node provides a pointer to the klist that owns it and a kref
- * reference count that indicates the number of current users of that node
- * in the list.
+ * This file is released under the GPL v2.
*
- * The entire point is to provide an interface for iterating over a list
- * that is safe and allows for modification of the list during the
- * iteration (e.g. insertion and removal), including modification of the
- * current node on the list.
+ * This klist interface provides a couple of structures that wrap around
+ * struct list_head to provide explicit list "head" (struct klist) and list
+ * "node" (struct klist_node) objects. For struct klist, a spinlock is
+ * included that protects access to the actual list itself. struct
+ * klist_node provides a pointer to the klist that owns it and a kref
+ * reference count that indicates the number of current users of that node
+ * in the list.
*
- * It works using a 3rd object type - struct klist_iter - that is declared
- * and initialized before an iteration. klist_next() is used to acquire the
- * next element in the list. It returns NULL if there are no more items.
- * Internally, that routine takes the klist's lock, decrements the reference
- * count of the previous klist_node and increments the count of the next
- * klist_node. It then drops the lock and returns.
+ * The entire point is to provide an interface for iterating over a list
+ * that is safe and allows for modification of the list during the
+ * iteration (e.g. insertion and removal), including modification of the
+ * current node on the list.
*
- * There are primitives for adding and removing nodes to/from a klist.
- * When deleting, klist_del() will simply decrement the reference count.
- * Only when the count goes to 0 is the node removed from the list.
- * klist_remove() will try to delete the node from the list and block
- * until it is actually removed. This is useful for objects (like devices)
- * that have been removed from the system and must be freed (but must wait
- * until all accessors have finished).
+ * It works using a 3rd object type - struct klist_iter - that is declared
+ * and initialized before an iteration. klist_next() is used to acquire the
+ * next element in the list. It returns NULL if there are no more items.
+ * Internally, that routine takes the klist's lock, decrements the
+ * reference count of the previous klist_node and increments the count of
+ * the next klist_node. It then drops the lock and returns.
*
- * Copyright (C) 2005 Patrick Mochel
- *
- * This file is released under the GPL v2.
+ * There are primitives for adding and removing nodes to/from a klist.
+ * When deleting, klist_del() will simply decrement the reference count.
+ * Only when the count goes to 0 is the node removed from the list.
+ * klist_remove() will try to delete the node from the list and block until
+ * it is actually removed. This is useful for objects (like devices) that
+ * have been removed from the system and must be freed (but must wait until
+ * all accessors have finished).
*/
#include <linux/klist.h>
@@ -40,10 +39,10 @@
/**
- * 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)
+ * 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
@@ -51,8 +50,7 @@
* functions that take and release references on the embedding
* objects.
*/
-
-void klist_init(struct klist * k, void (*get)(struct klist_node *),
+void klist_init(struct klist *k, void (*get)(struct klist_node *),
void (*put)(struct klist_node *))
{
INIT_LIST_HEAD(&k->k_list);
@@ -60,26 +58,23 @@
k->get = get;
k->put = put;
}
-
EXPORT_SYMBOL_GPL(klist_init);
-
-static void add_head(struct klist * k, struct klist_node * n)
+static void add_head(struct klist *k, struct klist_node *n)
{
spin_lock(&k->k_lock);
list_add(&n->n_node, &k->k_list);
spin_unlock(&k->k_lock);
}
-static void add_tail(struct klist * k, struct klist_node * n)
+static void add_tail(struct klist *k, struct klist_node *n)
{
spin_lock(&k->k_lock);
list_add_tail(&n->n_node, &k->k_list);
spin_unlock(&k->k_lock);
}
-
-static void klist_node_init(struct klist * k, struct klist_node * n)
+static void klist_node_init(struct klist *k, struct klist_node *n)
{
INIT_LIST_HEAD(&n->n_node);
init_completion(&n->n_removed);
@@ -89,60 +84,83 @@
k->get(n);
}
-
/**
- * klist_add_head - Initialize a klist_node and add it to front.
- * @n: node we're adding.
- * @k: klist it's going on.
+ * klist_add_head - Initialize a klist_node and add it to front.
+ * @n: node we're adding.
+ * @k: klist it's going on.
*/
-
-void klist_add_head(struct klist_node * n, struct klist * k)
+void klist_add_head(struct klist_node *n, struct klist *k)
{
klist_node_init(k, n);
add_head(k, n);
}
-
EXPORT_SYMBOL_GPL(klist_add_head);
-
/**
- * klist_add_tail - Initialize a klist_node and add it to back.
- * @n: node we're adding.
- * @k: klist it's going on.
+ * klist_add_tail - Initialize a klist_node and add it to back.
+ * @n: node we're adding.
+ * @k: klist it's going on.
*/
-
-void klist_add_tail(struct klist_node * n, struct klist * k)
+void klist_add_tail(struct klist_node *n, struct klist *k)
{
klist_node_init(k, n);
add_tail(k, n);
}
-
EXPORT_SYMBOL_GPL(klist_add_tail);
-
-static void klist_release(struct kref * kref)
+/**
+ * klist_add_after - Init a klist_node and add it after an existing node
+ * @n: node we're adding.
+ * @pos: node to put @n after
+ */
+void klist_add_after(struct klist_node *n, struct klist_node *pos)
{
- struct klist_node * n = container_of(kref, struct klist_node, n_ref);
+ struct klist *k = pos->n_klist;
+
+ klist_node_init(k, n);
+ spin_lock(&k->k_lock);
+ list_add(&n->n_node, &pos->n_node);
+ spin_unlock(&k->k_lock);
+}
+EXPORT_SYMBOL_GPL(klist_add_after);
+
+/**
+ * klist_add_before - Init a klist_node and add it before an existing node
+ * @n: node we're adding.
+ * @pos: node to put @n after
+ */
+void klist_add_before(struct klist_node *n, struct klist_node *pos)
+{
+ struct klist *k = pos->n_klist;
+
+ klist_node_init(k, n);
+ spin_lock(&k->k_lock);
+ list_add_tail(&n->n_node, &pos->n_node);
+ spin_unlock(&k->k_lock);
+}
+EXPORT_SYMBOL_GPL(klist_add_before);
+
+static void klist_release(struct kref *kref)
+{
+ struct klist_node *n = container_of(kref, struct klist_node, n_ref);
list_del(&n->n_node);
complete(&n->n_removed);
n->n_klist = NULL;
}
-static int klist_dec_and_del(struct klist_node * n)
+static int klist_dec_and_del(struct klist_node *n)
{
return kref_put(&n->n_ref, klist_release);
}
-
/**
- * klist_del - Decrement the reference count of node and try to remove.
- * @n: node we're deleting.
+ * klist_del - Decrement the reference count of node and try to remove.
+ * @n: node we're deleting.
*/
-
-void klist_del(struct klist_node * n)
+void klist_del(struct klist_node *n)
{
- struct klist * k = n->n_klist;
+ struct klist *k = n->n_klist;
void (*put)(struct klist_node *) = k->put;
spin_lock(&k->k_lock);
@@ -152,48 +170,40 @@
if (put)
put(n);
}
-
EXPORT_SYMBOL_GPL(klist_del);
-
/**
- * klist_remove - Decrement the refcount of node and wait for it to go away.
- * @n: node we're removing.
+ * klist_remove - Decrement the refcount of node and wait for it to go away.
+ * @n: node we're removing.
*/
-
-void klist_remove(struct klist_node * n)
+void klist_remove(struct klist_node *n)
{
klist_del(n);
wait_for_completion(&n->n_removed);
}
-
EXPORT_SYMBOL_GPL(klist_remove);
-
/**
- * klist_node_attached - Say whether a node is bound to a list or not.
- * @n: Node that we're testing.
+ * klist_node_attached - Say whether a node is bound to a list or not.
+ * @n: Node that we're testing.
*/
-
-int klist_node_attached(struct klist_node * n)
+int klist_node_attached(struct klist_node *n)
{
return (n->n_klist != NULL);
}
-
EXPORT_SYMBOL_GPL(klist_node_attached);
-
/**
- * klist_iter_init_node - Initialize a klist_iter structure.
- * @k: klist we're iterating.
- * @i: klist_iter we're filling.
- * @n: node to start with.
+ * klist_iter_init_node - Initialize a klist_iter structure.
+ * @k: klist we're iterating.
+ * @i: klist_iter we're filling.
+ * @n: node to start with.
*
- * Similar to klist_iter_init(), but starts the action off with @n,
- * instead of with the list head.
+ * Similar to klist_iter_init(), but starts the action off with @n,
+ * instead of with the list head.
*/
-
-void klist_iter_init_node(struct klist * k, struct klist_iter * i, struct klist_node * n)
+void klist_iter_init_node(struct klist *k, struct klist_iter *i,
+ struct klist_node *n)
{
i->i_klist = k;
i->i_head = &k->k_list;
@@ -201,66 +211,56 @@
if (n)
kref_get(&n->n_ref);
}
-
EXPORT_SYMBOL_GPL(klist_iter_init_node);
-
/**
- * klist_iter_init - Iniitalize a klist_iter structure.
- * @k: klist we're iterating.
- * @i: klist_iter structure we're filling.
+ * klist_iter_init - Iniitalize a klist_iter structure.
+ * @k: klist we're iterating.
+ * @i: klist_iter structure we're filling.
*
- * Similar to klist_iter_init_node(), but start with the list head.
+ * Similar to klist_iter_init_node(), but start with the list head.
*/
-
-void klist_iter_init(struct klist * k, struct klist_iter * i)
+void klist_iter_init(struct klist *k, struct klist_iter *i)
{
klist_iter_init_node(k, i, NULL);
}
-
EXPORT_SYMBOL_GPL(klist_iter_init);
-
/**
- * klist_iter_exit - Finish a list iteration.
- * @i: Iterator structure.
+ * klist_iter_exit - Finish a list iteration.
+ * @i: Iterator structure.
*
- * Must be called when done iterating over list, as it decrements the
- * refcount of the current node. Necessary in case iteration exited before
- * the end of the list was reached, and always good form.
+ * Must be called when done iterating over list, as it decrements the
+ * refcount of the current node. Necessary in case iteration exited before
+ * the end of the list was reached, and always good form.
*/
-
-void klist_iter_exit(struct klist_iter * i)
+void klist_iter_exit(struct klist_iter *i)
{
if (i->i_cur) {
klist_del(i->i_cur);
i->i_cur = NULL;
}
}
-
EXPORT_SYMBOL_GPL(klist_iter_exit);
-
-static struct klist_node * to_klist_node(struct list_head * n)
+static struct klist_node *to_klist_node(struct list_head *n)
{
return container_of(n, struct klist_node, n_node);
}
-
/**
- * klist_next - Ante up next node in list.
- * @i: Iterator structure.
+ * klist_next - Ante up next node in list.
+ * @i: Iterator structure.
*
- * First grab list lock. Decrement the reference count of the previous
- * node, if there was one. Grab the next node, increment its reference
- * count, drop the lock, and return that next node.
+ * First grab list lock. Decrement the reference count of the previous
+ * node, if there was one. Grab the next node, increment its reference
+ * count, drop the lock, and return that next node.
*/
-
-struct klist_node * klist_next(struct klist_iter * i)
+struct klist_node *klist_next(struct klist_iter *i)
{
- struct list_head * next;
- struct klist_node * lnode = i->i_cur;
- struct klist_node * knode = NULL;
+ struct list_head *next;
+ struct klist_node *lnode = i->i_cur;
+ struct klist_node *knode = NULL;
void (*put)(struct klist_node *) = i->i_klist->put;
spin_lock(&i->i_klist->k_lock);
@@ -281,7 +281,4 @@
put(lnode);
return knode;
}
-
EXPORT_SYMBOL_GPL(klist_next);
-
-
diff --git a/lib/kobject.c b/lib/kobject.c
index 2c64903..718e510 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -90,7 +90,7 @@
}
pr_debug("kobject: '%s' (%p): %s: path = '%s'\n", kobject_name(kobj),
- kobj, __FUNCTION__, path);
+ kobj, __func__, path);
}
/**
@@ -181,7 +181,7 @@
}
pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n",
- kobject_name(kobj), kobj, __FUNCTION__,
+ kobject_name(kobj), kobj, __func__,
parent ? kobject_name(parent) : "<NULL>",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
@@ -196,10 +196,10 @@
printk(KERN_ERR "%s failed for %s with "
"-EEXIST, don't try to register things with "
"the same name in the same directory.\n",
- __FUNCTION__, kobject_name(kobj));
+ __func__, kobject_name(kobj));
else
printk(KERN_ERR "%s failed for %s (%d)\n",
- __FUNCTION__, kobject_name(kobj), error);
+ __func__, kobject_name(kobj), error);
dump_stack();
} else
kobj->state_in_sysfs = 1;
@@ -216,21 +216,12 @@
static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
va_list vargs)
{
- va_list aq;
- char *name;
-
- va_copy(aq, vargs);
- name = kvasprintf(GFP_KERNEL, fmt, vargs);
- va_end(aq);
-
- if (!name)
- return -ENOMEM;
-
/* Free the old name, if necessary. */
kfree(kobj->name);
- /* Now, set the new name */
- kobj->name = name;
+ kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs);
+ if (!kobj->name)
+ return -ENOMEM;
return 0;
}
@@ -246,12 +237,12 @@
*/
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
{
- va_list args;
+ va_list vargs;
int retval;
- va_start(args, fmt);
- retval = kobject_set_name_vargs(kobj, fmt, args);
- va_end(args);
+ va_start(vargs, fmt);
+ retval = kobject_set_name_vargs(kobj, fmt, vargs);
+ va_end(vargs);
return retval;
}
@@ -301,12 +292,9 @@
static int kobject_add_varg(struct kobject *kobj, struct kobject *parent,
const char *fmt, va_list vargs)
{
- va_list aq;
int retval;
- va_copy(aq, vargs);
- retval = kobject_set_name_vargs(kobj, fmt, aq);
- va_end(aq);
+ retval = kobject_set_name_vargs(kobj, fmt, vargs);
if (retval) {
printk(KERN_ERR "kobject: can not set name properly!\n");
return retval;
@@ -540,7 +528,7 @@
const char *name = kobj->name;
pr_debug("kobject: '%s' (%p): %s\n",
- kobject_name(kobj), kobj, __FUNCTION__);
+ kobject_name(kobj), kobj, __func__);
if (t && !t->release)
pr_debug("kobject: '%s' (%p): does not have a release() "
@@ -600,7 +588,7 @@
static void dynamic_kobj_release(struct kobject *kobj)
{
- pr_debug("kobject: (%p): %s\n", kobj, __FUNCTION__);
+ pr_debug("kobject: (%p): %s\n", kobj, __func__);
kfree(kobj);
}
@@ -657,7 +645,7 @@
retval = kobject_add(kobj, parent, "%s", name);
if (retval) {
printk(KERN_WARNING "%s: kobject_add error: %d\n",
- __FUNCTION__, retval);
+ __func__, retval);
kobject_put(kobj);
kobj = NULL;
}
@@ -765,7 +753,7 @@
{
struct kset *kset = container_of(kobj, struct kset, kobj);
pr_debug("kobject: '%s' (%p): %s\n",
- kobject_name(kobj), kobj, __FUNCTION__);
+ kobject_name(kobj), kobj, __func__);
kfree(kset);
}
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 9fb6b86..2fa545a 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -101,7 +101,7 @@
int retval = 0;
pr_debug("kobject: '%s' (%p): %s\n",
- kobject_name(kobj), kobj, __FUNCTION__);
+ kobject_name(kobj), kobj, __func__);
/* search the kset we belong to */
top_kobj = kobj;
@@ -111,7 +111,7 @@
if (!top_kobj->kset) {
pr_debug("kobject: '%s' (%p): %s: attempted to send uevent "
"without kset!\n", kobject_name(kobj), kobj,
- __FUNCTION__);
+ __func__);
return -EINVAL;
}
@@ -123,7 +123,7 @@
if (!uevent_ops->filter(kset, kobj)) {
pr_debug("kobject: '%s' (%p): %s: filter function "
"caused the event to drop!\n",
- kobject_name(kobj), kobj, __FUNCTION__);
+ kobject_name(kobj), kobj, __func__);
return 0;
}
@@ -135,7 +135,7 @@
if (!subsystem) {
pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the "
"event to drop!\n", kobject_name(kobj), kobj,
- __FUNCTION__);
+ __func__);
return 0;
}
@@ -177,7 +177,7 @@
if (retval) {
pr_debug("kobject: '%s' (%p): %s: uevent() returned "
"%d\n", kobject_name(kobj), kobj,
- __FUNCTION__, retval);
+ __func__, retval);
goto exit;
}
}
diff --git a/lib/percpu_counter.c b/lib/percpu_counter.c
index 393a0e9..1191744 100644
--- a/lib/percpu_counter.c
+++ b/lib/percpu_counter.c
@@ -102,6 +102,7 @@
return;
free_percpu(fbc->counters);
+ fbc->counters = NULL;
#ifdef CONFIG_HOTPLUG_CPU
mutex_lock(&percpu_counters_lock);
list_del(&fbc->list);
diff --git a/lib/proportions.c b/lib/proportions.c
index 9508d9a..4f387a6 100644
--- a/lib/proportions.c
+++ b/lib/proportions.c
@@ -73,12 +73,6 @@
#include <linux/proportions.h>
#include <linux/rcupdate.h>
-/*
- * Limit the time part in order to ensure there are some bits left for the
- * cycle counter.
- */
-#define PROP_MAX_SHIFT (3*BITS_PER_LONG/4)
-
int prop_descriptor_init(struct prop_descriptor *pd, int shift)
{
int err;
@@ -268,6 +262,38 @@
}
/*
+ * identical to __prop_inc_percpu, except that it limits this pl's fraction to
+ * @frac/PROP_FRAC_BASE by ignoring events when this limit has been exceeded.
+ */
+void __prop_inc_percpu_max(struct prop_descriptor *pd,
+ struct prop_local_percpu *pl, long frac)
+{
+ struct prop_global *pg = prop_get_global(pd);
+
+ prop_norm_percpu(pg, pl);
+
+ if (unlikely(frac != PROP_FRAC_BASE)) {
+ unsigned long period_2 = 1UL << (pg->shift - 1);
+ unsigned long counter_mask = period_2 - 1;
+ unsigned long global_count;
+ long numerator, denominator;
+
+ numerator = percpu_counter_read_positive(&pl->events);
+ global_count = percpu_counter_read(&pg->events);
+ denominator = period_2 + (global_count & counter_mask);
+
+ if (numerator > ((denominator * frac) >> PROP_FRAC_SHIFT))
+ goto out_put;
+ }
+
+ percpu_counter_add(&pl->events, 1);
+ percpu_counter_add(&pg->events, 1);
+
+out_put:
+ prop_put_global(pd, pg);
+}
+
+/*
* Obtain a fraction of this proportion
*
* p_{j} = x_{j} / (period/2 + t % period/2)
diff --git a/lib/ratelimit.c b/lib/ratelimit.c
new file mode 100644
index 0000000..485e304
--- /dev/null
+++ b/lib/ratelimit.c
@@ -0,0 +1,51 @@
+/*
+ * ratelimit.c - Do something with rate limit.
+ *
+ * Isolated from kernel/printk.c by Dave Young <hidave.darkstar@gmail.com>
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+
+/*
+ * __ratelimit - rate limiting
+ * @ratelimit_jiffies: minimum time in jiffies between two callbacks
+ * @ratelimit_burst: number of callbacks we do before ratelimiting
+ *
+ * This enforces a rate limit: not more than @ratelimit_burst callbacks
+ * in every ratelimit_jiffies
+ */
+int __ratelimit(int ratelimit_jiffies, int ratelimit_burst)
+{
+ static DEFINE_SPINLOCK(ratelimit_lock);
+ static unsigned toks = 10 * 5 * HZ;
+ static unsigned long last_msg;
+ static int missed;
+ unsigned long flags;
+ unsigned long now = jiffies;
+
+ spin_lock_irqsave(&ratelimit_lock, flags);
+ toks += now - last_msg;
+ last_msg = now;
+ if (toks > (ratelimit_burst * ratelimit_jiffies))
+ toks = ratelimit_burst * ratelimit_jiffies;
+ if (toks >= ratelimit_jiffies) {
+ int lost = missed;
+
+ missed = 0;
+ toks -= ratelimit_jiffies;
+ spin_unlock_irqrestore(&ratelimit_lock, flags);
+ if (lost)
+ printk(KERN_WARNING "%s: %d messages suppressed\n",
+ __func__, lost);
+ return 1;
+ }
+ missed++;
+ spin_unlock_irqrestore(&ratelimit_lock, flags);
+ return 0;
+}
+EXPORT_SYMBOL(__ratelimit);
diff --git a/lib/string.c b/lib/string.c
index 5efafed..b19b87a 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -493,6 +493,33 @@
EXPORT_SYMBOL(strsep);
#endif
+/**
+ * sysfs_streq - return true if strings are equal, modulo trailing newline
+ * @s1: one string
+ * @s2: another string
+ *
+ * This routine returns true iff two strings are equal, treating both
+ * NUL and newline-then-NUL as equivalent string terminations. It's
+ * geared for use with sysfs input strings, which generally terminate
+ * with newlines but are compared against values without newlines.
+ */
+bool sysfs_streq(const char *s1, const char *s2)
+{
+ while (*s1 && *s1 == *s2) {
+ s1++;
+ s2++;
+ }
+
+ if (*s1 == *s2)
+ return true;
+ if (!*s1 && *s2 == '\n' && !s2[1])
+ return true;
+ if (*s1 == '\n' && !s1[1] && !*s2)
+ return true;
+ return false;
+}
+EXPORT_SYMBOL(sysfs_streq);
+
#ifndef __HAVE_ARCH_MEMSET
/**
* memset - Fill a region of memory with the given value
diff --git a/lib/swiotlb.c b/lib/swiotlb.c
index 0259228..d568894 100644
--- a/lib/swiotlb.c
+++ b/lib/swiotlb.c
@@ -31,6 +31,7 @@
#include <linux/init.h>
#include <linux/bootmem.h>
+#include <linux/iommu-helper.h>
#define OFFSET(val,align) ((unsigned long) \
( (val) & ( (align) - 1)))
@@ -282,15 +283,6 @@
return (addr & ~mask) != 0;
}
-static inline unsigned int is_span_boundary(unsigned int index,
- unsigned int nslots,
- unsigned long offset_slots,
- unsigned long max_slots)
-{
- unsigned long offset = (offset_slots + index) & (max_slots - 1);
- return offset + nslots > max_slots;
-}
-
/*
* Allocates bounce buffer and returns its kernel virtual address.
*/
@@ -331,56 +323,53 @@
* request and allocate a buffer from that IO TLB pool.
*/
spin_lock_irqsave(&io_tlb_lock, flags);
- {
- index = ALIGN(io_tlb_index, stride);
- if (index >= io_tlb_nslabs)
- index = 0;
- wrap = index;
+ index = ALIGN(io_tlb_index, stride);
+ if (index >= io_tlb_nslabs)
+ index = 0;
+ wrap = index;
- do {
- while (is_span_boundary(index, nslots, offset_slots,
- max_slots)) {
- index += stride;
- if (index >= io_tlb_nslabs)
- index = 0;
- if (index == wrap)
- goto not_found;
- }
-
- /*
- * If we find a slot that indicates we have 'nslots'
- * number of contiguous buffers, we allocate the
- * buffers from that slot and mark the entries as '0'
- * indicating unavailable.
- */
- if (io_tlb_list[index] >= nslots) {
- int count = 0;
-
- for (i = index; i < (int) (index + nslots); i++)
- io_tlb_list[i] = 0;
- for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) && io_tlb_list[i]; i--)
- io_tlb_list[i] = ++count;
- dma_addr = io_tlb_start + (index << IO_TLB_SHIFT);
-
- /*
- * Update the indices to avoid searching in
- * the next round.
- */
- io_tlb_index = ((index + nslots) < io_tlb_nslabs
- ? (index + nslots) : 0);
-
- goto found;
- }
+ do {
+ while (iommu_is_span_boundary(index, nslots, offset_slots,
+ max_slots)) {
index += stride;
if (index >= io_tlb_nslabs)
index = 0;
- } while (index != wrap);
+ if (index == wrap)
+ goto not_found;
+ }
- not_found:
- spin_unlock_irqrestore(&io_tlb_lock, flags);
- return NULL;
- }
- found:
+ /*
+ * If we find a slot that indicates we have 'nslots' number of
+ * contiguous buffers, we allocate the buffers from that slot
+ * and mark the entries as '0' indicating unavailable.
+ */
+ if (io_tlb_list[index] >= nslots) {
+ int count = 0;
+
+ for (i = index; i < (int) (index + nslots); i++)
+ io_tlb_list[i] = 0;
+ for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE - 1) && io_tlb_list[i]; i--)
+ io_tlb_list[i] = ++count;
+ dma_addr = io_tlb_start + (index << IO_TLB_SHIFT);
+
+ /*
+ * Update the indices to avoid searching in the next
+ * round.
+ */
+ io_tlb_index = ((index + nslots) < io_tlb_nslabs
+ ? (index + nslots) : 0);
+
+ goto found;
+ }
+ index += stride;
+ if (index >= io_tlb_nslabs)
+ index = 0;
+ } while (index != wrap);
+
+not_found:
+ spin_unlock_irqrestore(&io_tlb_lock, flags);
+ return NULL;
+found:
spin_unlock_irqrestore(&io_tlb_lock, flags);
/*
@@ -566,7 +555,8 @@
* either swiotlb_unmap_single or swiotlb_dma_sync_single is performed.
*/
dma_addr_t
-swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
+swiotlb_map_single_attrs(struct device *hwdev, void *ptr, size_t size,
+ int dir, struct dma_attrs *attrs)
{
dma_addr_t dev_addr = virt_to_bus(ptr);
void *map;
@@ -599,6 +589,13 @@
return dev_addr;
}
+EXPORT_SYMBOL(swiotlb_map_single_attrs);
+
+dma_addr_t
+swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
+{
+ return swiotlb_map_single_attrs(hwdev, ptr, size, dir, NULL);
+}
/*
* Unmap a single streaming mode DMA translation. The dma_addr and size must
@@ -609,8 +606,8 @@
* whatever the device wrote there.
*/
void
-swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size,
- int dir)
+swiotlb_unmap_single_attrs(struct device *hwdev, dma_addr_t dev_addr,
+ size_t size, int dir, struct dma_attrs *attrs)
{
char *dma_addr = bus_to_virt(dev_addr);
@@ -620,7 +617,14 @@
else if (dir == DMA_FROM_DEVICE)
dma_mark_clean(dma_addr, size);
}
+EXPORT_SYMBOL(swiotlb_unmap_single_attrs);
+void
+swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size,
+ int dir)
+{
+ return swiotlb_unmap_single_attrs(hwdev, dev_addr, size, dir, NULL);
+}
/*
* Make physical memory consistent for a single streaming mode DMA translation
* after a transfer.
@@ -691,6 +695,8 @@
SYNC_FOR_DEVICE);
}
+void swiotlb_unmap_sg_attrs(struct device *, struct scatterlist *, int, int,
+ struct dma_attrs *);
/*
* Map a set of buffers described by scatterlist in streaming mode for DMA.
* This is the scatter-gather version of the above swiotlb_map_single
@@ -708,8 +714,8 @@
* same here.
*/
int
-swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
- int dir)
+swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems,
+ int dir, struct dma_attrs *attrs)
{
struct scatterlist *sg;
void *addr;
@@ -727,7 +733,8 @@
/* Don't panic here, we expect map_sg users
to do proper error handling. */
swiotlb_full(hwdev, sg->length, dir, 0);
- swiotlb_unmap_sg(hwdev, sgl, i, dir);
+ swiotlb_unmap_sg_attrs(hwdev, sgl, i, dir,
+ attrs);
sgl[0].dma_length = 0;
return 0;
}
@@ -738,14 +745,22 @@
}
return nelems;
}
+EXPORT_SYMBOL(swiotlb_map_sg_attrs);
+
+int
+swiotlb_map_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
+ int dir)
+{
+ return swiotlb_map_sg_attrs(hwdev, sgl, nelems, dir, NULL);
+}
/*
* Unmap a set of streaming mode DMA translations. Again, cpu read rules
* concerning calls here are the same as for swiotlb_unmap_single() above.
*/
void
-swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
- int dir)
+swiotlb_unmap_sg_attrs(struct device *hwdev, struct scatterlist *sgl,
+ int nelems, int dir, struct dma_attrs *attrs)
{
struct scatterlist *sg;
int i;
@@ -760,6 +775,14 @@
dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
}
}
+EXPORT_SYMBOL(swiotlb_unmap_sg_attrs);
+
+void
+swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sgl, int nelems,
+ int dir)
+{
+ return swiotlb_unmap_sg_attrs(hwdev, sgl, nelems, dir, NULL);
+}
/*
* Make physical memory consistent for a set of streaming mode DMA translations
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
index e8644b1..7c4f9e0 100644
--- a/mm/backing-dev.c
+++ b/mm/backing-dev.c
@@ -4,12 +4,229 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/module.h>
+#include <linux/writeback.h>
+#include <linux/device.h>
+
+
+static struct class *bdi_class;
+
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static struct dentry *bdi_debug_root;
+
+static void bdi_debug_init(void)
+{
+ bdi_debug_root = debugfs_create_dir("bdi", NULL);
+}
+
+static int bdi_debug_stats_show(struct seq_file *m, void *v)
+{
+ struct backing_dev_info *bdi = m->private;
+ long background_thresh;
+ long dirty_thresh;
+ long bdi_thresh;
+
+ get_dirty_limits(&background_thresh, &dirty_thresh, &bdi_thresh, bdi);
+
+#define K(x) ((x) << (PAGE_SHIFT - 10))
+ seq_printf(m,
+ "BdiWriteback: %8lu kB\n"
+ "BdiReclaimable: %8lu kB\n"
+ "BdiDirtyThresh: %8lu kB\n"
+ "DirtyThresh: %8lu kB\n"
+ "BackgroundThresh: %8lu kB\n",
+ (unsigned long) K(bdi_stat(bdi, BDI_WRITEBACK)),
+ (unsigned long) K(bdi_stat(bdi, BDI_RECLAIMABLE)),
+ K(bdi_thresh),
+ K(dirty_thresh),
+ K(background_thresh));
+#undef K
+
+ return 0;
+}
+
+static int bdi_debug_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, bdi_debug_stats_show, inode->i_private);
+}
+
+static const struct file_operations bdi_debug_stats_fops = {
+ .open = bdi_debug_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void bdi_debug_register(struct backing_dev_info *bdi, const char *name)
+{
+ bdi->debug_dir = debugfs_create_dir(name, bdi_debug_root);
+ bdi->debug_stats = debugfs_create_file("stats", 0444, bdi->debug_dir,
+ bdi, &bdi_debug_stats_fops);
+}
+
+static void bdi_debug_unregister(struct backing_dev_info *bdi)
+{
+ debugfs_remove(bdi->debug_stats);
+ debugfs_remove(bdi->debug_dir);
+}
+#else
+static inline void bdi_debug_init(void)
+{
+}
+static inline void bdi_debug_register(struct backing_dev_info *bdi,
+ const char *name)
+{
+}
+static inline void bdi_debug_unregister(struct backing_dev_info *bdi)
+{
+}
+#endif
+
+static ssize_t read_ahead_kb_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct backing_dev_info *bdi = dev_get_drvdata(dev);
+ char *end;
+ unsigned long read_ahead_kb;
+ ssize_t ret = -EINVAL;
+
+ read_ahead_kb = simple_strtoul(buf, &end, 10);
+ if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) {
+ bdi->ra_pages = read_ahead_kb >> (PAGE_SHIFT - 10);
+ ret = count;
+ }
+ return ret;
+}
+
+#define K(pages) ((pages) << (PAGE_SHIFT - 10))
+
+#define BDI_SHOW(name, expr) \
+static ssize_t name##_show(struct device *dev, \
+ struct device_attribute *attr, char *page) \
+{ \
+ struct backing_dev_info *bdi = dev_get_drvdata(dev); \
+ \
+ return snprintf(page, PAGE_SIZE-1, "%lld\n", (long long)expr); \
+}
+
+BDI_SHOW(read_ahead_kb, K(bdi->ra_pages))
+
+static ssize_t min_ratio_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct backing_dev_info *bdi = dev_get_drvdata(dev);
+ char *end;
+ unsigned int ratio;
+ ssize_t ret = -EINVAL;
+
+ ratio = simple_strtoul(buf, &end, 10);
+ if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) {
+ ret = bdi_set_min_ratio(bdi, ratio);
+ if (!ret)
+ ret = count;
+ }
+ return ret;
+}
+BDI_SHOW(min_ratio, bdi->min_ratio)
+
+static ssize_t max_ratio_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct backing_dev_info *bdi = dev_get_drvdata(dev);
+ char *end;
+ unsigned int ratio;
+ ssize_t ret = -EINVAL;
+
+ ratio = simple_strtoul(buf, &end, 10);
+ if (*buf && (end[0] == '\0' || (end[0] == '\n' && end[1] == '\0'))) {
+ ret = bdi_set_max_ratio(bdi, ratio);
+ if (!ret)
+ ret = count;
+ }
+ return ret;
+}
+BDI_SHOW(max_ratio, bdi->max_ratio)
+
+#define __ATTR_RW(attr) __ATTR(attr, 0644, attr##_show, attr##_store)
+
+static struct device_attribute bdi_dev_attrs[] = {
+ __ATTR_RW(read_ahead_kb),
+ __ATTR_RW(min_ratio),
+ __ATTR_RW(max_ratio),
+ __ATTR_NULL,
+};
+
+static __init int bdi_class_init(void)
+{
+ bdi_class = class_create(THIS_MODULE, "bdi");
+ bdi_class->dev_attrs = bdi_dev_attrs;
+ bdi_debug_init();
+ return 0;
+}
+
+postcore_initcall(bdi_class_init);
+
+int bdi_register(struct backing_dev_info *bdi, struct device *parent,
+ const char *fmt, ...)
+{
+ char *name;
+ va_list args;
+ int ret = 0;
+ struct device *dev;
+
+ va_start(args, fmt);
+ name = kvasprintf(GFP_KERNEL, fmt, args);
+ va_end(args);
+
+ if (!name)
+ return -ENOMEM;
+
+ dev = device_create(bdi_class, parent, MKDEV(0, 0), name);
+ if (IS_ERR(dev)) {
+ ret = PTR_ERR(dev);
+ goto exit;
+ }
+
+ bdi->dev = dev;
+ dev_set_drvdata(bdi->dev, bdi);
+ bdi_debug_register(bdi, name);
+
+exit:
+ kfree(name);
+ return ret;
+}
+EXPORT_SYMBOL(bdi_register);
+
+int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev)
+{
+ return bdi_register(bdi, NULL, "%u:%u", MAJOR(dev), MINOR(dev));
+}
+EXPORT_SYMBOL(bdi_register_dev);
+
+void bdi_unregister(struct backing_dev_info *bdi)
+{
+ if (bdi->dev) {
+ bdi_debug_unregister(bdi);
+ device_unregister(bdi->dev);
+ bdi->dev = NULL;
+ }
+}
+EXPORT_SYMBOL(bdi_unregister);
int bdi_init(struct backing_dev_info *bdi)
{
int i;
int err;
+ bdi->dev = NULL;
+
+ bdi->min_ratio = 0;
+ bdi->max_ratio = 100;
+ bdi->max_prop_frac = PROP_FRAC_BASE;
+
for (i = 0; i < NR_BDI_STAT_ITEMS; i++) {
err = percpu_counter_init_irq(&bdi->bdi_stat[i], 0);
if (err)
@@ -33,6 +250,8 @@
{
int i;
+ bdi_unregister(bdi);
+
for (i = 0; i < NR_BDI_STAT_ITEMS; i++)
percpu_counter_destroy(&bdi->bdi_stat[i]);
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 2c37c67..bbf953e 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -199,7 +199,8 @@
struct page *page;
page = alloc_pages_node(nid,
- htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE|__GFP_NOWARN,
+ htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE|
+ __GFP_REPEAT|__GFP_NOWARN,
HUGETLB_PAGE_ORDER);
if (page) {
if (arch_prepare_hugepage(page)) {
@@ -294,7 +295,8 @@
}
spin_unlock(&hugetlb_lock);
- page = alloc_pages(htlb_alloc_mask|__GFP_COMP|__GFP_NOWARN,
+ page = alloc_pages(htlb_alloc_mask|__GFP_COMP|
+ __GFP_REPEAT|__GFP_NOWARN,
HUGETLB_PAGE_ORDER);
spin_lock(&hugetlb_lock);
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 2e0bfc9..e46451e 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -26,15 +26,18 @@
#include <linux/backing-dev.h>
#include <linux/bit_spinlock.h>
#include <linux/rcupdate.h>
+#include <linux/slab.h>
#include <linux/swap.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <linux/seq_file.h>
+#include <linux/vmalloc.h>
#include <asm/uaccess.h>
struct cgroup_subsys mem_cgroup_subsys;
static const int MEM_CGROUP_RECLAIM_RETRIES = 5;
+static struct kmem_cache *page_cgroup_cache;
/*
* Statistics for memory cgroup.
@@ -45,6 +48,8 @@
*/
MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */
MEM_CGROUP_STAT_RSS, /* # of pages charged as rss */
+ MEM_CGROUP_STAT_PGPGIN_COUNT, /* # of pages paged in */
+ MEM_CGROUP_STAT_PGPGOUT_COUNT, /* # of pages paged out */
MEM_CGROUP_STAT_NSTATS,
};
@@ -196,6 +201,13 @@
__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_CACHE, val);
else
__mem_cgroup_stat_add_safe(stat, MEM_CGROUP_STAT_RSS, val);
+
+ if (charge)
+ __mem_cgroup_stat_add_safe(stat,
+ MEM_CGROUP_STAT_PGPGIN_COUNT, 1);
+ else
+ __mem_cgroup_stat_add_safe(stat,
+ MEM_CGROUP_STAT_PGPGOUT_COUNT, 1);
}
static struct mem_cgroup_per_zone *
@@ -236,26 +248,12 @@
css);
}
-static struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
+struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
{
return container_of(task_subsys_state(p, mem_cgroup_subsys_id),
struct mem_cgroup, css);
}
-void mm_init_cgroup(struct mm_struct *mm, struct task_struct *p)
-{
- struct mem_cgroup *mem;
-
- mem = mem_cgroup_from_task(p);
- css_get(&mem->css);
- mm->mem_cgroup = mem;
-}
-
-void mm_free_cgroup(struct mm_struct *mm)
-{
- css_put(&mm->mem_cgroup->css);
-}
-
static inline int page_cgroup_locked(struct page *page)
{
return bit_spin_is_locked(PAGE_CGROUP_LOCK_BIT, &page->page_cgroup);
@@ -287,10 +285,10 @@
bit_spin_unlock(PAGE_CGROUP_LOCK_BIT, &page->page_cgroup);
}
-static void __mem_cgroup_remove_list(struct page_cgroup *pc)
+static void __mem_cgroup_remove_list(struct mem_cgroup_per_zone *mz,
+ struct page_cgroup *pc)
{
int from = pc->flags & PAGE_CGROUP_FLAG_ACTIVE;
- struct mem_cgroup_per_zone *mz = page_cgroup_zoneinfo(pc);
if (from)
MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_ACTIVE) -= 1;
@@ -301,10 +299,10 @@
list_del_init(&pc->lru);
}
-static void __mem_cgroup_add_list(struct page_cgroup *pc)
+static void __mem_cgroup_add_list(struct mem_cgroup_per_zone *mz,
+ struct page_cgroup *pc)
{
int to = pc->flags & PAGE_CGROUP_FLAG_ACTIVE;
- struct mem_cgroup_per_zone *mz = page_cgroup_zoneinfo(pc);
if (!to) {
MEM_CGROUP_ZSTAT(mz, MEM_CGROUP_ZSTAT_INACTIVE) += 1;
@@ -476,6 +474,7 @@
int zid = zone_idx(z);
struct mem_cgroup_per_zone *mz;
+ BUG_ON(!mem_cont);
mz = mem_cgroup_zoneinfo(mem_cont, nid, zid);
if (active)
src = &mz->active_list;
@@ -560,7 +559,7 @@
}
unlock_page_cgroup(page);
- pc = kzalloc(sizeof(struct page_cgroup), gfp_mask);
+ pc = kmem_cache_zalloc(page_cgroup_cache, gfp_mask);
if (pc == NULL)
goto err;
@@ -574,7 +573,7 @@
mm = &init_mm;
rcu_read_lock();
- mem = rcu_dereference(mm->mem_cgroup);
+ mem = mem_cgroup_from_task(rcu_dereference(mm->owner));
/*
* For every charge from the cgroup, increment reference count
*/
@@ -602,7 +601,6 @@
mem_cgroup_out_of_memory(mem, gfp_mask);
goto out;
}
- congestion_wait(WRITE, HZ/10);
}
pc->ref_cnt = 1;
@@ -610,7 +608,7 @@
pc->page = page;
pc->flags = PAGE_CGROUP_FLAG_ACTIVE;
if (ctype == MEM_CGROUP_CHARGE_TYPE_CACHE)
- pc->flags |= PAGE_CGROUP_FLAG_CACHE;
+ pc->flags = PAGE_CGROUP_FLAG_CACHE;
lock_page_cgroup(page);
if (page_get_page_cgroup(page)) {
@@ -622,14 +620,14 @@
*/
res_counter_uncharge(&mem->res, PAGE_SIZE);
css_put(&mem->css);
- kfree(pc);
+ kmem_cache_free(page_cgroup_cache, pc);
goto retry;
}
page_assign_page_cgroup(page, pc);
mz = page_cgroup_zoneinfo(pc);
spin_lock_irqsave(&mz->lru_lock, flags);
- __mem_cgroup_add_list(pc);
+ __mem_cgroup_add_list(mz, pc);
spin_unlock_irqrestore(&mz->lru_lock, flags);
unlock_page_cgroup(page);
@@ -637,7 +635,7 @@
return 0;
out:
css_put(&mem->css);
- kfree(pc);
+ kmem_cache_free(page_cgroup_cache, pc);
err:
return -ENOMEM;
}
@@ -685,7 +683,7 @@
if (--(pc->ref_cnt) == 0) {
mz = page_cgroup_zoneinfo(pc);
spin_lock_irqsave(&mz->lru_lock, flags);
- __mem_cgroup_remove_list(pc);
+ __mem_cgroup_remove_list(mz, pc);
spin_unlock_irqrestore(&mz->lru_lock, flags);
page_assign_page_cgroup(page, NULL);
@@ -695,7 +693,7 @@
res_counter_uncharge(&mem->res, PAGE_SIZE);
css_put(&mem->css);
- kfree(pc);
+ kmem_cache_free(page_cgroup_cache, pc);
return;
}
@@ -747,7 +745,7 @@
mz = page_cgroup_zoneinfo(pc);
spin_lock_irqsave(&mz->lru_lock, flags);
- __mem_cgroup_remove_list(pc);
+ __mem_cgroup_remove_list(mz, pc);
spin_unlock_irqrestore(&mz->lru_lock, flags);
page_assign_page_cgroup(page, NULL);
@@ -759,7 +757,7 @@
mz = page_cgroup_zoneinfo(pc);
spin_lock_irqsave(&mz->lru_lock, flags);
- __mem_cgroup_add_list(pc);
+ __mem_cgroup_add_list(mz, pc);
spin_unlock_irqrestore(&mz->lru_lock, flags);
unlock_page_cgroup(newpage);
@@ -853,13 +851,10 @@
return 0;
}
-static ssize_t mem_cgroup_read(struct cgroup *cont,
- struct cftype *cft, struct file *file,
- char __user *userbuf, size_t nbytes, loff_t *ppos)
+static u64 mem_cgroup_read(struct cgroup *cont, struct cftype *cft)
{
- return res_counter_read(&mem_cgroup_from_cont(cont)->res,
- cft->private, userbuf, nbytes, ppos,
- NULL);
+ return res_counter_read_u64(&mem_cgroup_from_cont(cont)->res,
+ cft->private);
}
static ssize_t mem_cgroup_write(struct cgroup *cont, struct cftype *cft,
@@ -871,27 +866,25 @@
mem_cgroup_write_strategy);
}
-static ssize_t mem_force_empty_write(struct cgroup *cont,
- struct cftype *cft, struct file *file,
- const char __user *userbuf,
- size_t nbytes, loff_t *ppos)
+static int mem_cgroup_reset(struct cgroup *cont, unsigned int event)
{
- struct mem_cgroup *mem = mem_cgroup_from_cont(cont);
- int ret = mem_cgroup_force_empty(mem);
- if (!ret)
- ret = nbytes;
- return ret;
+ struct mem_cgroup *mem;
+
+ mem = mem_cgroup_from_cont(cont);
+ switch (event) {
+ case RES_MAX_USAGE:
+ res_counter_reset_max(&mem->res);
+ break;
+ case RES_FAILCNT:
+ res_counter_reset_failcnt(&mem->res);
+ break;
+ }
+ return 0;
}
-/*
- * Note: This should be removed if cgroup supports write-only file.
- */
-static ssize_t mem_force_empty_read(struct cgroup *cont,
- struct cftype *cft,
- struct file *file, char __user *userbuf,
- size_t nbytes, loff_t *ppos)
+static int mem_force_empty_write(struct cgroup *cont, unsigned int event)
{
- return -EINVAL;
+ return mem_cgroup_force_empty(mem_cgroup_from_cont(cont));
}
static const struct mem_cgroup_stat_desc {
@@ -900,11 +893,13 @@
} mem_cgroup_stat_desc[] = {
[MEM_CGROUP_STAT_CACHE] = { "cache", PAGE_SIZE, },
[MEM_CGROUP_STAT_RSS] = { "rss", PAGE_SIZE, },
+ [MEM_CGROUP_STAT_PGPGIN_COUNT] = {"pgpgin", 1, },
+ [MEM_CGROUP_STAT_PGPGOUT_COUNT] = {"pgpgout", 1, },
};
-static int mem_control_stat_show(struct seq_file *m, void *arg)
+static int mem_control_stat_show(struct cgroup *cont, struct cftype *cft,
+ struct cgroup_map_cb *cb)
{
- struct cgroup *cont = m->private;
struct mem_cgroup *mem_cont = mem_cgroup_from_cont(cont);
struct mem_cgroup_stat *stat = &mem_cont->stat;
int i;
@@ -914,8 +909,7 @@
val = mem_cgroup_read_stat(stat, i);
val *= mem_cgroup_stat_desc[i].unit;
- seq_printf(m, "%s %lld\n", mem_cgroup_stat_desc[i].msg,
- (long long)val);
+ cb->fill(cb, mem_cgroup_stat_desc[i].msg, val);
}
/* showing # of active pages */
{
@@ -925,52 +919,43 @@
MEM_CGROUP_ZSTAT_INACTIVE);
active = mem_cgroup_get_all_zonestat(mem_cont,
MEM_CGROUP_ZSTAT_ACTIVE);
- seq_printf(m, "active %ld\n", (active) * PAGE_SIZE);
- seq_printf(m, "inactive %ld\n", (inactive) * PAGE_SIZE);
+ cb->fill(cb, "active", (active) * PAGE_SIZE);
+ cb->fill(cb, "inactive", (inactive) * PAGE_SIZE);
}
return 0;
}
-static const struct file_operations mem_control_stat_file_operations = {
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int mem_control_stat_open(struct inode *unused, struct file *file)
-{
- /* XXX __d_cont */
- struct cgroup *cont = file->f_dentry->d_parent->d_fsdata;
-
- file->f_op = &mem_control_stat_file_operations;
- return single_open(file, mem_control_stat_show, cont);
-}
-
static struct cftype mem_cgroup_files[] = {
{
.name = "usage_in_bytes",
.private = RES_USAGE,
- .read = mem_cgroup_read,
+ .read_u64 = mem_cgroup_read,
+ },
+ {
+ .name = "max_usage_in_bytes",
+ .private = RES_MAX_USAGE,
+ .trigger = mem_cgroup_reset,
+ .read_u64 = mem_cgroup_read,
},
{
.name = "limit_in_bytes",
.private = RES_LIMIT,
.write = mem_cgroup_write,
- .read = mem_cgroup_read,
+ .read_u64 = mem_cgroup_read,
},
{
.name = "failcnt",
.private = RES_FAILCNT,
- .read = mem_cgroup_read,
+ .trigger = mem_cgroup_reset,
+ .read_u64 = mem_cgroup_read,
},
{
.name = "force_empty",
- .write = mem_force_empty_write,
- .read = mem_force_empty_read,
+ .trigger = mem_force_empty_write,
},
{
.name = "stat",
- .open = mem_control_stat_open,
+ .read_map = mem_control_stat_show,
},
};
@@ -1010,6 +995,29 @@
kfree(mem->info.nodeinfo[node]);
}
+static struct mem_cgroup *mem_cgroup_alloc(void)
+{
+ struct mem_cgroup *mem;
+
+ if (sizeof(*mem) < PAGE_SIZE)
+ mem = kmalloc(sizeof(*mem), GFP_KERNEL);
+ else
+ mem = vmalloc(sizeof(*mem));
+
+ if (mem)
+ memset(mem, 0, sizeof(*mem));
+ return mem;
+}
+
+static void mem_cgroup_free(struct mem_cgroup *mem)
+{
+ if (sizeof(*mem) < PAGE_SIZE)
+ kfree(mem);
+ else
+ vfree(mem);
+}
+
+
static struct cgroup_subsys_state *
mem_cgroup_create(struct cgroup_subsys *ss, struct cgroup *cont)
{
@@ -1018,17 +1026,15 @@
if (unlikely((cont->parent) == NULL)) {
mem = &init_mem_cgroup;
- init_mm.mem_cgroup = mem;
- } else
- mem = kzalloc(sizeof(struct mem_cgroup), GFP_KERNEL);
-
- if (mem == NULL)
- return ERR_PTR(-ENOMEM);
+ page_cgroup_cache = KMEM_CACHE(page_cgroup, SLAB_PANIC);
+ } else {
+ mem = mem_cgroup_alloc();
+ if (!mem)
+ return ERR_PTR(-ENOMEM);
+ }
res_counter_init(&mem->res);
- memset(&mem->info, 0, sizeof(mem->info));
-
for_each_node_state(node, N_POSSIBLE)
if (alloc_mem_cgroup_per_zone_info(mem, node))
goto free_out;
@@ -1038,7 +1044,7 @@
for_each_node_state(node, N_POSSIBLE)
free_mem_cgroup_per_zone_info(mem, node);
if (cont->parent != NULL)
- kfree(mem);
+ mem_cgroup_free(mem);
return ERR_PTR(-ENOMEM);
}
@@ -1058,7 +1064,7 @@
for_each_node_state(node, N_POSSIBLE)
free_mem_cgroup_per_zone_info(mem, node);
- kfree(mem_cgroup_from_cont(cont));
+ mem_cgroup_free(mem_cgroup_from_cont(cont));
}
static int mem_cgroup_populate(struct cgroup_subsys *ss,
@@ -1098,10 +1104,6 @@
if (!thread_group_leader(p))
goto out;
- css_get(&mem->css);
- rcu_assign_pointer(mm->mem_cgroup, mem);
- css_put(&old_mem->css);
-
out:
mmput(mm);
}
diff --git a/mm/migrate.c b/mm/migrate.c
index 4e0eccc..449d77d 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -383,7 +383,14 @@
if (PageDirty(page)) {
clear_page_dirty_for_io(page);
- set_page_dirty(newpage);
+ /*
+ * Want to mark the page and the radix tree as dirty, and
+ * redo the accounting that clear_page_dirty_for_io undid,
+ * but we can't use set_page_dirty because that function
+ * is actually a signal that all of the page has become dirty.
+ * Wheras only part of our page may be dirty.
+ */
+ __set_page_dirty_nobuffers(newpage);
}
#ifdef CONFIG_SWAP
diff --git a/mm/mmap.c b/mm/mmap.c
index 677d184..fac6633 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -230,8 +230,11 @@
might_sleep();
if (vma->vm_ops && vma->vm_ops->close)
vma->vm_ops->close(vma);
- if (vma->vm_file)
+ if (vma->vm_file) {
fput(vma->vm_file);
+ if (vma->vm_flags & VM_EXECUTABLE)
+ removed_exe_file_vma(vma->vm_mm);
+ }
mpol_put(vma_policy(vma));
kmem_cache_free(vm_area_cachep, vma);
return next;
@@ -623,8 +626,11 @@
spin_unlock(&mapping->i_mmap_lock);
if (remove_next) {
- if (file)
+ if (file) {
fput(file);
+ if (next->vm_flags & VM_EXECUTABLE)
+ removed_exe_file_vma(mm);
+ }
mm->map_count--;
mpol_put(vma_policy(next));
kmem_cache_free(vm_area_cachep, next);
@@ -1154,6 +1160,8 @@
error = file->f_op->mmap(file, vma);
if (error)
goto unmap_and_free_vma;
+ if (vm_flags & VM_EXECUTABLE)
+ added_exe_file_vma(mm);
} else if (vm_flags & VM_SHARED) {
error = shmem_zero_setup(vma);
if (error)
@@ -1185,6 +1193,8 @@
mpol_put(vma_policy(vma));
kmem_cache_free(vm_area_cachep, vma);
fput(file);
+ if (vm_flags & VM_EXECUTABLE)
+ removed_exe_file_vma(mm);
} else {
vma_link(mm, vma, prev, rb_link, rb_parent);
file = vma->vm_file;
@@ -1817,8 +1827,11 @@
}
vma_set_policy(new, pol);
- if (new->vm_file)
+ if (new->vm_file) {
get_file(new->vm_file);
+ if (vma->vm_flags & VM_EXECUTABLE)
+ added_exe_file_vma(mm);
+ }
if (new->vm_ops && new->vm_ops->open)
new->vm_ops->open(new);
@@ -2135,8 +2148,11 @@
new_vma->vm_start = addr;
new_vma->vm_end = addr + len;
new_vma->vm_pgoff = pgoff;
- if (new_vma->vm_file)
+ if (new_vma->vm_file) {
get_file(new_vma->vm_file);
+ if (vma->vm_flags & VM_EXECUTABLE)
+ added_exe_file_vma(mm);
+ }
if (new_vma->vm_ops && new_vma->vm_ops->open)
new_vma->vm_ops->open(new_vma);
vma_link(mm, new_vma, prev, rb_link, rb_parent);
diff --git a/mm/nommu.c b/mm/nommu.c
index 1d32fe8..ef8c62c 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -966,8 +966,13 @@
INIT_LIST_HEAD(&vma->anon_vma_node);
atomic_set(&vma->vm_usage, 1);
- if (file)
+ if (file) {
get_file(file);
+ if (vm_flags & VM_EXECUTABLE) {
+ added_exe_file_vma(current->mm);
+ vma->vm_mm = current->mm;
+ }
+ }
vma->vm_file = file;
vma->vm_flags = vm_flags;
vma->vm_start = addr;
@@ -1022,8 +1027,11 @@
up_write(&nommu_vma_sem);
kfree(vml);
if (vma) {
- if (vma->vm_file)
+ if (vma->vm_file) {
fput(vma->vm_file);
+ if (vma->vm_flags & VM_EXECUTABLE)
+ removed_exe_file_vma(vma->vm_mm);
+ }
kfree(vma);
}
return ret;
@@ -1053,7 +1061,7 @@
/*
* handle mapping disposal for uClinux
*/
-static void put_vma(struct vm_area_struct *vma)
+static void put_vma(struct mm_struct *mm, struct vm_area_struct *vma)
{
if (vma) {
down_write(&nommu_vma_sem);
@@ -1075,8 +1083,11 @@
realalloc -= kobjsize(vma);
askedalloc -= sizeof(*vma);
- if (vma->vm_file)
+ if (vma->vm_file) {
fput(vma->vm_file);
+ if (vma->vm_flags & VM_EXECUTABLE)
+ removed_exe_file_vma(mm);
+ }
kfree(vma);
}
@@ -1113,7 +1124,7 @@
found:
vml = *parent;
- put_vma(vml->vma);
+ put_vma(mm, vml->vma);
*parent = vml->next;
realalloc -= kobjsize(vml);
@@ -1158,7 +1169,7 @@
while ((tmp = mm->context.vmlist)) {
mm->context.vmlist = tmp->next;
- put_vma(tmp->vma);
+ put_vma(mm, tmp->vma);
realalloc -= kobjsize(tmp);
askedalloc -= sizeof(*tmp);
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 5e00f17..789b6ad 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -164,9 +164,20 @@
*/
static inline void __bdi_writeout_inc(struct backing_dev_info *bdi)
{
- __prop_inc_percpu(&vm_completions, &bdi->completions);
+ __prop_inc_percpu_max(&vm_completions, &bdi->completions,
+ bdi->max_prop_frac);
}
+void bdi_writeout_inc(struct backing_dev_info *bdi)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ __bdi_writeout_inc(bdi);
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(bdi_writeout_inc);
+
static inline void task_dirty_inc(struct task_struct *tsk)
{
prop_inc_single(&vm_dirties, &tsk->dirties);
@@ -200,7 +211,8 @@
avail_dirty = dirty -
(global_page_state(NR_FILE_DIRTY) +
global_page_state(NR_WRITEBACK) +
- global_page_state(NR_UNSTABLE_NFS));
+ global_page_state(NR_UNSTABLE_NFS) +
+ global_page_state(NR_WRITEBACK_TEMP));
if (avail_dirty < 0)
avail_dirty = 0;
@@ -243,6 +255,55 @@
}
/*
+ *
+ */
+static DEFINE_SPINLOCK(bdi_lock);
+static unsigned int bdi_min_ratio;
+
+int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&bdi_lock, flags);
+ if (min_ratio > bdi->max_ratio) {
+ ret = -EINVAL;
+ } else {
+ min_ratio -= bdi->min_ratio;
+ if (bdi_min_ratio + min_ratio < 100) {
+ bdi_min_ratio += min_ratio;
+ bdi->min_ratio += min_ratio;
+ } else {
+ ret = -EINVAL;
+ }
+ }
+ spin_unlock_irqrestore(&bdi_lock, flags);
+
+ return ret;
+}
+
+int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ if (max_ratio > 100)
+ return -EINVAL;
+
+ spin_lock_irqsave(&bdi_lock, flags);
+ if (bdi->min_ratio > max_ratio) {
+ ret = -EINVAL;
+ } else {
+ bdi->max_ratio = max_ratio;
+ bdi->max_prop_frac = (PROP_FRAC_BASE * max_ratio) / 100;
+ }
+ spin_unlock_irqrestore(&bdi_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(bdi_set_max_ratio);
+
+/*
* Work out the current dirty-memory clamping and background writeout
* thresholds.
*
@@ -300,7 +361,7 @@
return x + 1; /* Ensure that we never return 0 */
}
-static void
+void
get_dirty_limits(long *pbackground, long *pdirty, long *pbdi_dirty,
struct backing_dev_info *bdi)
{
@@ -330,7 +391,7 @@
*pdirty = dirty;
if (bdi) {
- u64 bdi_dirty = dirty;
+ u64 bdi_dirty;
long numerator, denominator;
/*
@@ -338,8 +399,12 @@
*/
bdi_writeout_fraction(bdi, &numerator, &denominator);
+ bdi_dirty = (dirty * (100 - bdi_min_ratio)) / 100;
bdi_dirty *= numerator;
do_div(bdi_dirty, denominator);
+ bdi_dirty += (dirty * bdi->min_ratio) / 100;
+ if (bdi_dirty > (dirty * bdi->max_ratio) / 100)
+ bdi_dirty = dirty * bdi->max_ratio / 100;
*pbdi_dirty = bdi_dirty;
clip_bdi_dirty_limit(bdi, dirty, pbdi_dirty);
@@ -1192,7 +1257,7 @@
radix_tree_tag_clear(&mapping->page_tree,
page_index(page),
PAGECACHE_TAG_WRITEBACK);
- if (bdi_cap_writeback_dirty(bdi)) {
+ if (bdi_cap_account_writeback(bdi)) {
__dec_bdi_stat(bdi, BDI_WRITEBACK);
__bdi_writeout_inc(bdi);
}
@@ -1221,7 +1286,7 @@
radix_tree_tag_set(&mapping->page_tree,
page_index(page),
PAGECACHE_TAG_WRITEBACK);
- if (bdi_cap_writeback_dirty(bdi))
+ if (bdi_cap_account_writeback(bdi))
__inc_bdi_stat(bdi, BDI_WRITEBACK);
}
if (!PageDirty(page))
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index d1cf4f0..bdd5c43 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -45,6 +45,7 @@
#include <linux/fault-inject.h>
#include <linux/page-isolation.h>
#include <linux/memcontrol.h>
+#include <linux/debugobjects.h>
#include <asm/tlbflush.h>
#include <asm/div64.h>
@@ -532,8 +533,11 @@
if (reserved)
return;
- if (!PageHighMem(page))
+ if (!PageHighMem(page)) {
debug_check_no_locks_freed(page_address(page),PAGE_SIZE<<order);
+ debug_check_no_obj_freed(page_address(page),
+ PAGE_SIZE << order);
+ }
arch_free_page(page, order);
kernel_map_pages(page, 1 << order, 0);
@@ -995,8 +999,10 @@
if (free_pages_check(page))
return;
- if (!PageHighMem(page))
+ if (!PageHighMem(page)) {
debug_check_no_locks_freed(page_address(page), PAGE_SIZE);
+ debug_check_no_obj_freed(page_address(page), PAGE_SIZE);
+ }
arch_free_page(page, 0);
kernel_map_pages(page, 1, 0);
@@ -1461,7 +1467,8 @@
struct task_struct *p = current;
int do_retry;
int alloc_flags;
- int did_some_progress;
+ unsigned long did_some_progress;
+ unsigned long pages_reclaimed = 0;
might_sleep_if(wait);
@@ -1611,14 +1618,26 @@
* Don't let big-order allocations loop unless the caller explicitly
* requests that. Wait for some write requests to complete then retry.
*
- * In this implementation, __GFP_REPEAT means __GFP_NOFAIL for order
- * <= 3, but that may not be true in other implementations.
+ * In this implementation, order <= PAGE_ALLOC_COSTLY_ORDER
+ * means __GFP_NOFAIL, but that may not be true in other
+ * implementations.
+ *
+ * For order > PAGE_ALLOC_COSTLY_ORDER, if __GFP_REPEAT is
+ * specified, then we retry until we no longer reclaim any pages
+ * (above), or we've reclaimed an order of pages at least as
+ * large as the allocation's order. In both cases, if the
+ * allocation still fails, we stop retrying.
*/
+ pages_reclaimed += did_some_progress;
do_retry = 0;
if (!(gfp_mask & __GFP_NORETRY)) {
- if ((order <= PAGE_ALLOC_COSTLY_ORDER) ||
- (gfp_mask & __GFP_REPEAT))
+ if (order <= PAGE_ALLOC_COSTLY_ORDER) {
do_retry = 1;
+ } else {
+ if (gfp_mask & __GFP_REPEAT &&
+ pages_reclaimed < (1 << order))
+ do_retry = 1;
+ }
if (gfp_mask & __GFP_NOFAIL)
do_retry = 1;
}
@@ -2524,7 +2543,9 @@
struct page *page;
unsigned long end_pfn = start_pfn + size;
unsigned long pfn;
+ struct zone *z;
+ z = &NODE_DATA(nid)->node_zones[zone];
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
/*
* There can be holes in boot-time mem_map[]s
@@ -2542,7 +2563,6 @@
init_page_count(page);
reset_page_mapcount(page);
SetPageReserved(page);
-
/*
* Mark the block movable so that blocks are reserved for
* movable at startup. This will force kernel allocations
@@ -2551,8 +2571,15 @@
* kernel allocations are made. Later some blocks near
* the start are marked MIGRATE_RESERVE by
* setup_zone_migrate_reserve()
+ *
+ * bitmap is created for zone's valid pfn range. but memmap
+ * can be created for invalid pages (for alignment)
+ * check here not to call set_pageblock_migratetype() against
+ * pfn out of zone.
*/
- if ((pfn & (pageblock_nr_pages-1)))
+ if ((z->zone_start_pfn <= pfn)
+ && (pfn < z->zone_start_pfn + z->spanned_pages)
+ && !(pfn & (pageblock_nr_pages - 1)))
set_pageblock_migratetype(page, MIGRATE_MOVABLE);
INIT_LIST_HEAD(&page->lru);
@@ -4464,6 +4491,8 @@
pfn = page_to_pfn(page);
bitmap = get_pageblock_bitmap(zone, pfn);
bitidx = pfn_to_bitidx(zone, pfn);
+ VM_BUG_ON(pfn < zone->zone_start_pfn);
+ VM_BUG_ON(pfn >= zone->zone_start_pfn + zone->spanned_pages);
for (; start_bitidx <= end_bitidx; start_bitidx++, value <<= 1)
if (flags & value)
diff --git a/mm/readahead.c b/mm/readahead.c
index 8762e89..d8723a5 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -235,7 +235,13 @@
static int __init readahead_init(void)
{
- return bdi_init(&default_backing_dev_info);
+ int err;
+
+ err = bdi_init(&default_backing_dev_info);
+ if (!err)
+ bdi_register(&default_backing_dev_info, NULL, "default");
+
+ return err;
}
subsys_initcall(readahead_init);
diff --git a/mm/shmem.c b/mm/shmem.c
index e6d9298..e2a6ae1 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -201,7 +201,7 @@
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,
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
.unplug_io_fn = default_unplug_io_fn,
};
diff --git a/mm/slab.c b/mm/slab.c
index 39d20f8..06236e4 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -110,6 +110,7 @@
#include <linux/fault-inject.h>
#include <linux/rtmutex.h>
#include <linux/reciprocal_div.h>
+#include <linux/debugobjects.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
@@ -174,12 +175,14 @@
SLAB_CACHE_DMA | \
SLAB_STORE_USER | \
SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
- SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD)
+ SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \
+ SLAB_DEBUG_OBJECTS)
#else
# define CREATE_MASK (SLAB_HWCACHE_ALIGN | \
SLAB_CACHE_DMA | \
SLAB_RECLAIM_ACCOUNT | SLAB_PANIC | \
- SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD)
+ SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD | \
+ SLAB_DEBUG_OBJECTS)
#endif
/*
@@ -858,7 +861,7 @@
*left_over = slab_size - nr_objs*buffer_size - mgmt_size;
}
-#define slab_error(cachep, msg) __slab_error(__FUNCTION__, cachep, msg)
+#define slab_error(cachep, msg) __slab_error(__func__, cachep, msg)
static void __slab_error(const char *function, struct kmem_cache *cachep,
char *msg)
@@ -2153,7 +2156,7 @@
*/
if (!name || in_interrupt() || (size < BYTES_PER_WORD) ||
size > KMALLOC_MAX_SIZE) {
- printk(KERN_ERR "%s: Early error in slab %s\n", __FUNCTION__,
+ printk(KERN_ERR "%s: Early error in slab %s\n", __func__,
name);
BUG();
}
@@ -3760,6 +3763,8 @@
local_irq_save(flags);
debug_check_no_locks_freed(objp, obj_size(cachep));
+ if (!(cachep->flags & SLAB_DEBUG_OBJECTS))
+ debug_check_no_obj_freed(objp, obj_size(cachep));
__cache_free(cachep, objp);
local_irq_restore(flags);
}
@@ -3785,6 +3790,7 @@
kfree_debugcheck(objp);
c = virt_to_cache(objp);
debug_check_no_locks_freed(objp, obj_size(c));
+ debug_check_no_obj_freed(objp, obj_size(c));
__cache_free(c, (void *)objp);
local_irq_restore(flags);
}
diff --git a/mm/slub.c b/mm/slub.c
index 992ecd4..32b6262 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -19,8 +19,10 @@
#include <linux/cpuset.h>
#include <linux/mempolicy.h>
#include <linux/ctype.h>
+#include <linux/debugobjects.h>
#include <linux/kallsyms.h>
#include <linux/memory.h>
+#include <linux/math64.h>
/*
* Lock order:
@@ -1747,6 +1749,8 @@
local_irq_save(flags);
c = get_cpu_slab(s, smp_processor_id());
debug_check_no_locks_freed(object, c->objsize);
+ if (!(s->flags & SLAB_DEBUG_OBJECTS))
+ debug_check_no_obj_freed(object, s->objsize);
if (likely(page == c->page && c->node >= 0)) {
object[c->offset] = c->freelist;
c->freelist = object;
@@ -2978,7 +2982,7 @@
kmalloc_caches[0].refcount = -1;
caches++;
- hotplug_memory_notifier(slab_memory_callback, 1);
+ hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
#endif
/* Able to allocate the per node structures */
@@ -3618,12 +3622,10 @@
len += sprintf(buf + len, "<not-available>");
if (l->sum_time != l->min_time) {
- unsigned long remainder;
-
len += sprintf(buf + len, " age=%ld/%ld/%ld",
- l->min_time,
- div_long_long_rem(l->sum_time, l->count, &remainder),
- l->max_time);
+ l->min_time,
+ (long)div_u64(l->sum_time, l->count),
+ l->max_time);
} else
len += sprintf(buf + len, " age=%ld",
l->min_time);
diff --git a/mm/sparse.c b/mm/sparse.c
index dff71f1..36511c7 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -250,29 +250,18 @@
static unsigned long *__init sparse_early_usemap_alloc(unsigned long pnum)
{
- unsigned long *usemap, section_nr;
+ unsigned long *usemap;
struct mem_section *ms = __nr_to_section(pnum);
int nid = sparse_early_nid(ms);
- struct pglist_data *pgdat = NODE_DATA(nid);
- /*
- * Usemap's page can't be freed until freeing other sections
- * which use it. And, Pgdat has same feature.
- * If section A has pgdat and section B has usemap for other
- * sections (includes section A), both sections can't be removed,
- * because there is the dependency each other.
- * To solve above issue, this collects all usemap on the same section
- * which has pgdat.
- */
- section_nr = pfn_to_section_nr(__pa(pgdat) >> PAGE_SHIFT);
- usemap = alloc_bootmem_section(usemap_size(), section_nr);
+ usemap = alloc_bootmem_node(NODE_DATA(nid), usemap_size());
if (usemap)
return usemap;
/* Stupid: suppress gcc warning for SPARSEMEM && !NUMA */
nid = 0;
- printk(KERN_WARNING "%s: allocation failed\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: allocation failed\n", __func__);
return NULL;
}
@@ -302,7 +291,7 @@
return map;
printk(KERN_ERR "%s: sparsemem memory map backing failed "
- "some memory will not be available.\n", __FUNCTION__);
+ "some memory will not be available.\n", __func__);
ms->section_mem_map = 0;
return NULL;
}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 50757ee..d8aadaf 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -33,7 +33,7 @@
};
static struct backing_dev_info swap_backing_dev_info = {
- .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
+ .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK,
.unplug_io_fn = swap_unplug_io_fn,
};
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 67051be..bd1bb59 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1426,11 +1426,7 @@
static int __init procswaps_init(void)
{
- struct proc_dir_entry *entry;
-
- entry = create_proc_entry("swaps", 0, NULL);
- if (entry)
- entry->proc_fops = &proc_swaps_operations;
+ proc_create("swaps", 0, NULL, &proc_swaps_operations);
return 0;
}
__initcall(procswaps_init);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index e33e0ae..6e45b0f 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -15,6 +15,7 @@
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/seq_file.h>
+#include <linux/debugobjects.h>
#include <linux/vmalloc.h>
#include <linux/kallsyms.h>
@@ -394,6 +395,7 @@
}
debug_check_no_locks_freed(addr, area->size);
+ debug_check_no_obj_freed(addr, area->size);
if (deallocate_pages) {
int i;
@@ -545,6 +547,7 @@
* @gfp_mask: flags for the page level allocator
* @prot: protection mask for the allocated pages
* @node: node to use for allocation or -1
+ * @caller: caller's return address
*
* Allocate enough pages to cover @size from the page level
* allocator with @gfp_mask flags. Map them into contiguous
diff --git a/mm/vmscan.c b/mm/vmscan.c
index eceac9f..9a29901 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -191,7 +191,7 @@
shrinker->nr += delta;
if (shrinker->nr < 0) {
printk(KERN_ERR "%s: nr=%ld\n",
- __FUNCTION__, shrinker->nr);
+ __func__, shrinker->nr);
shrinker->nr = max_pass;
}
@@ -339,7 +339,7 @@
if (PagePrivate(page)) {
if (try_to_free_buffers(page)) {
ClearPageDirty(page);
- printk("%s: orphaned page\n", __FUNCTION__);
+ printk("%s: orphaned page\n", __func__);
return PAGE_CLEAN;
}
}
@@ -1299,6 +1299,9 @@
* hope that some of these pages can be written. But if the allocating task
* holds filesystem locks which prevent writeout this might not work, and the
* allocation attempt will fail.
+ *
+ * returns: 0, if no pages reclaimed
+ * else, the number of pages reclaimed
*/
static unsigned long do_try_to_free_pages(struct zonelist *zonelist,
struct scan_control *sc)
@@ -1347,7 +1350,7 @@
}
total_scanned += sc->nr_scanned;
if (nr_reclaimed >= sc->swap_cluster_max) {
- ret = 1;
+ ret = nr_reclaimed;
goto out;
}
@@ -1370,7 +1373,7 @@
}
/* top priority shrink_caches still had more to do? don't OOM, then */
if (!sc->all_unreclaimable && scan_global_lru(sc))
- ret = 1;
+ ret = nr_reclaimed;
out:
/*
* Now that we've scanned all the zones at this priority level, note
diff --git a/mm/vmstat.c b/mm/vmstat.c
index ec6035e..1a32130 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -548,6 +548,10 @@
{
pg_data_t *pgdat = (pg_data_t *)arg;
+ /* check memoryless node */
+ if (!node_state(pgdat->node_id, N_HIGH_MEMORY))
+ return 0;
+
seq_printf(m, "Page block order: %d\n", pageblock_order);
seq_printf(m, "Pages per block: %lu\n", pageblock_nr_pages);
seq_putc(m, '\n');
@@ -608,6 +612,7 @@
"nr_unstable",
"nr_bounce",
"nr_vmscan_write",
+ "nr_writeback_temp",
#ifdef CONFIG_NUMA
"numa_hit",
diff --git a/net/bridge/br.c b/net/bridge/br.c
index a901828..8f3c58e 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -76,7 +76,6 @@
rcu_assign_pointer(br_stp_sap->rcv_func, NULL);
br_netlink_fini();
- br_netfilter_fini();
unregister_netdevice_notifier(&br_device_notifier);
brioctl_set(NULL);
@@ -84,6 +83,7 @@
synchronize_net();
+ br_netfilter_fini();
llc_sap_put(br_stp_sap);
br_fdb_get_hook = NULL;
br_fdb_put_hook = NULL;
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 298e0f4..77a981a 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -411,9 +411,12 @@
br_fdb_delete_by_port(br, p, 1);
err1:
kobject_del(&p->kobj);
- return err;
+ goto put_back;
err0:
kobject_put(&p->kobj);
+
+put_back:
+ dev_put(dev);
return err;
}
diff --git a/net/compat.c b/net/compat.c
index 01bf95d..c823f6f 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -548,6 +548,9 @@
__attribute__ ((aligned(4)));
} __attribute__ ((packed));
+#define __COMPAT_GF0_SIZE (sizeof(struct compat_group_filter) - \
+ sizeof(struct __kernel_sockaddr_storage))
+
int compat_mc_setsockopt(struct sock *sock, int level, int optname,
char __user *optval, int optlen,
@@ -582,7 +585,7 @@
case MCAST_UNBLOCK_SOURCE:
{
struct compat_group_source_req __user *gsr32 = (void *)optval;
- struct group_source_req *kgsr = compat_alloc_user_space(
+ struct group_source_req __user *kgsr = compat_alloc_user_space(
sizeof(struct group_source_req));
u32 interface;
@@ -603,10 +606,10 @@
case MCAST_MSFILTER:
{
struct compat_group_filter __user *gf32 = (void *)optval;
- struct group_filter *kgf;
+ struct group_filter __user *kgf;
u32 interface, fmode, numsrc;
- if (!access_ok(VERIFY_READ, gf32, sizeof(*gf32)) ||
+ if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
__get_user(interface, &gf32->gf_interface) ||
__get_user(fmode, &gf32->gf_fmode) ||
__get_user(numsrc, &gf32->gf_numsrc))
@@ -622,7 +625,7 @@
__put_user(numsrc, &kgf->gf_numsrc) ||
copy_in_user(&kgf->gf_group, &gf32->gf_group,
sizeof(kgf->gf_group)) ||
- (numsrc && copy_in_user(&kgf->gf_slist, &gf32->gf_slist,
+ (numsrc && copy_in_user(kgf->gf_slist, gf32->gf_slist,
numsrc * sizeof(kgf->gf_slist[0]))))
return -EFAULT;
koptval = (char __user *)kgf;
@@ -637,6 +640,85 @@
EXPORT_SYMBOL(compat_mc_setsockopt);
+int compat_mc_getsockopt(struct sock *sock, int level, int optname,
+ char __user *optval, int __user *optlen,
+ int (*getsockopt)(struct sock *,int,int,char __user *,int __user *))
+{
+ struct compat_group_filter __user *gf32 = (void *)optval;
+ struct group_filter __user *kgf;
+ int __user *koptlen;
+ u32 interface, fmode, numsrc;
+ int klen, ulen, err;
+
+ if (optname != MCAST_MSFILTER)
+ return getsockopt(sock, level, optname, optval, optlen);
+
+ koptlen = compat_alloc_user_space(sizeof(*koptlen));
+ if (!access_ok(VERIFY_READ, optlen, sizeof(*optlen)) ||
+ __get_user(ulen, optlen))
+ return -EFAULT;
+
+ /* adjust len for pad */
+ klen = ulen + sizeof(*kgf) - sizeof(*gf32);
+
+ if (klen < GROUP_FILTER_SIZE(0))
+ return -EINVAL;
+
+ if (!access_ok(VERIFY_WRITE, koptlen, sizeof(*koptlen)) ||
+ __put_user(klen, koptlen))
+ return -EFAULT;
+
+ /* have to allow space for previous compat_alloc_user_space, too */
+ kgf = compat_alloc_user_space(klen+sizeof(*optlen));
+
+ if (!access_ok(VERIFY_READ, gf32, __COMPAT_GF0_SIZE) ||
+ __get_user(interface, &gf32->gf_interface) ||
+ __get_user(fmode, &gf32->gf_fmode) ||
+ __get_user(numsrc, &gf32->gf_numsrc) ||
+ __put_user(interface, &kgf->gf_interface) ||
+ __put_user(fmode, &kgf->gf_fmode) ||
+ __put_user(numsrc, &kgf->gf_numsrc) ||
+ copy_in_user(&kgf->gf_group,&gf32->gf_group,sizeof(kgf->gf_group)))
+ return -EFAULT;
+
+ err = getsockopt(sock, level, optname, (char __user *)kgf, koptlen);
+ if (err)
+ return err;
+
+ if (!access_ok(VERIFY_READ, koptlen, sizeof(*koptlen)) ||
+ __get_user(klen, koptlen))
+ return -EFAULT;
+
+ ulen = klen - (sizeof(*kgf)-sizeof(*gf32));
+
+ if (!access_ok(VERIFY_WRITE, optlen, sizeof(*optlen)) ||
+ __put_user(ulen, optlen))
+ return -EFAULT;
+
+ if (!access_ok(VERIFY_READ, kgf, klen) ||
+ !access_ok(VERIFY_WRITE, gf32, ulen) ||
+ __get_user(interface, &kgf->gf_interface) ||
+ __get_user(fmode, &kgf->gf_fmode) ||
+ __get_user(numsrc, &kgf->gf_numsrc) ||
+ __put_user(interface, &gf32->gf_interface) ||
+ __put_user(fmode, &gf32->gf_fmode) ||
+ __put_user(numsrc, &gf32->gf_numsrc))
+ return -EFAULT;
+ if (numsrc) {
+ int copylen;
+
+ klen -= GROUP_FILTER_SIZE(0);
+ copylen = numsrc * sizeof(gf32->gf_slist[0]);
+ if (copylen > klen)
+ copylen = klen;
+ if (copy_in_user(gf32->gf_slist, kgf->gf_slist, copylen))
+ return -EFAULT;
+ }
+ return err;
+}
+
+EXPORT_SYMBOL(compat_mc_getsockopt);
+
/* Argument list sizes for compat_sys_socketcall */
#define AL(x) ((x) * sizeof(u32))
diff --git a/net/core/dev.c b/net/core/dev.c
index e1df1ab..ed49da5 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1524,7 +1524,7 @@
if (!segs)
return 0;
- if (unlikely(IS_ERR(segs)))
+ if (IS_ERR(segs))
return PTR_ERR(segs);
skb->next = segs;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index f2b5270..24eca23 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1234,7 +1234,7 @@
segs = ops->gso_segment(skb, features);
rcu_read_unlock();
- if (!segs || unlikely(IS_ERR(segs)))
+ if (!segs || IS_ERR(segs))
goto out;
skb = segs;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index c67d00e..8739735 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -691,7 +691,8 @@
NIPQUAD(iph->daddr));
} else {
info = ip_rt_frag_needed(net, iph,
- ntohs(icmph->un.frag.mtu));
+ ntohs(icmph->un.frag.mtu),
+ skb->dev);
if (!info)
goto out;
}
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 0834926..e527628 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -753,23 +753,15 @@
skb->ip_summed = CHECKSUM_PARTIAL;
skb->csum = 0;
sk->sk_sndmsg_off = 0;
- }
- err = skb_append_datato_frags(sk,skb, getfrag, from,
- (length - transhdrlen));
- if (!err) {
- /* specify the length of each IP datagram fragment*/
+ /* specify the length of each IP datagram fragment */
skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
__skb_queue_tail(&sk->sk_write_queue, skb);
-
- return 0;
}
- /* There is not enough support do UFO ,
- * so follow normal path
- */
- kfree_skb(skb);
- return err;
+
+ return skb_append_datato_frags(sk, skb, getfrag, from,
+ (length - transhdrlen));
}
/*
@@ -863,9 +855,9 @@
csummode = CHECKSUM_PARTIAL;
inet->cork.length += length;
- if (((length > mtu) && (sk->sk_protocol == IPPROTO_UDP)) &&
- (rt->u.dst.dev->features & NETIF_F_UFO)) {
-
+ if (((length> mtu) || !skb_queue_empty(&sk->sk_write_queue)) &&
+ (sk->sk_protocol == IPPROTO_UDP) &&
+ (rt->u.dst.dev->features & NETIF_F_UFO)) {
err = ip_ufo_append_data(sk, getfrag, from, length, hh_len,
fragheaderlen, transhdrlen, mtu,
flags);
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 4d8d954..e0514e8 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -1186,7 +1186,14 @@
int compat_ip_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen)
{
- int err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+ int err;
+
+ if (optname == MCAST_MSFILTER)
+ return compat_mc_getsockopt(sk, level, optname, optval, optlen,
+ ip_getsockopt);
+
+ err = do_ip_getsockopt(sk, level, optname, optval, optlen);
+
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS &&
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 0f42d1c..89dee43 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -412,12 +412,12 @@
.func = ic_rarp_recv,
};
-static inline void ic_rarp_init(void)
+static inline void __init ic_rarp_init(void)
{
dev_add_pack(&rarp_packet_type);
}
-static inline void ic_rarp_cleanup(void)
+static inline void __init ic_rarp_cleanup(void)
{
dev_remove_pack(&rarp_packet_type);
}
@@ -682,7 +682,7 @@
/*
* Initialize the DHCP/BOOTP mechanism.
*/
-static inline void ic_bootp_init(void)
+static inline void __init ic_bootp_init(void)
{
int i;
@@ -696,7 +696,7 @@
/*
* DHCP/BOOTP cleanup.
*/
-static inline void ic_bootp_cleanup(void)
+static inline void __init ic_bootp_cleanup(void)
{
dev_remove_pack(&bootp_packet_type);
}
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
index dde28a2..4b1c16c 100644
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ b/net/ipv4/ipvs/ip_vs_proto.c
@@ -148,7 +148,7 @@
struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
if (pp == NULL || pp->state_name == NULL)
- return "ERR!";
+ return (IPPROTO_IP == proto) ? "NONE" : "ERR!";
return pp->state_name(state);
}
diff --git a/net/ipv4/ipvs/ip_vs_proto_ah.c b/net/ipv4/ipvs/ip_vs_proto_ah.c
index a842676..4bf835e 100644
--- a/net/ipv4/ipvs/ip_vs_proto_ah.c
+++ b/net/ipv4/ipvs/ip_vs_proto_ah.c
@@ -160,6 +160,7 @@
struct ip_vs_protocol ip_vs_protocol_ah = {
.name = "AH",
.protocol = IPPROTO_AH,
+ .num_states = 1,
.dont_defrag = 1,
.init = ah_init,
.exit = ah_exit,
diff --git a/net/ipv4/ipvs/ip_vs_proto_esp.c b/net/ipv4/ipvs/ip_vs_proto_esp.c
index aef0d3e..db6a6b7 100644
--- a/net/ipv4/ipvs/ip_vs_proto_esp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_esp.c
@@ -159,6 +159,7 @@
struct ip_vs_protocol ip_vs_protocol_esp = {
.name = "ESP",
.protocol = IPPROTO_ESP,
+ .num_states = 1,
.dont_defrag = 1,
.init = esp_init,
.exit = esp_exit,
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 620e40f..b83dc14 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -594,6 +594,7 @@
struct ip_vs_protocol ip_vs_protocol_tcp = {
.name = "TCP",
.protocol = IPPROTO_TCP,
+ .num_states = IP_VS_TCP_S_LAST,
.dont_defrag = 0,
.appcnt = ATOMIC_INIT(0),
.init = ip_vs_tcp_init,
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 1caa290..75771cb 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -409,6 +409,7 @@
struct ip_vs_protocol ip_vs_protocol_udp = {
.name = "UDP",
.protocol = IPPROTO_UDP,
+ .num_states = IP_VS_UDP_S_LAST,
.dont_defrag = 0,
.init = udp_init,
.exit = udp_exit,
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index 69c5666..eff54ef 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -288,11 +288,16 @@
char *p;
int i;
+ if (buflen < sizeof(struct ip_vs_sync_mesg)) {
+ IP_VS_ERR_RL("sync message header too short\n");
+ return;
+ }
+
/* Convert size back to host byte order */
m->size = ntohs(m->size);
if (buflen != m->size) {
- IP_VS_ERR("bogus message\n");
+ IP_VS_ERR_RL("bogus sync message size\n");
return;
}
@@ -307,9 +312,48 @@
for (i=0; i<m->nr_conns; i++) {
unsigned flags, state;
- s = (struct ip_vs_sync_conn *)p;
+ if (p + SIMPLE_CONN_SIZE > buffer+buflen) {
+ IP_VS_ERR_RL("bogus conn in sync message\n");
+ return;
+ }
+ s = (struct ip_vs_sync_conn *) p;
flags = ntohs(s->flags) | IP_VS_CONN_F_SYNC;
+ flags &= ~IP_VS_CONN_F_HASHED;
+ if (flags & IP_VS_CONN_F_SEQ_MASK) {
+ opt = (struct ip_vs_sync_conn_options *)&s[1];
+ p += FULL_CONN_SIZE;
+ if (p > buffer+buflen) {
+ IP_VS_ERR_RL("bogus conn options in sync message\n");
+ return;
+ }
+ } else {
+ opt = NULL;
+ p += SIMPLE_CONN_SIZE;
+ }
+
state = ntohs(s->state);
+ if (!(flags & IP_VS_CONN_F_TEMPLATE)) {
+ pp = ip_vs_proto_get(s->protocol);
+ if (!pp) {
+ IP_VS_ERR_RL("Unsupported protocol %u in sync msg\n",
+ s->protocol);
+ continue;
+ }
+ if (state >= pp->num_states) {
+ IP_VS_DBG(2, "Invalid %s state %u in sync msg\n",
+ pp->name, state);
+ continue;
+ }
+ } else {
+ /* protocol in templates is not used for state/timeout */
+ pp = NULL;
+ if (state > 0) {
+ IP_VS_DBG(2, "Invalid template state %u in sync msg\n",
+ state);
+ state = 0;
+ }
+ }
+
if (!(flags & IP_VS_CONN_F_TEMPLATE))
cp = ip_vs_conn_in_get(s->protocol,
s->caddr, s->cport,
@@ -345,14 +389,9 @@
IP_VS_ERR("ip_vs_conn_new failed\n");
return;
}
- cp->state = state;
} else if (!cp->dest) {
dest = ip_vs_try_bind_dest(cp);
- if (!dest) {
- /* it is an unbound entry created by
- * synchronization */
- cp->flags = flags | IP_VS_CONN_F_HASHED;
- } else
+ if (dest)
atomic_dec(&dest->refcnt);
} else if ((cp->dest) && (cp->protocol == IPPROTO_TCP) &&
(cp->state != state)) {
@@ -371,23 +410,22 @@
}
}
- if (flags & IP_VS_CONN_F_SEQ_MASK) {
- opt = (struct ip_vs_sync_conn_options *)&s[1];
+ if (opt)
memcpy(&cp->in_seq, opt, sizeof(*opt));
- p += FULL_CONN_SIZE;
- } else
- p += SIMPLE_CONN_SIZE;
-
atomic_set(&cp->in_pkts, sysctl_ip_vs_sync_threshold[0]);
cp->state = state;
- pp = ip_vs_proto_get(s->protocol);
- cp->timeout = pp->timeout_table[cp->state];
+ cp->old_state = cp->state;
+ /*
+ * We can not recover the right timeout for templates
+ * in all cases, we can not find the right fwmark
+ * virtual service. If needed, we can do it for
+ * non-fwmark persistent services.
+ */
+ if (!(flags & IP_VS_CONN_F_TEMPLATE) && pp->timeout_table)
+ cp->timeout = pp->timeout_table[state];
+ else
+ cp->timeout = (3*60*HZ);
ip_vs_conn_put(cp);
-
- if (p > buffer+buflen) {
- IP_VS_ERR("bogus message\n");
- return;
- }
}
}
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 719be29..26a37ce 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -296,9 +296,8 @@
if (v->data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
- nskb = skb_copy_expand(e->skb, 0,
- diff - skb_tailroom(e->skb),
- GFP_ATOMIC);
+ nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
+ diff, GFP_ATOMIC);
if (!nskb) {
printk(KERN_WARNING "ip_queue: error "
"in mangle, dropping packet\n");
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index cacb9cb..5a955c4 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -303,7 +303,7 @@
const struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_tuple tuple;
- NF_CT_TUPLE_U_BLANK(&tuple);
+ memset(&tuple, 0, sizeof(tuple));
tuple.src.u3.ip = inet->rcv_saddr;
tuple.src.u.tcp.port = inet->sport;
tuple.dst.u3.ip = inet->daddr;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index ce25a13..5e3685c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1430,11 +1430,13 @@
}
unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
- unsigned short new_mtu)
+ unsigned short new_mtu,
+ struct net_device *dev)
{
- int i;
+ int i, k;
unsigned short old_mtu = ntohs(iph->tot_len);
struct rtable *rth;
+ int ikeys[2] = { dev->ifindex, 0 };
__be32 skeys[2] = { iph->saddr, 0, };
__be32 daddr = iph->daddr;
unsigned short est_mtu = 0;
@@ -1442,22 +1444,26 @@
if (ipv4_config.no_pmtu_disc)
return 0;
- for (i = 0; i < 2; i++) {
- unsigned hash = rt_hash(daddr, skeys[i], 0);
+ for (k = 0; k < 2; k++) {
+ for (i = 0; i < 2; i++) {
+ unsigned hash = rt_hash(daddr, skeys[i], ikeys[k]);
- rcu_read_lock();
- for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
- rth = rcu_dereference(rth->u.dst.rt_next)) {
- if (rth->fl.fl4_dst == daddr &&
- rth->fl.fl4_src == skeys[i] &&
- rth->rt_dst == daddr &&
- rth->rt_src == iph->saddr &&
- rth->fl.iif == 0 &&
- !(dst_metric_locked(&rth->u.dst, RTAX_MTU)) &&
- net_eq(dev_net(rth->u.dst.dev), net) &&
- rth->rt_genid == atomic_read(&rt_genid)) {
+ rcu_read_lock();
+ for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
+ rth = rcu_dereference(rth->u.dst.rt_next)) {
unsigned short mtu = new_mtu;
+ if (rth->fl.fl4_dst != daddr ||
+ rth->fl.fl4_src != skeys[i] ||
+ rth->rt_dst != daddr ||
+ rth->rt_src != iph->saddr ||
+ rth->fl.oif != ikeys[k] ||
+ rth->fl.iif != 0 ||
+ dst_metric_locked(&rth->u.dst, RTAX_MTU) ||
+ !net_eq(dev_net(rth->u.dst.dev), net) ||
+ rth->rt_genid != atomic_read(&rt_genid))
+ continue;
+
if (new_mtu < 68 || new_mtu >= old_mtu) {
/* BSD 4.2 compatibility hack :-( */
@@ -1483,8 +1489,8 @@
est_mtu = mtu;
}
}
+ rcu_read_unlock();
}
- rcu_read_unlock();
}
return est_mtu ? : new_mtu;
}
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
index 3a6be23..6a25082 100644
--- a/net/ipv4/tcp_cong.c
+++ b/net/ipv4/tcp_cong.c
@@ -285,14 +285,12 @@
if (in_flight >= tp->snd_cwnd)
return 1;
- if (!sk_can_gso(sk))
- return 0;
-
left = tp->snd_cwnd - in_flight;
- if (sysctl_tcp_tso_win_divisor)
- return left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd;
- else
- return left <= tcp_max_burst(tp);
+ if (sk_can_gso(sk) &&
+ left * sysctl_tcp_tso_win_divisor < tp->snd_cwnd &&
+ left * tp->mss_cache < sk->sk_gso_max_size)
+ return 1;
+ return left <= tcp_max_burst(tp);
}
EXPORT_SYMBOL_GPL(tcp_is_cwnd_limited);
diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c
index eb5b985..4a1221e 100644
--- a/net/ipv4/tcp_cubic.c
+++ b/net/ipv4/tcp_cubic.c
@@ -15,8 +15,8 @@
#include <linux/mm.h>
#include <linux/module.h>
+#include <linux/math64.h>
#include <net/tcp.h>
-#include <asm/div64.h>
#define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation
* max_cwnd = snd_cwnd * beta
@@ -128,7 +128,7 @@
* x = ( 2 * x + a / x ) / 3
* k+1 k k
*/
- x = (2 * x + (u32)div64_64(a, (u64)x * (u64)(x - 1)));
+ x = (2 * x + (u32)div64_u64(a, (u64)x * (u64)(x - 1)));
x = ((x * 341) >> 10);
return x;
}
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
index be24d6e..0e1a8c9 100644
--- a/net/ipv4/tcp_vegas.c
+++ b/net/ipv4/tcp_vegas.c
@@ -229,7 +229,8 @@
*/
tcp_reno_cong_avoid(sk, ack, in_flight);
} else {
- u32 rtt, target_cwnd, diff;
+ u32 rtt, diff;
+ u64 target_cwnd;
/* We have enough RTT samples, so, using the Vegas
* algorithm, we determine if we should increase or
@@ -252,8 +253,9 @@
* We keep it as a fixed point number with
* V_PARAM_SHIFT bits to the right of the binary point.
*/
- target_cwnd = ((old_wnd * vegas->baseRTT)
- << V_PARAM_SHIFT) / rtt;
+ target_cwnd = ((u64)old_wnd * vegas->baseRTT);
+ target_cwnd <<= V_PARAM_SHIFT;
+ do_div(target_cwnd, rtt);
/* Calculate the difference between the window we had,
* and the window we would like to have. This quantity
@@ -279,7 +281,7 @@
* utilization.
*/
tp->snd_cwnd = min(tp->snd_cwnd,
- (target_cwnd >>
+ ((u32)target_cwnd >>
V_PARAM_SHIFT)+1);
} else if (tp->snd_cwnd <= tp->snd_ssthresh) {
diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c
index d16689e..2bf618a 100644
--- a/net/ipv4/tcp_veno.c
+++ b/net/ipv4/tcp_veno.c
@@ -133,7 +133,8 @@
*/
tcp_reno_cong_avoid(sk, ack, in_flight);
} else {
- u32 rtt, target_cwnd;
+ u64 target_cwnd;
+ u32 rtt;
/* We have enough rtt samples, so, using the Veno
* algorithm, we determine the state of the network.
@@ -141,8 +142,9 @@
rtt = veno->minrtt;
- target_cwnd = ((tp->snd_cwnd * veno->basertt)
- << V_PARAM_SHIFT) / rtt;
+ target_cwnd = (tp->snd_cwnd * veno->basertt);
+ target_cwnd <<= V_PARAM_SHIFT;
+ do_div(target_cwnd, rtt);
veno->diff = (tp->snd_cwnd << V_PARAM_SHIFT) - target_cwnd;
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index db6fdc1..56d55fe 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -1127,6 +1127,10 @@
if (level != SOL_IPV6)
return -ENOPROTOOPT;
+ if (optname == MCAST_MSFILTER)
+ return compat_mc_getsockopt(sk, level, optname, optval, optlen,
+ ipv6_getsockopt);
+
err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
#ifdef CONFIG_NETFILTER
/* we need to exclude all possible ENOPROTOOPTs except default case */
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index 92a36c9..2eff3ae 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -298,9 +298,8 @@
if (v->data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
- nskb = skb_copy_expand(e->skb, 0,
- diff - skb_tailroom(e->skb),
- GFP_ATOMIC);
+ nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
+ diff, GFP_ATOMIC);
if (!nskb) {
printk(KERN_WARNING "ip6_queue: OOM "
"in mangle, dropping packet\n");
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index d262041..76c3057 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -555,10 +555,8 @@
ircomm_tty_shutdown(self);
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
+ tty_ldisc_flush(tty);
tty->closing = 0;
self->tty = NULL;
diff --git a/net/irda/irnet/irnet_irda.c b/net/irda/irnet/irnet_irda.c
index a4f1439..75497e5 100644
--- a/net/irda/irnet/irnet_irda.c
+++ b/net/irda/irnet/irnet_irda.c
@@ -9,6 +9,7 @@
*/
#include "irnet_irda.h" /* Private header */
+#include <linux/seq_file.h>
/*
* PPP disconnect work: we need to make sure we're in
@@ -1717,34 +1718,23 @@
*/
#ifdef CONFIG_PROC_FS
-/*------------------------------------------------------------------*/
-/*
- * Function irnet_proc_read (buf, start, offset, len, unused)
- *
- * Give some info to the /proc file system
- */
static int
-irnet_proc_read(char * buf,
- char ** start,
- off_t offset,
- int len)
+irnet_proc_show(struct seq_file *m, void *v)
{
irnet_socket * self;
char * state;
int i = 0;
- len = 0;
-
/* Get the IrNET server information... */
- len += sprintf(buf+len, "IrNET server - ");
- len += sprintf(buf+len, "IrDA state: %s, ",
+ seq_printf(m, "IrNET server - ");
+ seq_printf(m, "IrDA state: %s, ",
(irnet_server.running ? "running" : "dead"));
- len += sprintf(buf+len, "stsap_sel: %02x, ", irnet_server.s.stsap_sel);
- len += sprintf(buf+len, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel);
+ seq_printf(m, "stsap_sel: %02x, ", irnet_server.s.stsap_sel);
+ seq_printf(m, "dtsap_sel: %02x\n", irnet_server.s.dtsap_sel);
/* Do we need to continue ? */
if(!irnet_server.running)
- return len;
+ return 0;
/* Protect access to the instance list */
spin_lock_bh(&irnet_server.spinlock);
@@ -1754,23 +1744,23 @@
while(self != NULL)
{
/* Start printing info about the socket. */
- len += sprintf(buf+len, "\nIrNET socket %d - ", i++);
+ seq_printf(m, "\nIrNET socket %d - ", i++);
/* First, get the requested configuration */
- len += sprintf(buf+len, "Requested IrDA name: \"%s\", ", self->rname);
- len += sprintf(buf+len, "daddr: %08x, ", self->rdaddr);
- len += sprintf(buf+len, "saddr: %08x\n", self->rsaddr);
+ seq_printf(m, "Requested IrDA name: \"%s\", ", self->rname);
+ seq_printf(m, "daddr: %08x, ", self->rdaddr);
+ seq_printf(m, "saddr: %08x\n", self->rsaddr);
/* Second, get all the PPP info */
- len += sprintf(buf+len, " PPP state: %s",
+ seq_printf(m, " PPP state: %s",
(self->ppp_open ? "registered" : "unregistered"));
if(self->ppp_open)
{
- len += sprintf(buf+len, ", unit: ppp%d",
+ seq_printf(m, ", unit: ppp%d",
ppp_unit_number(&self->chan));
- len += sprintf(buf+len, ", channel: %d",
+ seq_printf(m, ", channel: %d",
ppp_channel_index(&self->chan));
- len += sprintf(buf+len, ", mru: %d",
+ seq_printf(m, ", mru: %d",
self->mru);
/* Maybe add self->flags ? Later... */
}
@@ -1789,10 +1779,10 @@
state = "weird";
else
state = "idle";
- len += sprintf(buf+len, "\n IrDA state: %s, ", state);
- len += sprintf(buf+len, "daddr: %08x, ", self->daddr);
- len += sprintf(buf+len, "stsap_sel: %02x, ", self->stsap_sel);
- len += sprintf(buf+len, "dtsap_sel: %02x\n", self->dtsap_sel);
+ seq_printf(m, "\n IrDA state: %s, ", state);
+ seq_printf(m, "daddr: %08x, ", self->daddr);
+ seq_printf(m, "stsap_sel: %02x, ", self->stsap_sel);
+ seq_printf(m, "dtsap_sel: %02x\n", self->dtsap_sel);
/* Next socket, please... */
self = (irnet_socket *) hashbin_get_next(irnet_server.list);
@@ -1801,8 +1791,21 @@
/* Spin lock end */
spin_unlock_bh(&irnet_server.spinlock);
- return len;
+ return 0;
}
+
+static int irnet_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, irnet_proc_show, NULL);
+}
+
+static const struct file_operations irnet_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = irnet_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif /* PROC_FS */
@@ -1841,7 +1844,7 @@
#ifdef CONFIG_PROC_FS
/* Add a /proc file for irnet infos */
- create_proc_info_entry("irnet", 0, proc_irda, irnet_proc_read);
+ proc_create("irnet", 0, proc_irda, &irnet_proc_fops);
#endif /* CONFIG_PROC_FS */
/* Setup the IrNET server */
diff --git a/net/irda/irnet/irnet_irda.h b/net/irda/irnet/irnet_irda.h
index 0ba92d0..3e40895 100644
--- a/net/irda/irnet/irnet_irda.h
+++ b/net/irda/irnet/irnet_irda.h
@@ -159,14 +159,6 @@
DISCOVERY_MODE,
void *);
#endif
-/* -------------------------- PROC ENTRY -------------------------- */
-#ifdef CONFIG_PROC_FS
-static int
- irnet_proc_read(char *,
- char **,
- off_t,
- int);
-#endif /* CONFIG_PROC_FS */
/**************************** VARIABLES ****************************/
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 2403a31..9e7236f 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1498,7 +1498,8 @@
err = xfrm_state_update(x);
xfrm_audit_state_add(x, err ? 0 : 1,
- audit_get_loginuid(current), 0);
+ audit_get_loginuid(current),
+ audit_get_sessionid(current), 0);
if (err < 0) {
x->km.state = XFRM_STATE_DEAD;
@@ -1552,7 +1553,8 @@
km_state_notify(x, &c);
out:
xfrm_audit_state_delete(x, err ? 0 : 1,
- audit_get_loginuid(current), 0);
+ audit_get_loginuid(current),
+ audit_get_sessionid(current), 0);
xfrm_state_put(x);
return err;
@@ -1728,6 +1730,7 @@
return -EINVAL;
audit_info.loginuid = audit_get_loginuid(current);
+ audit_info.sessionid = audit_get_sessionid(current);
audit_info.secid = 0;
err = xfrm_state_flush(proto, &audit_info);
if (err)
@@ -2324,7 +2327,8 @@
hdr->sadb_msg_type != SADB_X_SPDUPDATE);
xfrm_audit_policy_add(xp, err ? 0 : 1,
- audit_get_loginuid(current), 0);
+ audit_get_loginuid(current),
+ audit_get_sessionid(current), 0);
if (err)
goto out;
@@ -2406,7 +2410,8 @@
return -ENOENT;
xfrm_audit_policy_delete(xp, err ? 0 : 1,
- audit_get_loginuid(current), 0);
+ audit_get_loginuid(current),
+ audit_get_sessionid(current), 0);
if (err)
goto out;
@@ -2667,7 +2672,8 @@
if (delete) {
xfrm_audit_policy_delete(xp, err ? 0 : 1,
- audit_get_loginuid(current), 0);
+ audit_get_loginuid(current),
+ audit_get_sessionid(current), 0);
if (err)
goto out;
@@ -2767,6 +2773,7 @@
int err;
audit_info.loginuid = audit_get_loginuid(current);
+ audit_info.sessionid = audit_get_sessionid(current);
audit_info.secid = 0;
err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info);
if (err)
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 4eac65c..c4b1799 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -104,7 +104,7 @@
const struct nf_conntrack_l3proto *l3proto,
const struct nf_conntrack_l4proto *l4proto)
{
- NF_CT_TUPLE_U_BLANK(tuple);
+ memset(tuple, 0, sizeof(*tuple));
tuple->src.l3num = l3num;
if (l3proto->pkt_to_tuple(skb, nhoff, tuple) == 0)
@@ -151,7 +151,7 @@
const struct nf_conntrack_l3proto *l3proto,
const struct nf_conntrack_l4proto *l4proto)
{
- NF_CT_TUPLE_U_BLANK(inverse);
+ memset(inverse, 0, sizeof(*inverse));
inverse->src.l3num = orig->src.l3num;
if (l3proto->invert_tuple(inverse, orig) == 0)
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
index bbd2689..582ec3e 100644
--- a/net/netfilter/nf_queue.c
+++ b/net/netfilter/nf_queue.c
@@ -214,7 +214,7 @@
segs = skb_gso_segment(skb, 0);
kfree_skb(skb);
- if (unlikely(IS_ERR(segs)))
+ if (IS_ERR(segs))
return 1;
do {
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 2c9fe5c..3447025 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -454,9 +454,8 @@
if (data_len > 0xFFFF)
return -EINVAL;
if (diff > skb_tailroom(e->skb)) {
- nskb = skb_copy_expand(e->skb, 0,
- diff - skb_tailroom(e->skb),
- GFP_ATOMIC);
+ nskb = skb_copy_expand(e->skb, skb_headroom(e->skb),
+ diff, GFP_ATOMIC);
if (!nskb) {
printk(KERN_WARNING "nf_queue: OOM "
"in mangle, dropping packet\n");
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index f52f7f8..11b22ab 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -787,7 +787,7 @@
.open = xt_table_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = seq_release_net,
};
static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
diff --git a/net/netfilter/xt_TCPOPTSTRIP.c b/net/netfilter/xt_TCPOPTSTRIP.c
index 3b2aa56..9685b6f 100644
--- a/net/netfilter/xt_TCPOPTSTRIP.c
+++ b/net/netfilter/xt_TCPOPTSTRIP.c
@@ -90,7 +90,7 @@
const struct xt_target *target, const void *targinfo)
{
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
- unsigned int tcphoff;
+ int tcphoff;
u_int8_t nexthdr;
nexthdr = ipv6h->nexthdr;
diff --git a/net/netfilter/xt_connbytes.c b/net/netfilter/xt_connbytes.c
index b15e7e2..d7e8983 100644
--- a/net/netfilter/xt_connbytes.c
+++ b/net/netfilter/xt_connbytes.c
@@ -4,12 +4,11 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/skbuff.h>
+#include <linux/math64.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_connbytes.h>
#include <net/netfilter/nf_conntrack.h>
-#include <asm/div64.h>
-
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("Xtables: Number of packets/bytes per connection matching");
@@ -82,7 +81,7 @@
break;
}
if (pkts != 0)
- what = div64_64(bytes, pkts);
+ what = div64_u64(bytes, pkts);
break;
}
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index d282ad1..0099da5b 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -1780,6 +1780,7 @@
* messages so don't worry to much about these values. */
security_task_getsecid(current, &audit_info.secid);
audit_info.loginuid = 0;
+ audit_info.sessionid = 0;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL)
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index b17d420..68706b4 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -107,7 +107,9 @@
if (audit_buf == NULL)
return NULL;
- audit_log_format(audit_buf, "netlabel: auid=%u", audit_info->loginuid);
+ audit_log_format(audit_buf, "netlabel: auid=%u ses=%u",
+ audit_info->loginuid,
+ audit_info->sessionid);
if (audit_info->secid != 0 &&
security_secid_to_secctx(audit_info->secid,
diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
index 6d7f4ab..6caef8b 100644
--- a/net/netlabel/netlabel_user.h
+++ b/net/netlabel/netlabel_user.h
@@ -51,6 +51,7 @@
{
audit_info->secid = NETLINK_CB(skb).sid;
audit_info->loginuid = NETLINK_CB(skb).loginuid;
+ audit_info->sessionid = NETLINK_CB(skb).sessionid;
}
/* NetLabel NETLINK I/O functions */
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 46f3e44..9b97f80 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1248,6 +1248,7 @@
NETLINK_CB(skb).pid = nlk->pid;
NETLINK_CB(skb).dst_group = dst_group;
NETLINK_CB(skb).loginuid = audit_get_loginuid(current);
+ NETLINK_CB(skb).sessionid = audit_get_sessionid(current);
security_task_getsecid(current, &(NETLINK_CB(skb).sid));
memcpy(NETLINK_CREDS(skb), &siocb->scm->creds, sizeof(struct ucred));
diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
index a20e2ef..f0463d7 100644
--- a/net/sched/sch_sfq.c
+++ b/net/sched/sch_sfq.c
@@ -521,7 +521,8 @@
struct sfq_sched_data *q = qdisc_priv(sch);
tcf_destroy_chain(q->filter_list);
- del_timer(&q->perturb_timer);
+ q->perturb_period = 0;
+ del_timer_sync(&q->perturb_timer);
}
static int sfq_dump(struct Qdisc *sch, struct sk_buff *skb)
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 2519129..09cd9c0 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -150,7 +150,7 @@
segs = skb_gso_segment(skb, 0);
kfree_skb(skb);
- if (unlikely(IS_ERR(segs)))
+ if (IS_ERR(segs))
return PTR_ERR(segs);
do {
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index e0c0390..cae9fd8 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -762,6 +762,7 @@
if (err) {
xfrm_audit_policy_delete(pol, 0,
audit_info->loginuid,
+ audit_info->sessionid,
audit_info->secid);
return err;
}
@@ -777,6 +778,7 @@
if (err) {
xfrm_audit_policy_delete(pol, 0,
audit_info->loginuid,
+ audit_info->sessionid,
audit_info->secid);
return err;
}
@@ -819,6 +821,7 @@
write_unlock_bh(&xfrm_policy_lock);
xfrm_audit_policy_delete(pol, 1, audit_info->loginuid,
+ audit_info->sessionid,
audit_info->secid);
xfrm_policy_kill(pol);
@@ -841,6 +844,7 @@
xfrm_audit_policy_delete(pol, 1,
audit_info->loginuid,
+ audit_info->sessionid,
audit_info->secid);
xfrm_policy_kill(pol);
killed++;
@@ -2472,14 +2476,14 @@
}
void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
- u32 auid, u32 secid)
+ uid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
audit_buf = xfrm_audit_start("SPD-add");
if (audit_buf == NULL)
return;
- xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
+ xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
xfrm_audit_common_policyinfo(xp, audit_buf);
audit_log_end(audit_buf);
@@ -2487,14 +2491,14 @@
EXPORT_SYMBOL_GPL(xfrm_audit_policy_add);
void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
- u32 auid, u32 secid)
+ uid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
audit_buf = xfrm_audit_start("SPD-delete");
if (audit_buf == NULL)
return;
- xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
+ xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
xfrm_audit_common_policyinfo(xp, audit_buf);
audit_log_end(audit_buf);
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index fac27ce..72fddaf 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -496,7 +496,8 @@
km_state_expired(x, 1, 0);
xfrm_audit_state_delete(x, err ? 0 : 1,
- audit_get_loginuid(current), 0);
+ audit_get_loginuid(current),
+ audit_get_sessionid(current), 0);
out:
spin_unlock(&x->lock);
@@ -603,6 +604,7 @@
(err = security_xfrm_state_delete(x)) != 0) {
xfrm_audit_state_delete(x, 0,
audit_info->loginuid,
+ audit_info->sessionid,
audit_info->secid);
return err;
}
@@ -641,6 +643,7 @@
err = xfrm_state_delete(x);
xfrm_audit_state_delete(x, err ? 0 : 1,
audit_info->loginuid,
+ audit_info->sessionid,
audit_info->secid);
xfrm_state_put(x);
@@ -2123,14 +2126,14 @@
}
void xfrm_audit_state_add(struct xfrm_state *x, int result,
- u32 auid, u32 secid)
+ uid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
audit_buf = xfrm_audit_start("SAD-add");
if (audit_buf == NULL)
return;
- xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
+ xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
xfrm_audit_helper_sainfo(x, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
audit_log_end(audit_buf);
@@ -2138,14 +2141,14 @@
EXPORT_SYMBOL_GPL(xfrm_audit_state_add);
void xfrm_audit_state_delete(struct xfrm_state *x, int result,
- u32 auid, u32 secid)
+ uid_t auid, u32 sessionid, u32 secid)
{
struct audit_buffer *audit_buf;
audit_buf = xfrm_audit_start("SAD-delete");
if (audit_buf == NULL)
return;
- xfrm_audit_helper_usrinfo(auid, secid, audit_buf);
+ xfrm_audit_helper_usrinfo(auid, sessionid, secid, audit_buf);
xfrm_audit_helper_sainfo(x, audit_buf);
audit_log_format(audit_buf, " res=%u", result);
audit_log_end(audit_buf);
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 22a30ae..a1b0fbe 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -407,6 +407,9 @@
struct xfrm_state *x;
int err;
struct km_event c;
+ uid_t loginuid = NETLINK_CB(skb).loginuid;
+ u32 sessionid = NETLINK_CB(skb).sessionid;
+ u32 sid = NETLINK_CB(skb).sid;
err = verify_newsa_info(p, attrs);
if (err)
@@ -422,8 +425,7 @@
else
err = xfrm_state_update(x);
- xfrm_audit_state_add(x, err ? 0 : 1, NETLINK_CB(skb).loginuid,
- NETLINK_CB(skb).sid);
+ xfrm_audit_state_add(x, err ? 0 : 1, loginuid, sessionid, sid);
if (err < 0) {
x->km.state = XFRM_STATE_DEAD;
@@ -478,6 +480,9 @@
int err = -ESRCH;
struct km_event c;
struct xfrm_usersa_id *p = nlmsg_data(nlh);
+ uid_t loginuid = NETLINK_CB(skb).loginuid;
+ u32 sessionid = NETLINK_CB(skb).sessionid;
+ u32 sid = NETLINK_CB(skb).sid;
x = xfrm_user_state_lookup(p, attrs, &err);
if (x == NULL)
@@ -502,8 +507,7 @@
km_state_notify(x, &c);
out:
- xfrm_audit_state_delete(x, err ? 0 : 1, NETLINK_CB(skb).loginuid,
- NETLINK_CB(skb).sid);
+ xfrm_audit_state_delete(x, err ? 0 : 1, loginuid, sessionid, sid);
xfrm_state_put(x);
return err;
}
@@ -1123,6 +1127,9 @@
struct km_event c;
int err;
int excl;
+ uid_t loginuid = NETLINK_CB(skb).loginuid;
+ u32 sessionid = NETLINK_CB(skb).sessionid;
+ u32 sid = NETLINK_CB(skb).sid;
err = verify_newpolicy_info(p);
if (err)
@@ -1141,8 +1148,7 @@
* a type XFRM_MSG_UPDPOLICY - JHS */
excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY;
err = xfrm_policy_insert(p->dir, xp, excl);
- xfrm_audit_policy_add(xp, err ? 0 : 1, NETLINK_CB(skb).loginuid,
- NETLINK_CB(skb).sid);
+ xfrm_audit_policy_add(xp, err ? 0 : 1, loginuid, sessionid, sid);
if (err) {
security_xfrm_policy_free(xp->security);
@@ -1371,9 +1377,12 @@
NETLINK_CB(skb).pid);
}
} else {
- xfrm_audit_policy_delete(xp, err ? 0 : 1,
- NETLINK_CB(skb).loginuid,
- NETLINK_CB(skb).sid);
+ uid_t loginuid = NETLINK_CB(skb).loginuid;
+ u32 sessionid = NETLINK_CB(skb).sessionid;
+ u32 sid = NETLINK_CB(skb).sid;
+
+ xfrm_audit_policy_delete(xp, err ? 0 : 1, loginuid, sessionid,
+ sid);
if (err != 0)
goto out;
@@ -1399,6 +1408,7 @@
int err;
audit_info.loginuid = NETLINK_CB(skb).loginuid;
+ audit_info.sessionid = NETLINK_CB(skb).sessionid;
audit_info.secid = NETLINK_CB(skb).sid;
err = xfrm_state_flush(p->proto, &audit_info);
if (err)
@@ -1546,6 +1556,7 @@
return err;
audit_info.loginuid = NETLINK_CB(skb).loginuid;
+ audit_info.sessionid = NETLINK_CB(skb).sessionid;
audit_info.secid = NETLINK_CB(skb).sid;
err = xfrm_policy_flush(type, &audit_info);
if (err)
@@ -1604,9 +1615,11 @@
read_unlock(&xp->lock);
err = 0;
if (up->hard) {
+ uid_t loginuid = NETLINK_CB(skb).loginuid;
+ uid_t sessionid = NETLINK_CB(skb).sessionid;
+ u32 sid = NETLINK_CB(skb).sid;
xfrm_policy_delete(xp, p->dir);
- xfrm_audit_policy_delete(xp, 1, NETLINK_CB(skb).loginuid,
- NETLINK_CB(skb).sid);
+ xfrm_audit_policy_delete(xp, 1, loginuid, sessionid, sid);
} else {
// reset the timers here?
@@ -1640,9 +1653,11 @@
km_state_expired(x, ue->hard, current->pid);
if (ue->hard) {
+ uid_t loginuid = NETLINK_CB(skb).loginuid;
+ uid_t sessionid = NETLINK_CB(skb).sessionid;
+ u32 sid = NETLINK_CB(skb).sid;
__xfrm_state_delete(x);
- xfrm_audit_state_delete(x, 1, NETLINK_CB(skb).loginuid,
- NETLINK_CB(skb).sid);
+ xfrm_audit_state_delete(x, 1, loginuid, sessionid, sid);
}
err = 0;
out:
diff --git a/samples/markers/marker-example.c b/samples/markers/marker-example.c
index 05e438f..e90dc5d 100644
--- a/samples/markers/marker-example.c
+++ b/samples/markers/marker-example.c
@@ -33,10 +33,8 @@
static int example_init(void)
{
printk(KERN_ALERT "example init\n");
- pentry_example = create_proc_entry("marker-example", 0444, NULL);
- if (pentry_example)
- pentry_example->proc_fops = &mark_ops;
- else
+ pentry_example = proc_create("marker-example", 0444, NULL, &mark_ops);
+ if (!pentry_example)
return -EPERM;
return 0;
}
diff --git a/scripts/Lindent b/scripts/Lindent
index 9468ec7..9c4b3e2 100755
--- a/scripts/Lindent
+++ b/scripts/Lindent
@@ -1,2 +1,18 @@
#!/bin/sh
-indent -npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1 "$@"
+PARAM="-npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1"
+RES=`indent --version`
+V1=`echo $RES | cut -d' ' -f3 | cut -d'.' -f1`
+V2=`echo $RES | cut -d' ' -f3 | cut -d'.' -f2`
+V3=`echo $RES | cut -d' ' -f3 | cut -d'.' -f3`
+if [ $V1 -gt 2 ]; then
+ PARAM="$PARAM -il0"
+elif [ $V1 -eq 2 ]; then
+ if [ $V2 -gt 2 ]; then
+ PARAM="$PARAM -il0";
+ elif [ $V2 -eq 2 ]; then
+ if [ $V3 -ge 10 ]; then
+ PARAM="$PARAM -il0"
+ fi
+ fi
+fi
+indent $PARAM "$@"
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 64ec4b8..b6bbbcd 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -9,7 +9,7 @@
my $P = $0;
$P =~ s@.*/@@g;
-my $V = '0.16';
+my $V = '0.18';
use Getopt::Long qw(:config no_auto_abbrev);
@@ -131,6 +131,17 @@
our $Type;
our $Declare;
+our $UTF8 = qr {
+ [\x09\x0A\x0D\x20-\x7E] # ASCII
+ | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
+ | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
+ | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
+ | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
+ | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
+ | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
+ | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
+}x;
+
our @typeList = (
qr{void},
qr{char},
@@ -692,7 +703,7 @@
while (length($cur)) {
@av_paren_type = ('E') if ($#av_paren_type < 0);
print " <" . join('', @av_paren_type) .
- "> <$type> " if ($dbg_values > 1);
+ "> <$type> <$av_pending>" if ($dbg_values > 1);
if ($cur =~ /^(\s+)/o) {
print "WS($1)\n" if ($dbg_values > 1);
if ($1 =~ /\n/ && $av_preprocessor) {
@@ -705,9 +716,18 @@
$type = 'T';
} elsif ($cur =~ /^(#\s*define\s*$Ident)(\(?)/o) {
- print "DEFINE($1)\n" if ($dbg_values > 1);
+ print "DEFINE($1,$2)\n" if ($dbg_values > 1);
$av_preprocessor = 1;
- $av_pending = 'N';
+ push(@av_paren_type, $type);
+ if ($2 ne '') {
+ $av_pending = 'N';
+ }
+ $type = 'E';
+
+ } elsif ($cur =~ /^(#\s*undef\s*$Ident)/o) {
+ print "UNDEF($1)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+ push(@av_paren_type, $type);
} elsif ($cur =~ /^(#\s*(?:ifdef|ifndef|if))/o) {
print "PRE_START($1)\n" if ($dbg_values > 1);
@@ -715,7 +735,7 @@
push(@av_paren_type, $type);
push(@av_paren_type, $type);
- $type = 'N';
+ $type = 'E';
} elsif ($cur =~ /^(#\s*(?:else|elif))/o) {
print "PRE_RESTART($1)\n" if ($dbg_values > 1);
@@ -723,7 +743,7 @@
push(@av_paren_type, $av_paren_type[$#av_paren_type]);
- $type = 'N';
+ $type = 'E';
} elsif ($cur =~ /^(#\s*(?:endif))/o) {
print "PRE_END($1)\n" if ($dbg_values > 1);
@@ -734,11 +754,16 @@
# one does, and continue as if the #endif was not here.
pop(@av_paren_type);
push(@av_paren_type, $type);
- $type = 'N';
+ $type = 'E';
} elsif ($cur =~ /^(\\\n)/o) {
print "PRECONT($1)\n" if ($dbg_values > 1);
+ } elsif ($cur =~ /^(__attribute__)\s*\(?/o) {
+ print "ATTR($1)\n" if ($dbg_values > 1);
+ $av_pending = $type;
+ $type = 'N';
+
} elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
print "SIZEOF($1)\n" if ($dbg_values > 1);
if (defined $2) {
@@ -930,7 +955,7 @@
# edge is a close comment then we must be in a comment
# at context start.
my $edge;
- for (my $ln = $linenr; $ln < ($linenr + $realcnt); $ln++) {
+ for (my $ln = $linenr + 1; $ln < ($linenr + $realcnt); $ln++) {
next if ($line =~ /^-/);
($edge) = ($rawlines[$ln - 1] =~ m@(/\*|\*/)@);
last if (defined $edge);
@@ -951,9 +976,9 @@
##print "COMMENT:$in_comment edge<$edge> $rawline\n";
sanitise_line_reset($in_comment);
- } elsif ($realcnt) {
+ } elsif ($realcnt && $rawline =~ /^(?:\+| |$)/) {
# Standardise the strings and chars within the input to
- # simplify matching.
+ # simplify matching -- only bother with positive lines.
$line = sanitise_line($rawline);
}
push(@lines, $line);
@@ -1066,17 +1091,14 @@
# UTF-8 regex found at http://www.w3.org/International/questions/qa-forms-utf-8.en.php
if (($realfile =~ /^$/ || $line =~ /^\+/) &&
- !($rawline =~ m/^(
- [\x09\x0A\x0D\x20-\x7E] # ASCII
- | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
- | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
- | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
- | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
- | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
- | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
- | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
- )*$/x )) {
- ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $herecurr);
+ $rawline !~ m/^$UTF8*$/) {
+ my ($utf8_prefix) = ($rawline =~ /^($UTF8*)/);
+
+ my $blank = copy_spacing($rawline);
+ my $ptr = substr($blank, 0, length($utf8_prefix)) . "^";
+ my $hereptr = "$hereline$ptr\n";
+
+ ERROR("Invalid UTF-8, patch and commit message should be encoded in UTF-8\n" . $hereptr);
}
#ignore lines being removed
@@ -1112,7 +1134,7 @@
if ($rawline =~ /^\+\s* \t\s*\S/ ||
$rawline =~ /^\+\s* \s*/) {
my $herevet = "$here\n" . cat_vet($rawline) . "\n";
- ERROR("use tabs not spaces\n" . $herevet);
+ ERROR("code indent should use tabs where possible\n" . $herevet);
}
# check for RCS/CVS revision markers
@@ -1121,35 +1143,40 @@
}
# Check for potential 'bare' types
- if ($realcnt) {
- my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
- $s =~ s/\n./ /g;
- $s =~ s/{.*$//;
+ my ($stat, $cond);
+ if ($realcnt && $line =~ /.\s*\S/) {
+ ($stat, $cond) = ctx_statement_block($linenr,
+ $realcnt, 0);
+ $stat =~ s/\n./\n /g;
+ $cond =~ s/\n./\n /g;
+
+ my $s = $stat;
+ $s =~ s/{.*$//s;
# Ignore goto labels.
- if ($s =~ /$Ident:\*$/) {
+ if ($s =~ /$Ident:\*$/s) {
# Ignore functions being called
- } elsif ($s =~ /^.\s*$Ident\s*\(/) {
+ } elsif ($s =~ /^.\s*$Ident\s*\(/s) {
# definitions in global scope can only start with types
- } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b/) {
+ } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b/s) {
possible($1, $s);
# declarations always start with types
- } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:const\s+)?($Ident)\b(:?\s+$Sparse)?\s*\**\s*$Ident\s*(?:;|=|,)/) {
+ } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:const\s+)?($Ident)\b(:?\s+$Sparse)?\s*\**\s*$Ident\s*(?:;|=|,)/s) {
possible($1, $s);
}
# any (foo ... *) is a pointer cast, and foo is a type
- while ($s =~ /\(($Ident)(?:\s+$Sparse)*\s*\*+\s*\)/g) {
+ while ($s =~ /\(($Ident)(?:\s+$Sparse)*\s*\*+\s*\)/sg) {
possible($1, $s);
}
# Check for any sort of function declaration.
# int foo(something bar, other baz);
# void (*store_gdt)(x86_descr_ptr *);
- if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/) {
+ if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/s) {
my ($name_len) = length($1);
my $ctx = $s;
@@ -1282,18 +1309,19 @@
($prevline !~ /^ }/) &&
($prevline !~ /^.DECLARE_$Ident\(\Q$name\E\)/) &&
($prevline !~ /^.LIST_HEAD\(\Q$name\E\)/) &&
+ ($prevline !~ /^.$Type\s*\(\s*\*\s*\Q$name\E\s*\)\s*\(/) &&
($prevline !~ /\b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[)/)) {
WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
}
}
# check for external initialisers.
- if ($line =~ /^.$Type\s*$Ident\s*=\s*(0|NULL);/) {
+ if ($line =~ /^.$Type\s*$Ident\s*=\s*(0|NULL|false)\s*;/) {
ERROR("do not initialise externals to 0 or NULL\n" .
$herecurr);
}
# check for static initialisers.
- if ($line =~ /\s*static\s.*=\s*(0|NULL);/) {
+ if ($line =~ /\s*static\s.*=\s*(0|NULL|false)\s*;/) {
ERROR("do not initialise statics to 0 or NULL\n" .
$herecurr);
}
@@ -1512,7 +1540,10 @@
if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
ERROR("space required before that '$op' $at\n" . $hereptr);
}
- if ($ctx =~ /.xW/) {
+ if ($op eq '*' && $cc =~/\s*const\b/) {
+ # A unary '*' may be const
+
+ } elsif ($ctx =~ /.xW/) {
ERROR("space prohibited after that '$op' $at\n" . $hereptr);
}
@@ -1617,7 +1648,7 @@
# Check for illegal assignment in if conditional.
if ($line =~ /\bif\s*\(/) {
- my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
+ my ($s, $c) = ($stat, $cond);
if ($c =~ /\bif\s*\(.*[^<>!=]=[^=].*/) {
ERROR("do not use assignment in if condition\n" . $herecurr);
@@ -1695,7 +1726,7 @@
#warn if <asm/foo.h> is #included and <linux/foo.h> is available (uses RAW line)
if ($tree && $rawline =~ m{^.\#\s*include\s*\<asm\/(.*)\.h\>}) {
my $checkfile = "$root/include/linux/$1.h";
- if (-f $checkfile && $1 ne 'irq.h') {
+ if (-f $checkfile && $1 ne 'irq') {
WARN("Use #include <linux/$1.h> instead of <asm/$1.h>\n" .
$herecurr);
}
@@ -1910,7 +1941,8 @@
}
# check for spinlock_t definitions without a comment.
- if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/) {
+ if ($line =~ /^.\s*(struct\s+mutex|spinlock_t)\s+\S+;/ ||
+ $line =~ /^.\s*(DEFINE_MUTEX)\s*\(/) {
my $which = $1;
if (!ctx_has_comment($first_line, $linenr)) {
CHK("$1 definition without comment\n" . $herecurr);
@@ -1940,7 +1972,26 @@
}
# check for new externs in .c files.
- if ($line =~ /^.\s*extern\s/ && ($realfile =~ /\.c$/)) {
+ if ($realfile =~ /\.c$/ && defined $stat &&
+ $stat =~ /^.\s*(?:extern\s+)?$Type\s+$Ident(\s*)\(/s)
+ {
+ my $paren_space = $1;
+
+ my $s = $stat;
+ if (defined $cond) {
+ substr($s, 0, length($cond), '');
+ }
+ if ($s =~ /^\s*;/) {
+ WARN("externs should be avoided in .c files\n" . $herecurr);
+ }
+
+ if ($paren_space =~ /\n/) {
+ WARN("arguments for function declarations should follow identifier\n" . $herecurr);
+ }
+
+ } elsif ($realfile =~ /\.c$/ && defined $stat &&
+ $stat =~ /^.\s*extern\s+/)
+ {
WARN("externs should be avoided in .c files\n" . $herecurr);
}
@@ -1964,11 +2015,11 @@
}
# check for semaphores used as mutexes
- if ($line =~ /\b(DECLARE_MUTEX|init_MUTEX)\s*\(/) {
+ if ($line =~ /^.\s*(DECLARE_MUTEX|init_MUTEX)\s*\(/) {
WARN("mutexes are preferred for single holder semaphores\n" . $herecurr);
}
# check for semaphores used as mutexes
- if ($line =~ /\binit_MUTEX_LOCKED\s*\(/) {
+ if ($line =~ /^.\s*init_MUTEX_LOCKED\s*\(/) {
WARN("consider using a completion\n" . $herecurr);
}
# recommend strict_strto* over simple_strto*
@@ -1979,11 +2030,24 @@
# use of NR_CPUS is usually wrong
# ignore definitions of NR_CPUS and usage to define arrays as likely right
if ($line =~ /\bNR_CPUS\b/ &&
- $line !~ /^.#\s*define\s+NR_CPUS\s+/ &&
- $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/)
+ $line !~ /^.#\s*if\b.*\bNR_CPUS\b/ &&
+ $line !~ /^.#\s*define\b.*\bNR_CPUS\b/ &&
+ $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/ &&
+ $line !~ /\[[^\]]*\.\.\.[^\]]*NR_CPUS[^\]]*\]/ &&
+ $line !~ /\[[^\]]*NR_CPUS[^\]]*\.\.\.[^\]]*\]/)
{
WARN("usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
}
+
+# check for %L{u,d,i} in strings
+ my $string;
+ while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
+ $string = substr($rawline, $-[1], $+[1] - $-[1]);
+ if ($string =~ /(?<!%)%L[udi]/) {
+ WARN("\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
+ last;
+ }
+ }
}
# If we have no input at all, then there is nothing to report on
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
index c912137..5d20a2e 100644
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -7,12 +7,6 @@
*
* Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S
*
- * ChangeLog:
- *
- * (25/Aug/2004) Paulo Marques <pmarques@grupopie.com>
- * Changed the compression method from stem compression to "table lookup"
- * compression
- *
* Table compression uses all the unused char codes on the symbols and
* maps these to the most used substrings (tokens). For instance, it might
* map char code 0xF7 to represent "write_" and then in every symbol where
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh
index 62e1e02..5552154 100644
--- a/scripts/kconfig/lxdialog/check-lxdialog.sh
+++ b/scripts/kconfig/lxdialog/check-lxdialog.sh
@@ -36,8 +36,10 @@
# Check if we can link to ncurses
check() {
- echo -e " #include CURSES_LOC \n main() {}" |
- $cc -xc - -o $tmp 2> /dev/null
+ $cc -xc - -o $tmp 2>/dev/null <<'EOF'
+#include CURSES_LOC
+main() {}
+EOF
if [ $? != 0 ]; then
echo " *** Unable to find the ncurses libraries or the" 1>&2
echo " *** required header files." 1>&2
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 769b69d..e04c4218 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -576,6 +576,15 @@
return 1;
}
+/* Looks like: i2c:S */
+static int do_i2c_entry(const char *filename, struct i2c_device_id *id,
+ char *alias)
+{
+ sprintf(alias, I2C_MODULE_PREFIX "%s", id->name);
+
+ return 1;
+}
+
/* Ignore any prefix, eg. v850 prepends _ */
static inline int sym_is(const char *symbol, const char *name)
{
@@ -704,6 +713,10 @@
do_table(symval, sym->st_size,
sizeof(struct virtio_device_id), "virtio",
do_virtio_entry, mod);
+ else if (sym_is(symname, "__mod_i2c_device_table"))
+ do_table(symval, sym->st_size,
+ sizeof(struct i2c_device_id), "i2c",
+ do_i2c_entry, mod);
free(zeros);
}
diff --git a/security/Makefile b/security/Makefile
index 9e8b025..7ef1107 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -18,3 +18,4 @@
obj-$(CONFIG_SECURITY_SMACK) += commoncap.o smack/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
+obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o
diff --git a/security/commoncap.c b/security/commoncap.c
index e8c3f5e..5edabc7 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -383,8 +383,8 @@
current->egid != current->gid);
}
-int cap_inode_setxattr(struct dentry *dentry, char *name, void *value,
- size_t size, int flags)
+int cap_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
if (!strcmp(name, XATTR_NAME_CAPS)) {
if (!capable(CAP_SETFCAP))
@@ -397,7 +397,7 @@
return 0;
}
-int cap_inode_removexattr(struct dentry *dentry, char *name)
+int cap_inode_removexattr(struct dentry *dentry, const char *name)
{
if (!strcmp(name, XATTR_NAME_CAPS)) {
if (!capable(CAP_SETFCAP))
diff --git a/security/device_cgroup.c b/security/device_cgroup.c
new file mode 100644
index 0000000..4ea5836
--- /dev/null
+++ b/security/device_cgroup.c
@@ -0,0 +1,575 @@
+/*
+ * dev_cgroup.c - device cgroup subsystem
+ *
+ * Copyright 2007 IBM Corp
+ */
+
+#include <linux/device_cgroup.h>
+#include <linux/cgroup.h>
+#include <linux/ctype.h>
+#include <linux/list.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+
+#define ACC_MKNOD 1
+#define ACC_READ 2
+#define ACC_WRITE 4
+#define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE)
+
+#define DEV_BLOCK 1
+#define DEV_CHAR 2
+#define DEV_ALL 4 /* this represents all devices */
+
+/*
+ * whitelist locking rules:
+ * cgroup_lock() cannot be taken under dev_cgroup->lock.
+ * dev_cgroup->lock can be taken with or without cgroup_lock().
+ *
+ * modifications always require cgroup_lock
+ * modifications to a list which is visible require the
+ * dev_cgroup->lock *and* cgroup_lock()
+ * walking the list requires dev_cgroup->lock or cgroup_lock().
+ *
+ * reasoning: dev_whitelist_copy() needs to kmalloc, so needs
+ * a mutex, which the cgroup_lock() is. Since modifying
+ * a visible list requires both locks, either lock can be
+ * taken for walking the list.
+ */
+
+struct dev_whitelist_item {
+ u32 major, minor;
+ short type;
+ short access;
+ struct list_head list;
+};
+
+struct dev_cgroup {
+ struct cgroup_subsys_state css;
+ struct list_head whitelist;
+ spinlock_t lock;
+};
+
+static inline struct dev_cgroup *cgroup_to_devcgroup(struct cgroup *cgroup)
+{
+ return container_of(cgroup_subsys_state(cgroup, devices_subsys_id),
+ struct dev_cgroup, css);
+}
+
+struct cgroup_subsys devices_subsys;
+
+static int devcgroup_can_attach(struct cgroup_subsys *ss,
+ struct cgroup *new_cgroup, struct task_struct *task)
+{
+ if (current != task && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ return 0;
+}
+
+/*
+ * called under cgroup_lock()
+ */
+static int dev_whitelist_copy(struct list_head *dest, struct list_head *orig)
+{
+ struct dev_whitelist_item *wh, *tmp, *new;
+
+ list_for_each_entry(wh, orig, list) {
+ new = kmalloc(sizeof(*wh), GFP_KERNEL);
+ if (!new)
+ goto free_and_exit;
+ new->major = wh->major;
+ new->minor = wh->minor;
+ new->type = wh->type;
+ new->access = wh->access;
+ list_add_tail(&new->list, dest);
+ }
+
+ return 0;
+
+free_and_exit:
+ list_for_each_entry_safe(wh, tmp, dest, list) {
+ list_del(&wh->list);
+ kfree(wh);
+ }
+ return -ENOMEM;
+}
+
+/* Stupid prototype - don't bother combining existing entries */
+/*
+ * called under cgroup_lock()
+ * since the list is visible to other tasks, we need the spinlock also
+ */
+static int dev_whitelist_add(struct dev_cgroup *dev_cgroup,
+ struct dev_whitelist_item *wh)
+{
+ struct dev_whitelist_item *whcopy;
+
+ whcopy = kmalloc(sizeof(*whcopy), GFP_KERNEL);
+ if (!whcopy)
+ return -ENOMEM;
+
+ memcpy(whcopy, wh, sizeof(*whcopy));
+ spin_lock(&dev_cgroup->lock);
+ list_add_tail(&whcopy->list, &dev_cgroup->whitelist);
+ spin_unlock(&dev_cgroup->lock);
+ return 0;
+}
+
+/*
+ * called under cgroup_lock()
+ * since the list is visible to other tasks, we need the spinlock also
+ */
+static void dev_whitelist_rm(struct dev_cgroup *dev_cgroup,
+ struct dev_whitelist_item *wh)
+{
+ struct dev_whitelist_item *walk, *tmp;
+
+ spin_lock(&dev_cgroup->lock);
+ list_for_each_entry_safe(walk, tmp, &dev_cgroup->whitelist, list) {
+ if (walk->type == DEV_ALL)
+ goto remove;
+ if (walk->type != wh->type)
+ continue;
+ if (walk->major != ~0 && walk->major != wh->major)
+ continue;
+ if (walk->minor != ~0 && walk->minor != wh->minor)
+ continue;
+
+remove:
+ walk->access &= ~wh->access;
+ if (!walk->access) {
+ list_del(&walk->list);
+ kfree(walk);
+ }
+ }
+ spin_unlock(&dev_cgroup->lock);
+}
+
+/*
+ * called from kernel/cgroup.c with cgroup_lock() held.
+ */
+static struct cgroup_subsys_state *devcgroup_create(struct cgroup_subsys *ss,
+ struct cgroup *cgroup)
+{
+ struct dev_cgroup *dev_cgroup, *parent_dev_cgroup;
+ struct cgroup *parent_cgroup;
+ int ret;
+
+ dev_cgroup = kzalloc(sizeof(*dev_cgroup), GFP_KERNEL);
+ if (!dev_cgroup)
+ return ERR_PTR(-ENOMEM);
+ INIT_LIST_HEAD(&dev_cgroup->whitelist);
+ parent_cgroup = cgroup->parent;
+
+ if (parent_cgroup == NULL) {
+ struct dev_whitelist_item *wh;
+ wh = kmalloc(sizeof(*wh), GFP_KERNEL);
+ if (!wh) {
+ kfree(dev_cgroup);
+ return ERR_PTR(-ENOMEM);
+ }
+ wh->minor = wh->major = ~0;
+ wh->type = DEV_ALL;
+ wh->access = ACC_MKNOD | ACC_READ | ACC_WRITE;
+ list_add(&wh->list, &dev_cgroup->whitelist);
+ } else {
+ parent_dev_cgroup = cgroup_to_devcgroup(parent_cgroup);
+ ret = dev_whitelist_copy(&dev_cgroup->whitelist,
+ &parent_dev_cgroup->whitelist);
+ if (ret) {
+ kfree(dev_cgroup);
+ return ERR_PTR(ret);
+ }
+ }
+
+ spin_lock_init(&dev_cgroup->lock);
+ return &dev_cgroup->css;
+}
+
+static void devcgroup_destroy(struct cgroup_subsys *ss,
+ struct cgroup *cgroup)
+{
+ struct dev_cgroup *dev_cgroup;
+ struct dev_whitelist_item *wh, *tmp;
+
+ dev_cgroup = cgroup_to_devcgroup(cgroup);
+ list_for_each_entry_safe(wh, tmp, &dev_cgroup->whitelist, list) {
+ list_del(&wh->list);
+ kfree(wh);
+ }
+ kfree(dev_cgroup);
+}
+
+#define DEVCG_ALLOW 1
+#define DEVCG_DENY 2
+#define DEVCG_LIST 3
+
+#define MAJMINLEN 10
+#define ACCLEN 4
+
+static void set_access(char *acc, short access)
+{
+ int idx = 0;
+ memset(acc, 0, ACCLEN);
+ if (access & ACC_READ)
+ acc[idx++] = 'r';
+ if (access & ACC_WRITE)
+ acc[idx++] = 'w';
+ if (access & ACC_MKNOD)
+ acc[idx++] = 'm';
+}
+
+static char type_to_char(short type)
+{
+ if (type == DEV_ALL)
+ return 'a';
+ if (type == DEV_CHAR)
+ return 'c';
+ if (type == DEV_BLOCK)
+ return 'b';
+ return 'X';
+}
+
+static void set_majmin(char *str, unsigned m)
+{
+ memset(str, 0, MAJMINLEN);
+ if (m == ~0)
+ sprintf(str, "*");
+ else
+ snprintf(str, MAJMINLEN, "%d", m);
+}
+
+static int devcgroup_seq_read(struct cgroup *cgroup, struct cftype *cft,
+ struct seq_file *m)
+{
+ struct dev_cgroup *devcgroup = cgroup_to_devcgroup(cgroup);
+ struct dev_whitelist_item *wh;
+ char maj[MAJMINLEN], min[MAJMINLEN], acc[ACCLEN];
+
+ spin_lock(&devcgroup->lock);
+ list_for_each_entry(wh, &devcgroup->whitelist, list) {
+ set_access(acc, wh->access);
+ set_majmin(maj, wh->major);
+ set_majmin(min, wh->minor);
+ seq_printf(m, "%c %s:%s %s\n", type_to_char(wh->type),
+ maj, min, acc);
+ }
+ spin_unlock(&devcgroup->lock);
+
+ return 0;
+}
+
+/*
+ * may_access_whitelist:
+ * does the access granted to dev_cgroup c contain the access
+ * requested in whitelist item refwh.
+ * return 1 if yes, 0 if no.
+ * call with c->lock held
+ */
+static int may_access_whitelist(struct dev_cgroup *c,
+ struct dev_whitelist_item *refwh)
+{
+ struct dev_whitelist_item *whitem;
+
+ list_for_each_entry(whitem, &c->whitelist, list) {
+ if (whitem->type & DEV_ALL)
+ return 1;
+ if ((refwh->type & DEV_BLOCK) && !(whitem->type & DEV_BLOCK))
+ continue;
+ if ((refwh->type & DEV_CHAR) && !(whitem->type & DEV_CHAR))
+ continue;
+ if (whitem->major != ~0 && whitem->major != refwh->major)
+ continue;
+ if (whitem->minor != ~0 && whitem->minor != refwh->minor)
+ continue;
+ if (refwh->access & (~(whitem->access | ACC_MASK)))
+ continue;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * parent_has_perm:
+ * when adding a new allow rule to a device whitelist, the rule
+ * must be allowed in the parent device
+ */
+static int parent_has_perm(struct cgroup *childcg,
+ struct dev_whitelist_item *wh)
+{
+ struct cgroup *pcg = childcg->parent;
+ struct dev_cgroup *parent;
+ int ret;
+
+ if (!pcg)
+ return 1;
+ parent = cgroup_to_devcgroup(pcg);
+ spin_lock(&parent->lock);
+ ret = may_access_whitelist(parent, wh);
+ spin_unlock(&parent->lock);
+ return ret;
+}
+
+/*
+ * Modify the whitelist using allow/deny rules.
+ * CAP_SYS_ADMIN is needed for this. It's at least separate from CAP_MKNOD
+ * so we can give a container CAP_MKNOD to let it create devices but not
+ * modify the whitelist.
+ * It seems likely we'll want to add a CAP_CONTAINER capability to allow
+ * us to also grant CAP_SYS_ADMIN to containers without giving away the
+ * device whitelist controls, but for now we'll stick with CAP_SYS_ADMIN
+ *
+ * Taking rules away is always allowed (given CAP_SYS_ADMIN). Granting
+ * new access is only allowed if you're in the top-level cgroup, or your
+ * parent cgroup has the access you're asking for.
+ */
+static ssize_t devcgroup_access_write(struct cgroup *cgroup, struct cftype *cft,
+ struct file *file, const char __user *userbuf,
+ size_t nbytes, loff_t *ppos)
+{
+ struct cgroup *cur_cgroup;
+ struct dev_cgroup *devcgroup, *cur_devcgroup;
+ int filetype = cft->private;
+ char *buffer, *b;
+ int retval = 0, count;
+ struct dev_whitelist_item wh;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ devcgroup = cgroup_to_devcgroup(cgroup);
+ cur_cgroup = task_cgroup(current, devices_subsys.subsys_id);
+ cur_devcgroup = cgroup_to_devcgroup(cur_cgroup);
+
+ buffer = kmalloc(nbytes+1, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ if (copy_from_user(buffer, userbuf, nbytes)) {
+ retval = -EFAULT;
+ goto out1;
+ }
+ buffer[nbytes] = 0; /* nul-terminate */
+
+ cgroup_lock();
+ if (cgroup_is_removed(cgroup)) {
+ retval = -ENODEV;
+ goto out2;
+ }
+
+ memset(&wh, 0, sizeof(wh));
+ b = buffer;
+
+ switch (*b) {
+ case 'a':
+ wh.type = DEV_ALL;
+ wh.access = ACC_MASK;
+ goto handle;
+ case 'b':
+ wh.type = DEV_BLOCK;
+ break;
+ case 'c':
+ wh.type = DEV_CHAR;
+ break;
+ default:
+ retval = -EINVAL;
+ goto out2;
+ }
+ b++;
+ if (!isspace(*b)) {
+ retval = -EINVAL;
+ goto out2;
+ }
+ b++;
+ if (*b == '*') {
+ wh.major = ~0;
+ b++;
+ } else if (isdigit(*b)) {
+ wh.major = 0;
+ while (isdigit(*b)) {
+ wh.major = wh.major*10+(*b-'0');
+ b++;
+ }
+ } else {
+ retval = -EINVAL;
+ goto out2;
+ }
+ if (*b != ':') {
+ retval = -EINVAL;
+ goto out2;
+ }
+ b++;
+
+ /* read minor */
+ if (*b == '*') {
+ wh.minor = ~0;
+ b++;
+ } else if (isdigit(*b)) {
+ wh.minor = 0;
+ while (isdigit(*b)) {
+ wh.minor = wh.minor*10+(*b-'0');
+ b++;
+ }
+ } else {
+ retval = -EINVAL;
+ goto out2;
+ }
+ if (!isspace(*b)) {
+ retval = -EINVAL;
+ goto out2;
+ }
+ for (b++, count = 0; count < 3; count++, b++) {
+ switch (*b) {
+ case 'r':
+ wh.access |= ACC_READ;
+ break;
+ case 'w':
+ wh.access |= ACC_WRITE;
+ break;
+ case 'm':
+ wh.access |= ACC_MKNOD;
+ break;
+ case '\n':
+ case '\0':
+ count = 3;
+ break;
+ default:
+ retval = -EINVAL;
+ goto out2;
+ }
+ }
+
+handle:
+ retval = 0;
+ switch (filetype) {
+ case DEVCG_ALLOW:
+ if (!parent_has_perm(cgroup, &wh))
+ retval = -EPERM;
+ else
+ retval = dev_whitelist_add(devcgroup, &wh);
+ break;
+ case DEVCG_DENY:
+ dev_whitelist_rm(devcgroup, &wh);
+ break;
+ default:
+ retval = -EINVAL;
+ goto out2;
+ }
+
+ if (retval == 0)
+ retval = nbytes;
+
+out2:
+ cgroup_unlock();
+out1:
+ kfree(buffer);
+ return retval;
+}
+
+static struct cftype dev_cgroup_files[] = {
+ {
+ .name = "allow",
+ .write = devcgroup_access_write,
+ .private = DEVCG_ALLOW,
+ },
+ {
+ .name = "deny",
+ .write = devcgroup_access_write,
+ .private = DEVCG_DENY,
+ },
+ {
+ .name = "list",
+ .read_seq_string = devcgroup_seq_read,
+ .private = DEVCG_LIST,
+ },
+};
+
+static int devcgroup_populate(struct cgroup_subsys *ss,
+ struct cgroup *cgroup)
+{
+ return cgroup_add_files(cgroup, ss, dev_cgroup_files,
+ ARRAY_SIZE(dev_cgroup_files));
+}
+
+struct cgroup_subsys devices_subsys = {
+ .name = "devices",
+ .can_attach = devcgroup_can_attach,
+ .create = devcgroup_create,
+ .destroy = devcgroup_destroy,
+ .populate = devcgroup_populate,
+ .subsys_id = devices_subsys_id,
+};
+
+int devcgroup_inode_permission(struct inode *inode, int mask)
+{
+ struct cgroup *cgroup;
+ struct dev_cgroup *dev_cgroup;
+ struct dev_whitelist_item *wh;
+
+ dev_t device = inode->i_rdev;
+ if (!device)
+ return 0;
+ if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode))
+ return 0;
+ cgroup = task_cgroup(current, devices_subsys.subsys_id);
+ dev_cgroup = cgroup_to_devcgroup(cgroup);
+ if (!dev_cgroup)
+ return 0;
+
+ spin_lock(&dev_cgroup->lock);
+ list_for_each_entry(wh, &dev_cgroup->whitelist, list) {
+ if (wh->type & DEV_ALL)
+ goto acc_check;
+ if ((wh->type & DEV_BLOCK) && !S_ISBLK(inode->i_mode))
+ continue;
+ if ((wh->type & DEV_CHAR) && !S_ISCHR(inode->i_mode))
+ continue;
+ if (wh->major != ~0 && wh->major != imajor(inode))
+ continue;
+ if (wh->minor != ~0 && wh->minor != iminor(inode))
+ continue;
+acc_check:
+ if ((mask & MAY_WRITE) && !(wh->access & ACC_WRITE))
+ continue;
+ if ((mask & MAY_READ) && !(wh->access & ACC_READ))
+ continue;
+ spin_unlock(&dev_cgroup->lock);
+ return 0;
+ }
+ spin_unlock(&dev_cgroup->lock);
+
+ return -EPERM;
+}
+
+int devcgroup_inode_mknod(int mode, dev_t dev)
+{
+ struct cgroup *cgroup;
+ struct dev_cgroup *dev_cgroup;
+ struct dev_whitelist_item *wh;
+
+ cgroup = task_cgroup(current, devices_subsys.subsys_id);
+ dev_cgroup = cgroup_to_devcgroup(cgroup);
+ if (!dev_cgroup)
+ return 0;
+
+ spin_lock(&dev_cgroup->lock);
+ list_for_each_entry(wh, &dev_cgroup->whitelist, list) {
+ if (wh->type & DEV_ALL)
+ goto acc_check;
+ if ((wh->type & DEV_BLOCK) && !S_ISBLK(mode))
+ continue;
+ if ((wh->type & DEV_CHAR) && !S_ISCHR(mode))
+ continue;
+ if (wh->major != ~0 && wh->major != MAJOR(dev))
+ continue;
+ if (wh->minor != ~0 && wh->minor != MINOR(dev))
+ continue;
+acc_check:
+ if (!(wh->access & ACC_MKNOD))
+ continue;
+ spin_unlock(&dev_cgroup->lock);
+ return 0;
+ }
+ spin_unlock(&dev_cgroup->lock);
+ return -EPERM;
+}
diff --git a/security/dummy.c b/security/dummy.c
index 58d4dd1..f50c6c3 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -365,8 +365,8 @@
return;
}
-static int dummy_inode_setxattr (struct dentry *dentry, char *name, void *value,
- size_t size, int flags)
+static int dummy_inode_setxattr (struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
@@ -375,12 +375,13 @@
return 0;
}
-static void dummy_inode_post_setxattr (struct dentry *dentry, char *name, void *value,
- size_t size, int flags)
+static void dummy_inode_post_setxattr (struct dentry *dentry, const char *name,
+ const void *value, size_t size,
+ int flags)
{
}
-static int dummy_inode_getxattr (struct dentry *dentry, char *name)
+static int dummy_inode_getxattr (struct dentry *dentry, const char *name)
{
return 0;
}
@@ -390,7 +391,7 @@
return 0;
}
-static int dummy_inode_removexattr (struct dentry *dentry, char *name)
+static int dummy_inode_removexattr (struct dentry *dentry, const char *name)
{
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
@@ -967,7 +968,7 @@
return -EOPNOTSUPP;
}
-static int dummy_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+static int dummy_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
return -EOPNOTSUPP;
}
@@ -993,6 +994,13 @@
{
return 0;
}
+
+static int dummy_key_getsecurity(struct key *key, char **_buffer)
+{
+ *_buffer = NULL;
+ return 0;
+}
+
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
@@ -1209,6 +1217,7 @@
set_to_dummy_if_null(ops, key_alloc);
set_to_dummy_if_null(ops, key_free);
set_to_dummy_if_null(ops, key_permission);
+ set_to_dummy_if_null(ops, key_getsecurity);
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
set_to_dummy_if_null(ops, audit_rule_init);
diff --git a/security/keys/Makefile b/security/keys/Makefile
index 5145adf..747a464 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -14,3 +14,4 @@
obj-$(CONFIG_KEYS_COMPAT) += compat.o
obj-$(CONFIG_PROC_FS) += proc.o
+obj-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/security/keys/compat.c b/security/keys/compat.c
index e10ec99..c766c68 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -79,6 +79,9 @@
case KEYCTL_ASSUME_AUTHORITY:
return keyctl_assume_authority(arg2);
+ case KEYCTL_GET_SECURITY:
+ return keyctl_get_security(arg2, compat_ptr(arg3), arg4);
+
default:
return -EOPNOTSUPP;
}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 7d894ef..8c05587 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -57,10 +57,6 @@
int qnbytes; /* number of bytes allocated to this user */
};
-#define KEYQUOTA_MAX_KEYS 100
-#define KEYQUOTA_MAX_BYTES 10000
-#define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */
-
extern struct rb_root key_user_tree;
extern spinlock_t key_user_lock;
extern struct key_user root_key_user;
@@ -68,6 +64,16 @@
extern struct key_user *key_user_lookup(uid_t uid);
extern void key_user_put(struct key_user *user);
+/*
+ * key quota limits
+ * - root has its own separate limits to everyone else
+ */
+extern unsigned key_quota_root_maxkeys;
+extern unsigned key_quota_root_maxbytes;
+extern unsigned key_quota_maxkeys;
+extern unsigned key_quota_maxbytes;
+
+#define KEYQUOTA_LINK_BYTES 4 /* a link in a keyring is worth 4 bytes */
extern struct rb_root key_serial_tree;
@@ -77,8 +83,6 @@
extern wait_queue_head_t request_key_conswq;
-extern void keyring_publish_name(struct key *keyring);
-
extern int __key_link(struct key *keyring, struct key *key);
extern key_ref_t __keyring_search_one(key_ref_t keyring_ref,
@@ -102,14 +106,15 @@
key_match_func_t match,
struct task_struct *tsk);
-extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
+extern struct key *find_keyring_by_name(const char *name, bool skip_perm_check);
extern int install_thread_keyring(struct task_struct *tsk);
extern int install_process_keyring(struct task_struct *tsk);
extern struct key *request_key_and_link(struct key_type *type,
const char *description,
- const char *callout_info,
+ const void *callout_info,
+ size_t callout_len,
void *aux,
struct key *dest_keyring,
unsigned long flags);
@@ -120,13 +125,15 @@
struct request_key_auth {
struct key *target_key;
struct task_struct *context;
- char *callout_info;
+ void *callout_info;
+ size_t callout_len;
pid_t pid;
};
extern struct key_type key_type_request_key_auth;
extern struct key *request_key_auth_new(struct key *target,
- const char *callout_info);
+ const void *callout_info,
+ size_t callout_len);
extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
@@ -152,7 +159,8 @@
extern long keyctl_set_reqkey_keyring(int);
extern long keyctl_set_timeout(key_serial_t, unsigned);
extern long keyctl_assume_authority(key_serial_t);
-
+extern long keyctl_get_security(key_serial_t keyid, char __user *buffer,
+ size_t buflen);
/*
* debugging key validation
diff --git a/security/keys/key.c b/security/keys/key.c
index 654d23b..14948cf 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -1,6 +1,6 @@
/* Basic authentication token and access key management
*
- * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2008 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -27,6 +27,11 @@
struct rb_root key_user_tree; /* tree of quota records indexed by UID */
DEFINE_SPINLOCK(key_user_lock);
+unsigned int key_quota_root_maxkeys = 200; /* root's key count quota */
+unsigned int key_quota_root_maxbytes = 20000; /* root's key space quota */
+unsigned int key_quota_maxkeys = 200; /* general key count quota */
+unsigned int key_quota_maxbytes = 20000; /* general key space quota */
+
static LIST_HEAD(key_types_list);
static DECLARE_RWSEM(key_types_sem);
@@ -139,36 +144,6 @@
/*****************************************************************************/
/*
- * insert a key with a fixed serial number
- */
-static void __init __key_insert_serial(struct key *key)
-{
- struct rb_node *parent, **p;
- struct key *xkey;
-
- parent = NULL;
- p = &key_serial_tree.rb_node;
-
- while (*p) {
- parent = *p;
- xkey = rb_entry(parent, struct key, serial_node);
-
- if (key->serial < xkey->serial)
- p = &(*p)->rb_left;
- else if (key->serial > xkey->serial)
- p = &(*p)->rb_right;
- else
- BUG();
- }
-
- /* we've found a suitable hole - arrange for this key to occupy it */
- rb_link_node(&key->serial_node, parent, p);
- rb_insert_color(&key->serial_node, &key_serial_tree);
-
-} /* end __key_insert_serial() */
-
-/*****************************************************************************/
-/*
* assign a key the next unique serial number
* - these are assigned randomly to avoid security issues through covert
* channel problems
@@ -266,11 +241,16 @@
/* check that the user's quota permits allocation of another key and
* its description */
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA)) {
+ unsigned maxkeys = (uid == 0) ?
+ key_quota_root_maxkeys : key_quota_maxkeys;
+ unsigned maxbytes = (uid == 0) ?
+ key_quota_root_maxbytes : key_quota_maxbytes;
+
spin_lock(&user->lock);
if (!(flags & KEY_ALLOC_QUOTA_OVERRUN)) {
- if (user->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
- user->qnbytes + quotalen >= KEYQUOTA_MAX_BYTES
- )
+ if (user->qnkeys + 1 >= maxkeys ||
+ user->qnbytes + quotalen >= maxbytes ||
+ user->qnbytes + quotalen < user->qnbytes)
goto no_quota;
}
@@ -375,11 +355,14 @@
/* contemplate the quota adjustment */
if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
+ unsigned maxbytes = (key->user->uid == 0) ?
+ key_quota_root_maxbytes : key_quota_maxbytes;
+
spin_lock(&key->user->lock);
if (delta > 0 &&
- key->user->qnbytes + delta > KEYQUOTA_MAX_BYTES
- ) {
+ (key->user->qnbytes + delta >= maxbytes ||
+ key->user->qnbytes + delta < key->user->qnbytes)) {
ret = -EDQUOT;
}
else {
@@ -757,11 +740,11 @@
const char *description,
const void *payload,
size_t plen,
+ key_perm_t perm,
unsigned long flags)
{
struct key_type *ktype;
struct key *keyring, *key = NULL;
- key_perm_t perm;
key_ref_t key_ref;
int ret;
@@ -806,15 +789,17 @@
goto found_matching_key;
}
- /* decide on the permissions we want */
- perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
- perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR;
+ /* if the client doesn't provide, decide on the permissions we want */
+ if (perm == KEY_PERM_UNDEF) {
+ perm = KEY_POS_VIEW | KEY_POS_SEARCH | KEY_POS_LINK | KEY_POS_SETATTR;
+ perm |= KEY_USR_VIEW | KEY_USR_SEARCH | KEY_USR_LINK | KEY_USR_SETATTR;
- if (ktype->read)
- perm |= KEY_POS_READ | KEY_USR_READ;
+ if (ktype->read)
+ perm |= KEY_POS_READ | KEY_USR_READ;
- if (ktype == &key_type_keyring || ktype->update)
- perm |= KEY_USR_WRITE;
+ if (ktype == &key_type_keyring || ktype->update)
+ perm |= KEY_USR_WRITE;
+ }
/* allocate a new key */
key = key_alloc(ktype, description, current->fsuid, current->fsgid,
@@ -1018,17 +1003,4 @@
rb_insert_color(&root_key_user.node,
&key_user_tree);
- /* record root's user standard keyrings */
- key_check(&root_user_keyring);
- key_check(&root_session_keyring);
-
- __key_insert_serial(&root_user_keyring);
- __key_insert_serial(&root_session_keyring);
-
- keyring_publish_name(&root_user_keyring);
- keyring_publish_name(&root_session_keyring);
-
- /* link the two root keyrings together */
- key_link(&root_session_keyring, &root_user_keyring);
-
} /* end key_init() */
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index d9ca15c..acc9c89 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -19,6 +19,8 @@
#include <linux/capability.h>
#include <linux/string.h>
#include <linux/err.h>
+#include <linux/vmalloc.h>
+#include <linux/security.h>
#include <asm/uaccess.h>
#include "internal.h"
@@ -62,9 +64,10 @@
char type[32], *description;
void *payload;
long ret;
+ bool vm;
ret = -EINVAL;
- if (plen > 32767)
+ if (plen > 1024 * 1024 - 1)
goto error;
/* draw all the data into kernel space */
@@ -81,11 +84,18 @@
/* pull the payload in if one was supplied */
payload = NULL;
+ vm = false;
if (_payload) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL);
- if (!payload)
- goto error2;
+ if (!payload) {
+ if (plen <= PAGE_SIZE)
+ goto error2;
+ vm = true;
+ payload = vmalloc(plen);
+ if (!payload)
+ goto error2;
+ }
ret = -EFAULT;
if (copy_from_user(payload, _payload, plen) != 0)
@@ -102,7 +112,8 @@
/* create or update the requested key and add it to the target
* keyring */
key_ref = key_create_or_update(keyring_ref, type, description,
- payload, plen, KEY_ALLOC_IN_QUOTA);
+ payload, plen, KEY_PERM_UNDEF,
+ KEY_ALLOC_IN_QUOTA);
if (!IS_ERR(key_ref)) {
ret = key_ref_to_ptr(key_ref)->serial;
key_ref_put(key_ref);
@@ -113,7 +124,10 @@
key_ref_put(keyring_ref);
error3:
- kfree(payload);
+ if (!vm)
+ kfree(payload);
+ else
+ vfree(payload);
error2:
kfree(description);
error:
@@ -140,6 +154,7 @@
struct key_type *ktype;
struct key *key;
key_ref_t dest_ref;
+ size_t callout_len;
char type[32], *description, *callout_info;
long ret;
@@ -157,12 +172,14 @@
/* pull the callout info into kernel space */
callout_info = NULL;
+ callout_len = 0;
if (_callout_info) {
callout_info = strndup_user(_callout_info, PAGE_SIZE);
if (IS_ERR(callout_info)) {
ret = PTR_ERR(callout_info);
goto error2;
}
+ callout_len = strlen(callout_info);
}
/* get the destination keyring if specified */
@@ -183,8 +200,8 @@
}
/* do the search */
- key = request_key_and_link(ktype, description, callout_info, NULL,
- key_ref_to_ptr(dest_ref),
+ key = request_key_and_link(ktype, description, callout_info,
+ callout_len, NULL, key_ref_to_ptr(dest_ref),
KEY_ALLOC_IN_QUOTA);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
@@ -714,10 +731,16 @@
/* transfer the quota burden to the new user */
if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
+ unsigned maxkeys = (uid == 0) ?
+ key_quota_root_maxkeys : key_quota_maxkeys;
+ unsigned maxbytes = (uid == 0) ?
+ key_quota_root_maxbytes : key_quota_maxbytes;
+
spin_lock(&newowner->lock);
- if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS ||
- newowner->qnbytes + key->quotalen >=
- KEYQUOTA_MAX_BYTES)
+ if (newowner->qnkeys + 1 >= maxkeys ||
+ newowner->qnbytes + key->quotalen >= maxbytes ||
+ newowner->qnbytes + key->quotalen <
+ newowner->qnbytes)
goto quota_overrun;
newowner->qnkeys++;
@@ -821,9 +844,10 @@
key_ref_t keyring_ref;
void *payload;
long ret;
+ bool vm = false;
ret = -EINVAL;
- if (plen > 32767)
+ if (plen > 1024 * 1024 - 1)
goto error;
/* the appropriate instantiation authorisation key must have been
@@ -843,8 +867,14 @@
if (_payload) {
ret = -ENOMEM;
payload = kmalloc(plen, GFP_KERNEL);
- if (!payload)
- goto error;
+ if (!payload) {
+ if (plen <= PAGE_SIZE)
+ goto error;
+ vm = true;
+ payload = vmalloc(plen);
+ if (!payload)
+ goto error;
+ }
ret = -EFAULT;
if (copy_from_user(payload, _payload, plen) != 0)
@@ -877,7 +907,10 @@
}
error2:
- kfree(payload);
+ if (!vm)
+ kfree(payload);
+ else
+ vfree(payload);
error:
return ret;
@@ -1055,6 +1088,66 @@
} /* end keyctl_assume_authority() */
+/*
+ * get the security label of a key
+ * - the key must grant us view permission
+ * - if there's a buffer, we place up to buflen bytes of data into it
+ * - unless there's an error, we return the amount of information available,
+ * irrespective of how much we may have copied (including the terminal NUL)
+ * - implements keyctl(KEYCTL_GET_SECURITY)
+ */
+long keyctl_get_security(key_serial_t keyid,
+ char __user *buffer,
+ size_t buflen)
+{
+ struct key *key, *instkey;
+ key_ref_t key_ref;
+ char *context;
+ long ret;
+
+ key_ref = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
+ if (IS_ERR(key_ref)) {
+ if (PTR_ERR(key_ref) != -EACCES)
+ return PTR_ERR(key_ref);
+
+ /* viewing a key under construction is also permitted if we
+ * have the authorisation token handy */
+ instkey = key_get_instantiation_authkey(keyid);
+ if (IS_ERR(instkey))
+ return PTR_ERR(key_ref);
+ key_put(instkey);
+
+ key_ref = lookup_user_key(NULL, keyid, 0, 1, 0);
+ if (IS_ERR(key_ref))
+ return PTR_ERR(key_ref);
+ }
+
+ key = key_ref_to_ptr(key_ref);
+ ret = security_key_getsecurity(key, &context);
+ if (ret == 0) {
+ /* if no information was returned, give userspace an empty
+ * string */
+ ret = 1;
+ if (buffer && buflen > 0 &&
+ copy_to_user(buffer, "", 1) != 0)
+ ret = -EFAULT;
+ } else if (ret > 0) {
+ /* return as much data as there's room for */
+ if (buffer && buflen > 0) {
+ if (buflen > ret)
+ buflen = ret;
+
+ if (copy_to_user(buffer, context, buflen) != 0)
+ ret = -EFAULT;
+ }
+
+ kfree(context);
+ }
+
+ key_ref_put(key_ref);
+ return ret;
+}
+
/*****************************************************************************/
/*
* the key control system call
@@ -1135,6 +1228,11 @@
case KEYCTL_ASSUME_AUTHORITY:
return keyctl_assume_authority((key_serial_t) arg2);
+ case KEYCTL_GET_SECURITY:
+ return keyctl_get_security((key_serial_t) arg2,
+ (char *) arg3,
+ (size_t) arg4);
+
default:
return -EOPNOTSUPP;
}
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index 88292e3..a9ab8af 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1,6 +1,6 @@
-/* keyring.c: keyring handling
+/* Keyring handling
*
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -79,7 +79,7 @@
* publish the name of a keyring so that it can be found by name (if it has
* one)
*/
-void keyring_publish_name(struct key *keyring)
+static void keyring_publish_name(struct key *keyring)
{
int bucket;
@@ -292,7 +292,7 @@
struct keyring_list *keylist;
struct timespec now;
- unsigned long possessed;
+ unsigned long possessed, kflags;
struct key *keyring, *key;
key_ref_t key_ref;
long err;
@@ -319,6 +319,32 @@
err = -EAGAIN;
sp = 0;
+ /* firstly we should check to see if this top-level keyring is what we
+ * are looking for */
+ key_ref = ERR_PTR(-EAGAIN);
+ kflags = keyring->flags;
+ if (keyring->type == type && match(keyring, description)) {
+ key = keyring;
+
+ /* check it isn't negative and hasn't expired or been
+ * revoked */
+ if (kflags & (1 << KEY_FLAG_REVOKED))
+ goto error_2;
+ if (key->expiry && now.tv_sec >= key->expiry)
+ goto error_2;
+ key_ref = ERR_PTR(-ENOKEY);
+ if (kflags & (1 << KEY_FLAG_NEGATIVE))
+ goto error_2;
+ goto found;
+ }
+
+ /* otherwise, the top keyring must not be revoked, expired, or
+ * negatively instantiated if we are to search it */
+ key_ref = ERR_PTR(-EAGAIN);
+ if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) ||
+ (keyring->expiry && now.tv_sec >= keyring->expiry))
+ goto error_2;
+
/* start processing a new keyring */
descend:
if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
@@ -331,13 +357,14 @@
/* iterate through the keys in this keyring first */
for (kix = 0; kix < keylist->nkeys; kix++) {
key = keylist->keys[kix];
+ kflags = key->flags;
/* ignore keys not of this type */
if (key->type != type)
continue;
/* skip revoked keys and expired keys */
- if (test_bit(KEY_FLAG_REVOKED, &key->flags))
+ if (kflags & (1 << KEY_FLAG_REVOKED))
continue;
if (key->expiry && now.tv_sec >= key->expiry)
@@ -352,8 +379,8 @@
context, KEY_SEARCH) < 0)
continue;
- /* we set a different error code if we find a negative key */
- if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
+ /* we set a different error code if we pass a negative key */
+ if (kflags & (1 << KEY_FLAG_NEGATIVE)) {
err = -ENOKEY;
continue;
}
@@ -489,10 +516,9 @@
/*
* find a keyring with the specified name
* - all named keyrings are searched
- * - only find keyrings with search permission for the process
- * - only find keyrings with a serial number greater than the one specified
+ * - normally only finds keyrings with search permission for the current process
*/
-struct key *find_keyring_by_name(const char *name, key_serial_t bound)
+struct key *find_keyring_by_name(const char *name, bool skip_perm_check)
{
struct key *keyring;
int bucket;
@@ -518,15 +544,11 @@
if (strcmp(keyring->description, name) != 0)
continue;
- if (key_permission(make_key_ref(keyring, 0),
+ if (!skip_perm_check &&
+ key_permission(make_key_ref(keyring, 0),
KEY_SEARCH) < 0)
continue;
- /* found a potential candidate, but we still need to
- * check the serial number */
- if (keyring->serial <= bound)
- continue;
-
/* we've got a match */
atomic_inc(&keyring->usage);
read_unlock(&keyring_name_lock);
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 6941260..f619170 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -70,19 +70,15 @@
struct proc_dir_entry *p;
#ifdef CONFIG_KEYS_DEBUG_PROC_KEYS
- p = create_proc_entry("keys", 0, NULL);
+ p = proc_create("keys", 0, NULL, &proc_keys_fops);
if (!p)
panic("Cannot create /proc/keys\n");
-
- p->proc_fops = &proc_keys_fops;
#endif
- p = create_proc_entry("key-users", 0, NULL);
+ p = proc_create("key-users", 0, NULL, &proc_key_users_fops);
if (!p)
panic("Cannot create /proc/key-users\n");
- p->proc_fops = &proc_key_users_fops;
-
return 0;
} /* end key_proc_init() */
@@ -246,6 +242,10 @@
{
struct rb_node *_p = v;
struct key_user *user = rb_entry(_p, struct key_user, node);
+ unsigned maxkeys = (user->uid == 0) ?
+ key_quota_root_maxkeys : key_quota_maxkeys;
+ unsigned maxbytes = (user->uid == 0) ?
+ key_quota_root_maxbytes : key_quota_maxbytes;
seq_printf(m, "%5u: %5d %d/%d %d/%d %d/%d\n",
user->uid,
@@ -253,10 +253,9 @@
atomic_read(&user->nkeys),
atomic_read(&user->nikeys),
user->qnkeys,
- KEYQUOTA_MAX_KEYS,
+ maxkeys,
user->qnbytes,
- KEYQUOTA_MAX_BYTES
- );
+ maxbytes);
return 0;
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index c886a2b..5be6d01 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -1,6 +1,6 @@
-/* process_keys.c: management of a process's keyrings
+/* Management of a process's keyrings
*
- * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-2005, 2008 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -23,6 +23,9 @@
/* session keyring create vs join semaphore */
static DEFINE_MUTEX(key_session_mutex);
+/* user keyring creation semaphore */
+static DEFINE_MUTEX(key_user_keyring_mutex);
+
/* the root user's tracking struct */
struct key_user root_key_user = {
.usage = ATOMIC_INIT(3),
@@ -33,78 +36,84 @@
.uid = 0,
};
-/* the root user's UID keyring */
-struct key root_user_keyring = {
- .usage = ATOMIC_INIT(1),
- .serial = 2,
- .type = &key_type_keyring,
- .user = &root_key_user,
- .sem = __RWSEM_INITIALIZER(root_user_keyring.sem),
- .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
- .flags = 1 << KEY_FLAG_INSTANTIATED,
- .description = "_uid.0",
-#ifdef KEY_DEBUGGING
- .magic = KEY_DEBUG_MAGIC,
-#endif
-};
-
-/* the root user's default session keyring */
-struct key root_session_keyring = {
- .usage = ATOMIC_INIT(1),
- .serial = 1,
- .type = &key_type_keyring,
- .user = &root_key_user,
- .sem = __RWSEM_INITIALIZER(root_session_keyring.sem),
- .perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_ALL,
- .flags = 1 << KEY_FLAG_INSTANTIATED,
- .description = "_uid_ses.0",
-#ifdef KEY_DEBUGGING
- .magic = KEY_DEBUG_MAGIC,
-#endif
-};
-
/*****************************************************************************/
/*
- * allocate the keyrings to be associated with a UID
+ * install user and user session keyrings for a particular UID
*/
-int alloc_uid_keyring(struct user_struct *user,
- struct task_struct *ctx)
+static int install_user_keyrings(struct task_struct *tsk)
{
+ struct user_struct *user = tsk->user;
struct key *uid_keyring, *session_keyring;
char buf[20];
int ret;
- /* concoct a default session keyring */
- sprintf(buf, "_uid_ses.%u", user->uid);
+ kenter("%p{%u}", user, user->uid);
- session_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
- KEY_ALLOC_IN_QUOTA, NULL);
- if (IS_ERR(session_keyring)) {
- ret = PTR_ERR(session_keyring);
- goto error;
+ if (user->uid_keyring) {
+ kleave(" = 0 [exist]");
+ return 0;
}
- /* and a UID specific keyring, pointed to by the default session
- * keyring */
- sprintf(buf, "_uid.%u", user->uid);
-
- uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1, ctx,
- KEY_ALLOC_IN_QUOTA, session_keyring);
- if (IS_ERR(uid_keyring)) {
- key_put(session_keyring);
- ret = PTR_ERR(uid_keyring);
- goto error;
- }
-
- /* install the keyrings */
- user->uid_keyring = uid_keyring;
- user->session_keyring = session_keyring;
+ mutex_lock(&key_user_keyring_mutex);
ret = 0;
-error:
- return ret;
+ if (!user->uid_keyring) {
+ /* get the UID-specific keyring
+ * - there may be one in existence already as it may have been
+ * pinned by a session, but the user_struct pointing to it
+ * may have been destroyed by setuid */
+ sprintf(buf, "_uid.%u", user->uid);
-} /* end alloc_uid_keyring() */
+ uid_keyring = find_keyring_by_name(buf, true);
+ if (IS_ERR(uid_keyring)) {
+ uid_keyring = keyring_alloc(buf, user->uid, (gid_t) -1,
+ tsk, KEY_ALLOC_IN_QUOTA,
+ NULL);
+ if (IS_ERR(uid_keyring)) {
+ ret = PTR_ERR(uid_keyring);
+ goto error;
+ }
+ }
+
+ /* get a default session keyring (which might also exist
+ * already) */
+ sprintf(buf, "_uid_ses.%u", user->uid);
+
+ session_keyring = find_keyring_by_name(buf, true);
+ if (IS_ERR(session_keyring)) {
+ session_keyring =
+ keyring_alloc(buf, user->uid, (gid_t) -1,
+ tsk, KEY_ALLOC_IN_QUOTA, NULL);
+ if (IS_ERR(session_keyring)) {
+ ret = PTR_ERR(session_keyring);
+ goto error_release;
+ }
+
+ /* we install a link from the user session keyring to
+ * the user keyring */
+ ret = key_link(session_keyring, uid_keyring);
+ if (ret < 0)
+ goto error_release_both;
+ }
+
+ /* install the keyrings */
+ user->uid_keyring = uid_keyring;
+ user->session_keyring = session_keyring;
+ }
+
+ mutex_unlock(&key_user_keyring_mutex);
+ kleave(" = 0");
+ return 0;
+
+error_release_both:
+ key_put(session_keyring);
+error_release:
+ key_put(uid_keyring);
+error:
+ mutex_unlock(&key_user_keyring_mutex);
+ kleave(" = %d", ret);
+ return ret;
+}
/*****************************************************************************/
/*
@@ -481,7 +490,7 @@
}
}
/* or search the user-session keyring */
- else {
+ else if (context->user->session_keyring) {
key_ref = keyring_search_aux(
make_key_ref(context->user->session_keyring, 1),
context, type, description, match);
@@ -614,6 +623,9 @@
if (!context->signal->session_keyring) {
/* always install a session keyring upon access if one
* doesn't exist yet */
+ ret = install_user_keyrings(context);
+ if (ret < 0)
+ goto error;
ret = install_session_keyring(
context, context->user->session_keyring);
if (ret < 0)
@@ -628,12 +640,24 @@
break;
case KEY_SPEC_USER_KEYRING:
+ if (!context->user->uid_keyring) {
+ ret = install_user_keyrings(context);
+ if (ret < 0)
+ goto error;
+ }
+
key = context->user->uid_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
break;
case KEY_SPEC_USER_SESSION_KEYRING:
+ if (!context->user->session_keyring) {
+ ret = install_user_keyrings(context);
+ if (ret < 0)
+ goto error;
+ }
+
key = context->user->session_keyring;
atomic_inc(&key->usage);
key_ref = make_key_ref(key, 1);
@@ -744,7 +768,7 @@
mutex_lock(&key_session_mutex);
/* look for an existing keyring of this name */
- keyring = find_keyring_by_name(name, 0);
+ keyring = find_keyring_by_name(name, false);
if (PTR_ERR(keyring) == -ENOKEY) {
/* not found - try and create a new one */
keyring = keyring_alloc(name, tsk->uid, tsk->gid, tsk,
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 5ecc505..ba32ca6 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -16,6 +16,7 @@
#include <linux/kmod.h>
#include <linux/err.h>
#include <linux/keyctl.h>
+#include <linux/slab.h>
#include "internal.h"
/*
@@ -161,21 +162,22 @@
* call out to userspace for key construction
* - we ignore program failure and go on key status instead
*/
-static int construct_key(struct key *key, const char *callout_info, void *aux)
+static int construct_key(struct key *key, const void *callout_info,
+ size_t callout_len, void *aux)
{
struct key_construction *cons;
request_key_actor_t actor;
struct key *authkey;
int ret;
- kenter("%d,%s,%p", key->serial, callout_info, aux);
+ kenter("%d,%p,%zu,%p", key->serial, callout_info, callout_len, aux);
cons = kmalloc(sizeof(*cons), GFP_KERNEL);
if (!cons)
return -ENOMEM;
/* allocate an authorisation key */
- authkey = request_key_auth_new(key, callout_info);
+ authkey = request_key_auth_new(key, callout_info, callout_len);
if (IS_ERR(authkey)) {
kfree(cons);
ret = PTR_ERR(authkey);
@@ -331,6 +333,7 @@
static struct key *construct_key_and_link(struct key_type *type,
const char *description,
const char *callout_info,
+ size_t callout_len,
void *aux,
struct key *dest_keyring,
unsigned long flags)
@@ -348,7 +351,7 @@
key_user_put(user);
if (ret == 0) {
- ret = construct_key(key, callout_info, aux);
+ ret = construct_key(key, callout_info, callout_len, aux);
if (ret < 0)
goto construction_failed;
}
@@ -370,7 +373,8 @@
*/
struct key *request_key_and_link(struct key_type *type,
const char *description,
- const char *callout_info,
+ const void *callout_info,
+ size_t callout_len,
void *aux,
struct key *dest_keyring,
unsigned long flags)
@@ -378,8 +382,8 @@
struct key *key;
key_ref_t key_ref;
- kenter("%s,%s,%s,%p,%p,%lx",
- type->name, description, callout_info, aux,
+ kenter("%s,%s,%p,%zu,%p,%p,%lx",
+ type->name, description, callout_info, callout_len, aux,
dest_keyring, flags);
/* search all the process keyrings for a key */
@@ -398,7 +402,8 @@
goto error;
key = construct_key_and_link(type, description, callout_info,
- aux, dest_keyring, flags);
+ callout_len, aux, dest_keyring,
+ flags);
}
error:
@@ -434,10 +439,13 @@
const char *callout_info)
{
struct key *key;
+ size_t callout_len = 0;
int ret;
- key = request_key_and_link(type, description, callout_info, NULL,
- NULL, KEY_ALLOC_IN_QUOTA);
+ if (callout_info)
+ callout_len = strlen(callout_info);
+ key = request_key_and_link(type, description, callout_info, callout_len,
+ NULL, NULL, KEY_ALLOC_IN_QUOTA);
if (!IS_ERR(key)) {
ret = wait_for_key_construction(key, false);
if (ret < 0) {
@@ -458,14 +466,15 @@
*/
struct key *request_key_with_auxdata(struct key_type *type,
const char *description,
- const char *callout_info,
+ const void *callout_info,
+ size_t callout_len,
void *aux)
{
struct key *key;
int ret;
- key = request_key_and_link(type, description, callout_info, aux,
- NULL, KEY_ALLOC_IN_QUOTA);
+ key = request_key_and_link(type, description, callout_info, callout_len,
+ aux, NULL, KEY_ALLOC_IN_QUOTA);
if (!IS_ERR(key)) {
ret = wait_for_key_construction(key, false);
if (ret < 0) {
@@ -485,10 +494,12 @@
*/
struct key *request_key_async(struct key_type *type,
const char *description,
- const char *callout_info)
+ const void *callout_info,
+ size_t callout_len)
{
- return request_key_and_link(type, description, callout_info, NULL,
- NULL, KEY_ALLOC_IN_QUOTA);
+ return request_key_and_link(type, description, callout_info,
+ callout_len, NULL, NULL,
+ KEY_ALLOC_IN_QUOTA);
}
EXPORT_SYMBOL(request_key_async);
@@ -500,10 +511,11 @@
*/
struct key *request_key_async_with_auxdata(struct key_type *type,
const char *description,
- const char *callout_info,
+ const void *callout_info,
+ size_t callout_len,
void *aux)
{
- return request_key_and_link(type, description, callout_info, aux,
- NULL, KEY_ALLOC_IN_QUOTA);
+ return request_key_and_link(type, description, callout_info,
+ callout_len, aux, NULL, KEY_ALLOC_IN_QUOTA);
}
EXPORT_SYMBOL(request_key_async_with_auxdata);
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index e42b525..bd237b0 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -15,6 +15,7 @@
#include <linux/sched.h>
#include <linux/err.h>
#include <linux/seq_file.h>
+#include <linux/slab.h>
#include <asm/uaccess.h>
#include "internal.h"
@@ -61,7 +62,7 @@
seq_puts(m, "key:");
seq_puts(m, key->description);
- seq_printf(m, " pid:%d ci:%zu", rka->pid, strlen(rka->callout_info));
+ seq_printf(m, " pid:%d ci:%zu", rka->pid, rka->callout_len);
} /* end request_key_auth_describe() */
@@ -77,7 +78,7 @@
size_t datalen;
long ret;
- datalen = strlen(rka->callout_info);
+ datalen = rka->callout_len;
ret = datalen;
/* we can return the data as is */
@@ -137,7 +138,8 @@
* create an authorisation token for /sbin/request-key or whoever to gain
* access to the caller's security data
*/
-struct key *request_key_auth_new(struct key *target, const char *callout_info)
+struct key *request_key_auth_new(struct key *target, const void *callout_info,
+ size_t callout_len)
{
struct request_key_auth *rka, *irka;
struct key *authkey = NULL;
@@ -152,7 +154,7 @@
kleave(" = -ENOMEM");
return ERR_PTR(-ENOMEM);
}
- rka->callout_info = kmalloc(strlen(callout_info) + 1, GFP_KERNEL);
+ rka->callout_info = kmalloc(callout_len, GFP_KERNEL);
if (!rka->callout_info) {
kleave(" = -ENOMEM");
kfree(rka);
@@ -186,7 +188,8 @@
}
rka->target_key = key_get(target);
- strcpy(rka->callout_info, callout_info);
+ memcpy(rka->callout_info, callout_info, callout_len);
+ rka->callout_len = callout_len;
/* allocate the auth key */
sprintf(desc, "%x", target->serial);
diff --git a/security/keys/sysctl.c b/security/keys/sysctl.c
new file mode 100644
index 0000000..b611d49
--- /dev/null
+++ b/security/keys/sysctl.c
@@ -0,0 +1,50 @@
+/* Key management controls
+ *
+ * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#include <linux/key.h>
+#include <linux/sysctl.h>
+#include "internal.h"
+
+ctl_table key_sysctls[] = {
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "maxkeys",
+ .data = &key_quota_maxkeys,
+ .maxlen = sizeof(unsigned),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "maxbytes",
+ .data = &key_quota_maxbytes,
+ .maxlen = sizeof(unsigned),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "root_maxkeys",
+ .data = &key_quota_root_maxkeys,
+ .maxlen = sizeof(unsigned),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "root_maxbytes",
+ .data = &key_quota_root_maxbytes,
+ .maxlen = sizeof(unsigned),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ { .ctl_name = 0 }
+};
diff --git a/security/security.c b/security/security.c
index d5cb589..59838a9 100644
--- a/security/security.c
+++ b/security/security.c
@@ -491,23 +491,23 @@
security_ops->inode_delete(inode);
}
-int security_inode_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+int security_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
return security_ops->inode_setxattr(dentry, name, value, size, flags);
}
-void security_inode_post_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+void security_inode_post_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return;
security_ops->inode_post_setxattr(dentry, name, value, size, flags);
}
-int security_inode_getxattr(struct dentry *dentry, char *name)
+int security_inode_getxattr(struct dentry *dentry, const char *name)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
@@ -521,7 +521,7 @@
return security_ops->inode_listxattr(dentry);
}
-int security_inode_removexattr(struct dentry *dentry, char *name)
+int security_inode_removexattr(struct dentry *dentry, const char *name)
{
if (unlikely(IS_PRIVATE(dentry->d_inode)))
return 0;
@@ -886,7 +886,7 @@
}
EXPORT_SYMBOL(security_secid_to_secctx);
-int security_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
return security_ops->secctx_to_secid(secdata, seclen, secid);
}
@@ -1156,6 +1156,11 @@
return security_ops->key_permission(key_ref, context, perm);
}
+int security_key_getsecurity(struct key *key, char **_buffer)
+{
+ return security_ops->key_getsecurity(key, _buffer);
+}
+
#endif /* CONFIG_KEYS */
#ifdef CONFIG_AUDIT
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 95a8ef4..114b4b4 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -646,7 +646,7 @@
if (*p)
audit_log_untrustedstring(ab, p);
else
- audit_log_hex(ab, p, len);
+ audit_log_n_hex(ab, p, len);
break;
}
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 04acb5a..1c864c0 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -39,6 +39,7 @@
#include <linux/spinlock.h>
#include <linux/syscalls.h>
#include <linux/file.h>
+#include <linux/fdtable.h>
#include <linux/namei.h>
#include <linux/mount.h>
#include <linux/ext2_fs.h>
@@ -2619,7 +2620,7 @@
return dentry_has_perm(current, mnt, dentry, FILE__GETATTR);
}
-static int selinux_inode_setotherxattr(struct dentry *dentry, char *name)
+static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name)
{
if (!strncmp(name, XATTR_SECURITY_PREFIX,
sizeof XATTR_SECURITY_PREFIX - 1)) {
@@ -2638,7 +2639,8 @@
return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
}
-static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags)
+static int selinux_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
struct task_security_struct *tsec = current->security;
struct inode *inode = dentry->d_inode;
@@ -2687,8 +2689,9 @@
&ad);
}
-static void selinux_inode_post_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+static void selinux_inode_post_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size,
+ int flags)
{
struct inode *inode = dentry->d_inode;
struct inode_security_struct *isec = inode->i_security;
@@ -2711,7 +2714,7 @@
return;
}
-static int selinux_inode_getxattr(struct dentry *dentry, char *name)
+static int selinux_inode_getxattr(struct dentry *dentry, const char *name)
{
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
}
@@ -2721,7 +2724,7 @@
return dentry_has_perm(current, NULL, dentry, FILE__GETATTR);
}
-static int selinux_inode_removexattr(struct dentry *dentry, char *name)
+static int selinux_inode_removexattr(struct dentry *dentry, const char *name)
{
if (strcmp(name, XATTR_NAME_SELINUX))
return selinux_inode_setotherxattr(dentry, name);
@@ -3284,9 +3287,6 @@
if (rc)
return rc;
- if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info)))
- return 0;
-
if (!sig)
perm = PROCESS__SIGNULL; /* null signal; existence test */
else
@@ -5236,7 +5236,7 @@
return security_sid_to_context(secid, secdata, seclen);
}
-static int selinux_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+static int selinux_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
return security_context_to_sid(secdata, seclen, secid);
}
@@ -5298,6 +5298,20 @@
SECCLASS_KEY, perm, NULL);
}
+static int selinux_key_getsecurity(struct key *key, char **_buffer)
+{
+ struct key_security_struct *ksec = key->security;
+ char *context = NULL;
+ unsigned len;
+ int rc;
+
+ rc = security_sid_to_context(ksec->sid, &context, &len);
+ if (!rc)
+ rc = len;
+ *_buffer = context;
+ return rc;
+}
+
#endif
static struct security_operations selinux_ops = {
@@ -5486,6 +5500,7 @@
.key_alloc = selinux_key_alloc,
.key_free = selinux_key_free,
.key_permission = selinux_key_permission,
+ .key_getsecurity = selinux_key_getsecurity,
#endif
#ifdef CONFIG_AUDIT
@@ -5534,14 +5549,6 @@
else
printk(KERN_DEBUG "SELinux: Starting in permissive mode\n");
-#ifdef CONFIG_KEYS
- /* Add security information to initial keyrings */
- selinux_key_alloc(&root_user_keyring, current,
- KEY_ALLOC_NOT_IN_QUOTA);
- selinux_key_alloc(&root_session_keyring, current,
- KEY_ALLOC_NOT_IN_QUOTA);
-#endif
-
return 0;
}
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 6445b64..ad30ac4 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -93,10 +93,10 @@
int security_sid_to_context(u32 sid, char **scontext,
u32 *scontext_len);
-int security_context_to_sid(char *scontext, u32 scontext_len,
+int security_context_to_sid(const char *scontext, u32 scontext_len,
u32 *out_sid);
-int security_context_to_sid_default(char *scontext, u32 scontext_len,
+int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *out_sid, u32 def_sid, gfp_t gfp_flags);
int security_get_user_sids(u32 callsid, char *username,
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 2daaddb..dcc2e1c 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -708,7 +708,7 @@
}
-static int security_context_to_sid_core(char *scontext, u32 scontext_len,
+static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags)
{
char *scontext2;
@@ -835,7 +835,7 @@
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
-int security_context_to_sid(char *scontext, u32 scontext_len, u32 *sid)
+int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid)
{
return security_context_to_sid_core(scontext, scontext_len,
sid, SECSID_NULL, GFP_KERNEL);
@@ -858,8 +858,8 @@
* Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
* memory is available, or 0 on success.
*/
-int security_context_to_sid_default(char *scontext, u32 scontext_len, u32 *sid,
- u32 def_sid, gfp_t gfp_flags)
+int security_context_to_sid_default(const char *scontext, u32 scontext_len,
+ u32 *sid, u32 def_sid, gfp_t gfp_flags)
{
return security_context_to_sid_core(scontext, scontext_len,
sid, def_sid, gfp_flags);
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 77ec16a..b5c8f92 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -26,6 +26,7 @@
#include <linux/pipe_fs_i.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
+#include <linux/audit.h>
#include "smack.h"
@@ -574,8 +575,8 @@
*
* Returns 0 if access is permitted, an error code otherwise
*/
-static int smack_inode_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+static int smack_inode_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
int rc = 0;
@@ -604,8 +605,8 @@
* Set the pointer in the inode blob to the entry found
* in the master label list.
*/
-static void smack_inode_post_setxattr(struct dentry *dentry, char *name,
- void *value, size_t size, int flags)
+static void smack_inode_post_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
{
struct inode_smack *isp;
char *nsp;
@@ -641,7 +642,7 @@
*
* Returns 0 if access is permitted, an error code otherwise
*/
-static int smack_inode_getxattr(struct dentry *dentry, char *name)
+static int smack_inode_getxattr(struct dentry *dentry, const char *name)
{
return smk_curacc(smk_of_inode(dentry->d_inode), MAY_READ);
}
@@ -655,7 +656,7 @@
*
* Returns 0 if access is permitted, an error code otherwise
*/
-static int smack_inode_removexattr(struct dentry *dentry, char *name)
+static int smack_inode_removexattr(struct dentry *dentry, const char *name)
{
int rc = 0;
@@ -752,6 +753,18 @@
return -EINVAL;
}
+/**
+ * smack_inode_getsecid - Extract inode's security id
+ * @inode: inode to extract the info from
+ * @secid: where result will be saved
+ */
+static void smack_inode_getsecid(const struct inode *inode, u32 *secid)
+{
+ struct inode_smack *isp = inode->i_security;
+
+ *secid = smack_to_secid(isp->smk_inode);
+}
+
/*
* File Hooks
*/
@@ -1118,15 +1131,6 @@
int sig, u32 secid)
{
/*
- * Special cases where signals really ought to go through
- * in spite of policy. Stephen Smalley suggests it may
- * make sense to change the caller so that it doesn't
- * bother with the LSM hook in these cases.
- */
- if (info != SEND_SIG_NOINFO &&
- (is_si_special(info) || SI_FROMKERNEL(info)))
- return 0;
- /*
* Sending a signal requires that the sender
* can write the receiver.
*/
@@ -1805,6 +1809,18 @@
return smk_curacc(isp, may);
}
+/**
+ * smack_ipc_getsecid - Extract smack security id
+ * @ipcp: the object permissions
+ * @secid: where result will be saved
+ */
+static void smack_ipc_getsecid(struct kern_ipc_perm *ipp, u32 *secid)
+{
+ char *smack = ipp->security;
+
+ *secid = smack_to_secid(smack);
+}
+
/* module stacking operations */
/**
@@ -2382,6 +2398,124 @@
#endif /* CONFIG_KEYS */
/*
+ * Smack Audit hooks
+ *
+ * Audit requires a unique representation of each Smack specific
+ * rule. This unique representation is used to distinguish the
+ * object to be audited from remaining kernel objects and also
+ * works as a glue between the audit hooks.
+ *
+ * Since repository entries are added but never deleted, we'll use
+ * the smack_known label address related to the given audit rule as
+ * the needed unique representation. This also better fits the smack
+ * model where nearly everything is a label.
+ */
+#ifdef CONFIG_AUDIT
+
+/**
+ * smack_audit_rule_init - Initialize a smack audit rule
+ * @field: audit rule fields given from user-space (audit.h)
+ * @op: required testing operator (=, !=, >, <, ...)
+ * @rulestr: smack label to be audited
+ * @vrule: pointer to save our own audit rule representation
+ *
+ * Prepare to audit cases where (@field @op @rulestr) is true.
+ * The label to be audited is created if necessay.
+ */
+static int smack_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
+{
+ char **rule = (char **)vrule;
+ *rule = NULL;
+
+ if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+ return -EINVAL;
+
+ if (op != AUDIT_EQUAL && op != AUDIT_NOT_EQUAL)
+ return -EINVAL;
+
+ *rule = smk_import(rulestr, 0);
+
+ return 0;
+}
+
+/**
+ * smack_audit_rule_known - Distinguish Smack audit rules
+ * @krule: rule of interest, in Audit kernel representation format
+ *
+ * This is used to filter Smack rules from remaining Audit ones.
+ * If it's proved that this rule belongs to us, the
+ * audit_rule_match hook will be called to do the final judgement.
+ */
+static int smack_audit_rule_known(struct audit_krule *krule)
+{
+ struct audit_field *f;
+ int i;
+
+ for (i = 0; i < krule->field_count; i++) {
+ f = &krule->fields[i];
+
+ if (f->type == AUDIT_SUBJ_USER || f->type == AUDIT_OBJ_USER)
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * smack_audit_rule_match - Audit given object ?
+ * @secid: security id for identifying the object to test
+ * @field: audit rule flags given from user-space
+ * @op: required testing operator
+ * @vrule: smack internal rule presentation
+ * @actx: audit context associated with the check
+ *
+ * The core Audit hook. It's used to take the decision of
+ * whether to audit or not to audit a given object.
+ */
+static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule,
+ struct audit_context *actx)
+{
+ char *smack;
+ char *rule = vrule;
+
+ if (!rule) {
+ audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR,
+ "Smack: missing rule\n");
+ return -ENOENT;
+ }
+
+ if (field != AUDIT_SUBJ_USER && field != AUDIT_OBJ_USER)
+ return 0;
+
+ smack = smack_from_secid(secid);
+
+ /*
+ * No need to do string comparisons. If a match occurs,
+ * both pointers will point to the same smack_known
+ * label.
+ */
+ if (op == AUDIT_EQUAL)
+ return (rule == smack);
+ if (op == AUDIT_NOT_EQUAL)
+ return (rule != smack);
+
+ return 0;
+}
+
+/**
+ * smack_audit_rule_free - free smack rule representation
+ * @vrule: rule to be freed.
+ *
+ * No memory was allocated.
+ */
+static void smack_audit_rule_free(void *vrule)
+{
+ /* No-op */
+}
+
+#endif /* CONFIG_AUDIT */
+
+/*
* smack_secid_to_secctx - return the smack label for a secid
* @secid: incoming integer
* @secdata: destination
@@ -2406,7 +2540,7 @@
*
* Exists for audit and networking code.
*/
-static int smack_secctx_to_secid(char *secdata, u32 seclen, u32 *secid)
+static int smack_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid)
{
*secid = smack_to_secid(secdata);
return 0;
@@ -2467,6 +2601,7 @@
.inode_getsecurity = smack_inode_getsecurity,
.inode_setsecurity = smack_inode_setsecurity,
.inode_listsecurity = smack_inode_listsecurity,
+ .inode_getsecid = smack_inode_getsecid,
.file_permission = smack_file_permission,
.file_alloc_security = smack_file_alloc_security,
@@ -2498,6 +2633,7 @@
.task_prctl = cap_task_prctl,
.ipc_permission = smack_ipc_permission,
+ .ipc_getsecid = smack_ipc_getsecid,
.msg_msg_alloc_security = smack_msg_msg_alloc_security,
.msg_msg_free_security = smack_msg_msg_free_security,
@@ -2542,12 +2678,22 @@
.sk_free_security = smack_sk_free_security,
.sock_graft = smack_sock_graft,
.inet_conn_request = smack_inet_conn_request,
+
/* key management security hooks */
#ifdef CONFIG_KEYS
.key_alloc = smack_key_alloc,
.key_free = smack_key_free,
.key_permission = smack_key_permission,
#endif /* CONFIG_KEYS */
+
+ /* Audit hooks */
+#ifdef CONFIG_AUDIT
+ .audit_rule_init = smack_audit_rule_init,
+ .audit_rule_known = smack_audit_rule_known,
+ .audit_rule_match = smack_audit_rule_match,
+ .audit_rule_free = smack_audit_rule_free,
+#endif /* CONFIG_AUDIT */
+
.secid_to_secctx = smack_secid_to_secctx,
.secctx_to_secid = smack_secctx_to_secid,
.release_secctx = smack_release_secctx,
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c
index a5da5a8..271a835 100644
--- a/security/smack/smackfs.c
+++ b/security/smack/smackfs.c
@@ -324,6 +324,7 @@
struct netlbl_audit audit_info;
audit_info.loginuid = audit_get_loginuid(current);
+ audit_info.sessionid = audit_get_sessionid(current);
audit_info.secid = smack_to_secid(current->security);
rc = netlbl_cfg_map_del(NULL, &audit_info);
@@ -356,6 +357,7 @@
struct netlbl_audit audit_info;
audit_info.loginuid = audit_get_loginuid(current);
+ audit_info.sessionid = audit_get_sessionid(current);
audit_info.secid = smack_to_secid(current->security);
if (oldambient != NULL) {
diff --git a/sound/core/info.c b/sound/core/info.c
index 9977ec2..cb5ead3 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -544,7 +544,7 @@
{
struct proc_dir_entry *p;
- p = snd_create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, &proc_root);
+ p = snd_create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
if (p == NULL)
return -ENOMEM;
snd_proc_root = p;
@@ -594,7 +594,7 @@
#ifdef CONFIG_SND_OSSEMUL
snd_info_free_entry(snd_oss_root);
#endif
- snd_remove_proc_entry(&proc_root, snd_proc_root);
+ snd_remove_proc_entry(NULL, snd_proc_root);
}
return 0;
}
diff --git a/sound/core/memalloc.c b/sound/core/memalloc.c
index 920e578..23b7bc0 100644
--- a/sound/core/memalloc.c
+++ b/sound/core/memalloc.c
@@ -629,9 +629,8 @@
static int __init snd_mem_init(void)
{
#ifdef CONFIG_PROC_FS
- snd_mem_proc = create_proc_entry(SND_MEM_PROC_FILE, 0644, NULL);
- if (snd_mem_proc)
- snd_mem_proc->proc_fops = &snd_mem_proc_fops;
+ snd_mem_proc = proc_create(SND_MEM_PROC_FILE, 0644, NULL,
+ &snd_mem_proc_fops);
#endif
return 0;
}
diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig
index fe85af1..a78a8d0 100644
--- a/sound/drivers/Kconfig
+++ b/sound/drivers/Kconfig
@@ -8,6 +8,8 @@
tristate "Internal PC speaker support"
depends on X86_PC && HIGH_RES_TIMERS
depends on INPUT
+ depends on SND
+ select SND_PCM
help
If you don't have a sound card in your computer, you can include a
driver for the PC speaker which allows it to act like a primitive
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index 18cca24..2af0999 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -243,7 +243,7 @@
#endif
}
mpu->write(mpu, cmd, MPU401C(mpu));
- if (ack) {
+ if (ack && !(mpu->info_flags & MPU401_INFO_NO_ACK)) {
ok = 0;
timeout = 10000;
while (!ok && timeout-- > 0) {
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index cdda64b..d9783a4 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -60,6 +60,7 @@
ALC880_TCL_S700,
ALC880_LG,
ALC880_LG_LW,
+ ALC880_MEDION_RIM,
#ifdef CONFIG_SND_DEBUG
ALC880_TEST,
#endif
@@ -2275,6 +2276,75 @@
alc880_lg_lw_automute(codec);
}
+static struct snd_kcontrol_new alc880_medion_rim_mixer[] = {
+ HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT),
+ HDA_BIND_MUTE("Master Playback Switch", 0x0c, 2, HDA_INPUT),
+ HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT),
+ HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x0b, 0x1, HDA_INPUT),
+ HDA_CODEC_MUTE("Internal Playback Switch", 0x0b, 0x1, HDA_INPUT),
+ { } /* end */
+};
+
+static struct hda_input_mux alc880_medion_rim_capture_source = {
+ .num_items = 2,
+ .items = {
+ { "Mic", 0x0 },
+ { "Internal Mic", 0x1 },
+ },
+};
+
+static struct hda_verb alc880_medion_rim_init_verbs[] = {
+ {0x13, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */
+
+ {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ /* Mic1 (rear panel) pin widget for input and vref at 80% */
+ {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
+ {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Mic2 (as headphone out) for HP output */
+ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
+ {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
+ /* Internal Speaker */
+ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
+ {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
+
+ {0x20, AC_VERB_SET_COEF_INDEX, 0x07},
+ {0x20, AC_VERB_SET_PROC_COEF, 0x3060},
+
+ {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT},
+ { }
+};
+
+/* toggle speaker-output according to the hp-jack state */
+static void alc880_medion_rim_automute(struct hda_codec *codec)
+{
+ unsigned int present;
+ unsigned char bits;
+
+ present = snd_hda_codec_read(codec, 0x14, 0,
+ AC_VERB_GET_PIN_SENSE, 0)
+ & AC_PINSENSE_PRESENCE;
+ bits = present ? HDA_AMP_MUTE : 0;
+ snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
+ HDA_AMP_MUTE, bits);
+ if (present)
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
+ else
+ snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2);
+}
+
+static void alc880_medion_rim_unsol_event(struct hda_codec *codec,
+ unsigned int res)
+{
+ /* Looks like the unsol event is incompatible with the standard
+ * definition. 4bit tag is placed at 28 bit!
+ */
+ if ((res >> 28) == ALC880_HP_EVENT)
+ alc880_medion_rim_automute(codec);
+}
+
#ifdef CONFIG_SND_HDA_POWER_SAVE
static struct hda_amp_list alc880_loopbacks[] = {
{ 0x0b, HDA_INPUT, 0 },
@@ -2882,6 +2952,7 @@
[ALC880_F1734] = "F1734",
[ALC880_LG] = "lg",
[ALC880_LG_LW] = "lg-lw",
+ [ALC880_MEDION_RIM] = "medion",
#ifdef CONFIG_SND_DEBUG
[ALC880_TEST] = "test",
#endif
@@ -2933,6 +3004,7 @@
SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_UNIWILL),
SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_UNIWILL_P53),
SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_W810),
+ SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_MEDION_RIM),
SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_5ST_DIG),
SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_5ST_DIG),
SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_F1734),
@@ -3227,6 +3299,20 @@
.unsol_event = alc880_lg_lw_unsol_event,
.init_hook = alc880_lg_lw_automute,
},
+ [ALC880_MEDION_RIM] = {
+ .mixers = { alc880_medion_rim_mixer },
+ .init_verbs = { alc880_volume_init_verbs,
+ alc880_medion_rim_init_verbs,
+ alc_gpio2_init_verbs },
+ .num_dacs = ARRAY_SIZE(alc880_dac_nids),
+ .dac_nids = alc880_dac_nids,
+ .dig_out_nid = ALC880_DIGOUT_NID,
+ .num_channel_mode = ARRAY_SIZE(alc880_2_jack_modes),
+ .channel_mode = alc880_2_jack_modes,
+ .input_mux = &alc880_medion_rim_capture_source,
+ .unsol_event = alc880_medion_rim_unsol_event,
+ .init_hook = alc880_medion_rim_automute,
+ },
#ifdef CONFIG_SND_DEBUG
[ALC880_TEST] = {
.mixers = { alc880_test_mixer },
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 4490422..6735090 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2429,6 +2429,7 @@
if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ICE1712,
ICEREG1724(ice, MPU_CTRL),
(MPU401_INFO_INTEGRATED |
+ MPU401_INFO_NO_ACK |
MPU401_INFO_TX_IRQ),
ice->irq, 0,
&ice->rmidi[0])) < 0) {
@@ -2442,12 +2443,10 @@
outb(inb(ICEREG1724(ice, IRQMASK)) &
~(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX),
ICEREG1724(ice, IRQMASK));
-#if 0 /* for testing */
/* set watermarks */
outb(VT1724_MPU_RX_FIFO | 0x1,
ICEREG1724(ice, MPU_FIFO_WM));
outb(0x1, ICEREG1724(ice, MPU_FIFO_WM));
-#endif
}
}
diff --git a/sound/sh/aica.c b/sound/sh/aica.c
index d49417b..9ca1133 100644
--- a/sound/sh/aica.c
+++ b/sound/sh/aica.c
@@ -663,7 +663,7 @@
return err;
pd = platform_device_register_simple(SND_AICA_DRIVER, -1,
aica_memory_space, 2);
- if (unlikely(IS_ERR(pd))) {
+ if (IS_ERR(pd)) {
platform_driver_unregister(&snd_aica_driver);
return PTR_ERR(pd);
}
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index a3b51df..18f28ac 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -30,6 +30,7 @@
source "sound/soc/sh/Kconfig"
source "sound/soc/fsl/Kconfig"
source "sound/soc/davinci/Kconfig"
+source "sound/soc/omap/Kconfig"
# Supported codecs
source "sound/soc/codecs/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index e489dbd..782db21 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,4 +1,4 @@
snd-soc-core-objs := soc-core.o soc-dapm.o
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
-obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/
+obj-$(CONFIG_SND_SOC) += codecs/ at91/ pxa/ s3c24xx/ sh/ fsl/ davinci/ omap/
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c
index 76a5c7b..fb41826 100644
--- a/sound/soc/codecs/wm8753.c
+++ b/sound/soc/codecs/wm8753.c
@@ -150,7 +150,7 @@
data[0] = (reg << 1) | ((value >> 8) & 0x0001);
data[1] = value & 0x00ff;
- wm8753_write_reg_cache (codec, reg, value);
+ wm8753_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
@@ -249,7 +249,7 @@
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
int mode = wm8753_read_reg_cache(codec, WM8753_IOCTL);
- if (((mode &0xc) >> 2) == ucontrol->value.integer.value[0])
+ if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0])
return 0;
mode &= 0xfff3;
@@ -342,7 +342,8 @@
for (i = 0; i < ARRAY_SIZE(wm8753_snd_controls); i++) {
err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm8753_snd_controls[i],codec, NULL));
+ snd_soc_cnew(&wm8753_snd_controls[i],
+ codec, NULL));
if (err < 0)
return err;
}
@@ -722,7 +723,7 @@
if ((Ndiv < 6) || (Ndiv > 12))
printk(KERN_WARNING
- "WM8753 N value outwith recommended range! N = %d\n",Ndiv);
+ "wm8753: unsupported N = %d\n", Ndiv);
pll_div->n = Ndiv;
Nmod = target % source;
@@ -1300,8 +1301,9 @@
}
#define WM8753_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
- SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
- SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
+ SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
#define WM8753_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
@@ -1507,9 +1509,9 @@
struct snd_soc_codec *codec = socdev->codec;
/* we only need to suspend if we are a valid card */
- if(!codec->card)
+ if (!codec->card)
return 0;
-
+
wm8753_dapm_event(codec, SNDRV_CTL_POWER_D3cold);
return 0;
}
@@ -1523,7 +1525,7 @@
u16 *cache = codec->reg_cache;
/* we only need to resume if we are a valid card */
- if(!codec->card)
+ if (!codec->card)
return 0;
/* Sync reg_cache with the hardware */
@@ -1613,9 +1615,10 @@
wm8753_add_widgets(codec);
ret = snd_soc_register_card(socdev);
if (ret < 0) {
- printk(KERN_ERR "wm8753: failed to register card\n");
+ printk(KERN_ERR "wm8753: failed to register card\n");
goto card_err;
- }
+ }
+
return ret;
card_err:
@@ -1630,7 +1633,7 @@
around */
static struct snd_soc_device *wm8753_socdev;
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
/*
* WM8753 2 wire address is determined by GPIO5
@@ -1661,7 +1664,7 @@
client_template.addr = addr;
i2c = kmemdup(&client_template, sizeof(client_template), GFP_KERNEL);
- if (i2c == NULL){
+ if (!i2c) {
kfree(codec);
return -ENOMEM;
}
@@ -1749,7 +1752,7 @@
wm8753_socdev = socdev;
INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
if (setup->i2c_address) {
normal_i2c[0] = setup->i2c_address;
codec->hw_write = (hw_write_t)i2c_master_send;
@@ -1793,7 +1796,7 @@
run_delayed_work(&codec->delayed_work);
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
-#if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8753_i2c_driver);
#endif
kfree(codec->private_data);
@@ -1808,7 +1811,6 @@
.suspend = wm8753_suspend,
.resume = wm8753_resume,
};
-
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8753);
MODULE_DESCRIPTION("ASoC WM8753 driver");
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index d2d79e1..76c1e2d 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -37,23 +37,23 @@
* WM9712 register cache
*/
static const u16 wm9712_reg[] = {
- 0x6174, 0x8000, 0x8000, 0x8000, // 6
- 0x0f0f, 0xaaa0, 0xc008, 0x6808, // e
- 0xe808, 0xaaa0, 0xad00, 0x8000, // 16
- 0xe808, 0x3000, 0x8000, 0x0000, // 1e
- 0x0000, 0x0000, 0x0000, 0x000f, // 26
- 0x0405, 0x0410, 0xbb80, 0xbb80, // 2e
- 0x0000, 0xbb80, 0x0000, 0x0000, // 36
- 0x0000, 0x2000, 0x0000, 0x0000, // 3e
- 0x0000, 0x0000, 0x0000, 0x0000, // 46
- 0x0000, 0x0000, 0xf83e, 0xffff, // 4e
- 0x0000, 0x0000, 0x0000, 0xf83e, // 56
- 0x0008, 0x0000, 0x0000, 0x0000, // 5e
- 0xb032, 0x3e00, 0x0000, 0x0000, // 66
- 0x0000, 0x0000, 0x0000, 0x0000, // 6e
- 0x0000, 0x0000, 0x0000, 0x0006, // 76
- 0x0001, 0x0000, 0x574d, 0x4c12, // 7e
- 0x0000, 0x0000 // virtual hp mixers
+ 0x6174, 0x8000, 0x8000, 0x8000, /* 6 */
+ 0x0f0f, 0xaaa0, 0xc008, 0x6808, /* e */
+ 0xe808, 0xaaa0, 0xad00, 0x8000, /* 16 */
+ 0xe808, 0x3000, 0x8000, 0x0000, /* 1e */
+ 0x0000, 0x0000, 0x0000, 0x000f, /* 26 */
+ 0x0405, 0x0410, 0xbb80, 0xbb80, /* 2e */
+ 0x0000, 0xbb80, 0x0000, 0x0000, /* 36 */
+ 0x0000, 0x2000, 0x0000, 0x0000, /* 3e */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 46 */
+ 0x0000, 0x0000, 0xf83e, 0xffff, /* 4e */
+ 0x0000, 0x0000, 0x0000, 0xf83e, /* 56 */
+ 0x0008, 0x0000, 0x0000, 0x0000, /* 5e */
+ 0xb032, 0x3e00, 0x0000, 0x0000, /* 66 */
+ 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */
+ 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */
+ 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */
+ 0x0000, 0x0000 /* virtual hp mixers */
};
/* virtual HP mixers regs */
@@ -94,7 +94,7 @@
SOC_DOUBLE("Speaker Playback Volume", AC97_MASTER, 8, 0, 31, 1),
SOC_SINGLE("Speaker Playback Switch", AC97_MASTER, 15, 1, 1),
SOC_DOUBLE("Headphone Playback Volume", AC97_HEADPHONE, 8, 0, 31, 1),
-SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE,15, 1, 1),
+SOC_SINGLE("Headphone Playback Switch", AC97_HEADPHONE, 15, 1, 1),
SOC_DOUBLE("PCM Playback Volume", AC97_PCM, 8, 0, 31, 1),
SOC_SINGLE("Speaker Playback ZC Switch", AC97_MASTER, 7, 1, 0),
@@ -165,7 +165,8 @@
for (i = 0; i < ARRAY_SIZE(wm9712_snd_ac97_controls); i++) {
err = snd_ctl_add(codec->card,
- snd_soc_cnew(&wm9712_snd_ac97_controls[i],codec, NULL));
+ snd_soc_cnew(&wm9712_snd_ac97_controls[i],
+ codec, NULL));
if (err < 0)
return err;
}
@@ -363,7 +364,6 @@
{"Left HP Mixer", "PCM Playback Switch", "Left DAC"},
{"Left HP Mixer", "Mic Sidetone Switch", "Mic PGA"},
{"Left HP Mixer", NULL, "ALC Sidetone Mux"},
- //{"Right HP Mixer", NULL, "HP Mixer"},
/* Right HP mixer */
{"Right HP Mixer", "PCBeep Bypass Switch", "PCBEEP"},
@@ -454,15 +454,13 @@
{
int i;
- for(i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++) {
+ for (i = 0; i < ARRAY_SIZE(wm9712_dapm_widgets); i++)
snd_soc_dapm_new_control(codec, &wm9712_dapm_widgets[i]);
- }
- /* set up audio path audio_mapnects */
- for(i = 0; audio_map[i][0] != NULL; i++) {
+ /* set up audio path connects */
+ for (i = 0; audio_map[i][0] != NULL; i++)
snd_soc_dapm_connect_input(codec, audio_map[i][0],
- audio_map[i][1], audio_map[i][2]);
- }
+ audio_map[i][1], audio_map[i][2]);
snd_soc_dapm_new_widgets(codec);
return 0;
@@ -540,7 +538,8 @@
}
#define WM9712_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
- SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 |\
+ SNDRV_PCM_RATE_48000)
struct snd_soc_codec_dai wm9712_dai[] = {
{
@@ -577,8 +576,6 @@
static int wm9712_dapm_event(struct snd_soc_codec *codec, int event)
{
- u16 reg;
-
switch (event) {
case SNDRV_CTL_POWER_D0: /* full On */
case SNDRV_CTL_POWER_D1: /* partial On */
@@ -633,7 +630,7 @@
u16 *cache = codec->reg_cache;
ret = wm9712_reset(codec, 1);
- if (ret < 0){
+ if (ret < 0) {
printk(KERN_ERR "could not reset AC97 codec\n");
return ret;
}
@@ -642,9 +639,9 @@
if (ret == 0) {
/* Sync reg_cache with the hardware after cold reset */
- for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i+=2) {
+ for (i = 2; i < ARRAY_SIZE(wm9712_reg) << 1; i += 2) {
if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||
- (i > 0x58 && i != 0x5c))
+ (i > 0x58 && i != 0x5c))
continue;
soc_ac97_ops.write(codec->ac97, i, cache[i>>1]);
}
@@ -757,7 +754,6 @@
.suspend = wm9712_soc_suspend,
.resume = wm9712_soc_resume,
};
-
EXPORT_SYMBOL_GPL(soc_codec_dev_wm9712);
MODULE_DESCRIPTION("ASoC WM9711/WM9712 driver");
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
new file mode 100644
index 0000000..0230d83
--- /dev/null
+++ b/sound/soc/omap/Kconfig
@@ -0,0 +1,19 @@
+menu "SoC Audio for the Texas Instruments OMAP"
+
+config SND_OMAP_SOC
+ tristate "SoC Audio for the Texas Instruments OMAP chips"
+ depends on ARCH_OMAP && SND_SOC
+
+config SND_OMAP_SOC_MCBSP
+ tristate
+ select OMAP_MCBSP
+
+config SND_OMAP_SOC_N810
+ tristate "SoC Audio support for Nokia N810"
+ depends on SND_OMAP_SOC && MACH_NOKIA_N810
+ select SND_OMAP_SOC_MCBSP
+ select SND_SOC_TLV320AIC3X
+ help
+ Say Y if you want to add support for SoC audio on Nokia N810.
+
+endmenu
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
new file mode 100644
index 0000000..d8d8d58
--- /dev/null
+++ b/sound/soc/omap/Makefile
@@ -0,0 +1,11 @@
+# OMAP Platform Support
+snd-soc-omap-objs := omap-pcm.o
+snd-soc-omap-mcbsp-objs := omap-mcbsp.o
+
+obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
+obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
+
+# OMAP Machine Support
+snd-soc-n810-objs := n810.o
+
+obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
new file mode 100644
index 0000000..83b1eb4
--- /dev/null
+++ b/sound/soc/omap/n810.c
@@ -0,0 +1,336 @@
+/*
+ * n810.c -- SoC audio for Nokia N810
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/mcbsp.h>
+
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+#include "../codecs/tlv320aic3x.h"
+
+#define RX44_HEADSET_AMP_GPIO 10
+#define RX44_SPEAKER_AMP_GPIO 101
+
+static struct clk *sys_clkout2;
+static struct clk *sys_clkout2_src;
+static struct clk *func96m_clk;
+
+static int n810_spk_func;
+static int n810_jack_func;
+
+static void n810_ext_control(struct snd_soc_codec *codec)
+{
+ snd_soc_dapm_set_endpoint(codec, "Ext Spk", n810_spk_func);
+ snd_soc_dapm_set_endpoint(codec, "Headphone Jack", n810_jack_func);
+
+ snd_soc_dapm_sync_endpoints(codec);
+}
+
+static int n810_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->codec;
+
+ n810_ext_control(codec);
+ return clk_enable(sys_clkout2);
+}
+
+static void n810_shutdown(struct snd_pcm_substream *substream)
+{
+ clk_disable(sys_clkout2);
+}
+
+static int n810_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ int err;
+
+ /* Set codec DAI configuration */
+ err = codec_dai->dai_ops.set_fmt(codec_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (err < 0)
+ return err;
+
+ /* Set cpu DAI configuration */
+ err = cpu_dai->dai_ops.set_fmt(cpu_dai,
+ SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF |
+ SND_SOC_DAIFMT_CBM_CFM);
+ if (err < 0)
+ return err;
+
+ /* Set the codec system clock for DAC and ADC */
+ err = codec_dai->dai_ops.set_sysclk(codec_dai, 0, 12000000,
+ SND_SOC_CLOCK_IN);
+
+ return err;
+}
+
+static struct snd_soc_ops n810_ops = {
+ .startup = n810_startup,
+ .hw_params = n810_hw_params,
+ .shutdown = n810_shutdown,
+};
+
+static int n810_get_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = n810_spk_func;
+
+ return 0;
+}
+
+static int n810_set_spk(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (n810_spk_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ n810_spk_func = ucontrol->value.integer.value[0];
+ n810_ext_control(codec);
+
+ return 1;
+}
+
+static int n810_get_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = n810_jack_func;
+
+ return 0;
+}
+
+static int n810_set_jack(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+ if (n810_jack_func == ucontrol->value.integer.value[0])
+ return 0;
+
+ n810_jack_func = ucontrol->value.integer.value[0];
+ n810_ext_control(codec);
+
+ return 1;
+}
+
+static int n810_spk_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 1);
+ else
+ omap_set_gpio_dataout(RX44_SPEAKER_AMP_GPIO, 0);
+
+ return 0;
+}
+
+static int n810_jack_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 1);
+ else
+ omap_set_gpio_dataout(RX44_HEADSET_AMP_GPIO, 0);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget aic33_dapm_widgets[] = {
+ SND_SOC_DAPM_SPK("Ext Spk", n810_spk_event),
+ SND_SOC_DAPM_HP("Headphone Jack", n810_jack_event),
+};
+
+static const char *audio_map[][3] = {
+ {"Headphone Jack", NULL, "HPLOUT"},
+ {"Headphone Jack", NULL, "HPROUT"},
+
+ {"Ext Spk", NULL, "LLOUT"},
+ {"Ext Spk", NULL, "RLOUT"},
+};
+
+static const char *spk_function[] = {"Off", "On"};
+static const char *jack_function[] = {"Off", "Headphone"};
+static const struct soc_enum n810_enum[] = {
+ SOC_ENUM_SINGLE_EXT(2, spk_function),
+ SOC_ENUM_SINGLE_EXT(3, jack_function),
+};
+
+static const struct snd_kcontrol_new aic33_n810_controls[] = {
+ SOC_ENUM_EXT("Speaker Function", n810_enum[0],
+ n810_get_spk, n810_set_spk),
+ SOC_ENUM_EXT("Jack Function", n810_enum[1],
+ n810_get_jack, n810_set_jack),
+};
+
+static int n810_aic33_init(struct snd_soc_codec *codec)
+{
+ int i, err;
+
+ /* Not connected */
+ snd_soc_dapm_set_endpoint(codec, "MONO_LOUT", 0);
+ snd_soc_dapm_set_endpoint(codec, "HPLCOM", 0);
+ snd_soc_dapm_set_endpoint(codec, "HPRCOM", 0);
+
+ /* Add N810 specific controls */
+ for (i = 0; i < ARRAY_SIZE(aic33_n810_controls); i++) {
+ err = snd_ctl_add(codec->card,
+ snd_soc_cnew(&aic33_n810_controls[i], codec, NULL));
+ if (err < 0)
+ return err;
+ }
+
+ /* Add N810 specific widgets */
+ for (i = 0; i < ARRAY_SIZE(aic33_dapm_widgets); i++)
+ snd_soc_dapm_new_control(codec, &aic33_dapm_widgets[i]);
+
+ /* Set up N810 specific audio path audio_map */
+ for (i = 0; i < ARRAY_SIZE(audio_map); i++)
+ snd_soc_dapm_connect_input(codec, audio_map[i][0],
+ audio_map[i][1], audio_map[i][2]);
+
+ snd_soc_dapm_sync_endpoints(codec);
+
+ return 0;
+}
+
+/* Digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link n810_dai = {
+ .name = "TLV320AIC33",
+ .stream_name = "AIC33",
+ .cpu_dai = &omap_mcbsp_dai[0],
+ .codec_dai = &aic3x_dai,
+ .init = n810_aic33_init,
+ .ops = &n810_ops,
+};
+
+/* Audio machine driver */
+static struct snd_soc_machine snd_soc_machine_n810 = {
+ .name = "N810",
+ .dai_link = &n810_dai,
+ .num_links = 1,
+};
+
+/* Audio private data */
+static struct aic3x_setup_data n810_aic33_setup = {
+ .i2c_address = 0x18,
+};
+
+/* Audio subsystem */
+static struct snd_soc_device n810_snd_devdata = {
+ .machine = &snd_soc_machine_n810,
+ .platform = &omap_soc_platform,
+ .codec_dev = &soc_codec_dev_aic3x,
+ .codec_data = &n810_aic33_setup,
+};
+
+static struct platform_device *n810_snd_device;
+
+static int __init n810_soc_init(void)
+{
+ int err;
+ struct device *dev;
+
+ if (!machine_is_nokia_n810())
+ return -ENODEV;
+
+ n810_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!n810_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(n810_snd_device, &n810_snd_devdata);
+ n810_snd_devdata.dev = &n810_snd_device->dev;
+ *(unsigned int *)n810_dai.cpu_dai->private_data = 1; /* McBSP2 */
+ err = platform_device_add(n810_snd_device);
+ if (err)
+ goto err1;
+
+ dev = &n810_snd_device->dev;
+
+ sys_clkout2_src = clk_get(dev, "sys_clkout2_src");
+ if (IS_ERR(sys_clkout2_src)) {
+ dev_err(dev, "Could not get sys_clkout2_src clock\n");
+ return -ENODEV;
+ }
+ sys_clkout2 = clk_get(dev, "sys_clkout2");
+ if (IS_ERR(sys_clkout2)) {
+ dev_err(dev, "Could not get sys_clkout2\n");
+ goto err1;
+ }
+ /*
+ * Configure 12 MHz output on SYS_CLKOUT2. Therefore we must use
+ * 96 MHz as its parent in order to get 12 MHz
+ */
+ func96m_clk = clk_get(dev, "func_96m_ck");
+ if (IS_ERR(func96m_clk)) {
+ dev_err(dev, "Could not get func 96M clock\n");
+ goto err2;
+ }
+ clk_set_parent(sys_clkout2_src, func96m_clk);
+ clk_set_rate(sys_clkout2, 12000000);
+
+ if (omap_request_gpio(RX44_HEADSET_AMP_GPIO) < 0)
+ BUG();
+ if (omap_request_gpio(RX44_SPEAKER_AMP_GPIO) < 0)
+ BUG();
+ omap_set_gpio_direction(RX44_HEADSET_AMP_GPIO, 0);
+ omap_set_gpio_direction(RX44_SPEAKER_AMP_GPIO, 0);
+
+ return 0;
+err2:
+ clk_put(sys_clkout2);
+ platform_device_del(n810_snd_device);
+err1:
+ platform_device_put(n810_snd_device);
+
+ return err;
+
+}
+
+static void __exit n810_soc_exit(void)
+{
+ platform_device_unregister(n810_snd_device);
+}
+
+module_init(n810_soc_init);
+module_exit(n810_soc_exit);
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
+MODULE_DESCRIPTION("ALSA SoC Nokia N810");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
new file mode 100644
index 0000000..40d87e6
--- /dev/null
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -0,0 +1,414 @@
+/*
+ * omap-mcbsp.c -- OMAP ALSA SoC DAI driver using McBSP port
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <asm/arch/control.h>
+#include <asm/arch/dma.h>
+#include <asm/arch/mcbsp.h>
+#include "omap-mcbsp.h"
+#include "omap-pcm.h"
+
+#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | \
+ SNDRV_PCM_RATE_KNOT)
+
+struct omap_mcbsp_data {
+ unsigned int bus_id;
+ struct omap_mcbsp_reg_cfg regs;
+ /*
+ * Flags indicating is the bus already activated and configured by
+ * another substream
+ */
+ int active;
+ int configured;
+};
+
+#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
+
+static struct omap_mcbsp_data mcbsp_data[NUM_LINKS];
+
+/*
+ * Stream DMA parameters. DMA request line and port address are set runtime
+ * since they are different between OMAP1 and later OMAPs
+ */
+static struct omap_pcm_dma_data omap_mcbsp_dai_dma_params[NUM_LINKS][2] = {
+{
+ { .name = "I2S PCM Stereo out", },
+ { .name = "I2S PCM Stereo in", },
+},
+};
+
+#if defined(CONFIG_ARCH_OMAP15XX) || defined(CONFIG_ARCH_OMAP16XX)
+static const int omap1_dma_reqs[][2] = {
+ { OMAP_DMA_MCBSP1_TX, OMAP_DMA_MCBSP1_RX },
+ { OMAP_DMA_MCBSP2_TX, OMAP_DMA_MCBSP2_RX },
+ { OMAP_DMA_MCBSP3_TX, OMAP_DMA_MCBSP3_RX },
+};
+static const unsigned long omap1_mcbsp_port[][2] = {
+ { OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
+ OMAP1510_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
+ { OMAP1510_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1,
+ OMAP1510_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
+ { OMAP1510_MCBSP3_BASE + OMAP_MCBSP_REG_DXR1,
+ OMAP1510_MCBSP3_BASE + OMAP_MCBSP_REG_DRR1 },
+};
+#else
+static const int omap1_dma_reqs[][2] = {};
+static const unsigned long omap1_mcbsp_port[][2] = {};
+#endif
+#if defined(CONFIG_ARCH_OMAP2420)
+static const int omap2420_dma_reqs[][2] = {
+ { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX },
+ { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX },
+};
+static const unsigned long omap2420_mcbsp_port[][2] = {
+ { OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR1,
+ OMAP24XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR1 },
+ { OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DXR1,
+ OMAP24XX_MCBSP2_BASE + OMAP_MCBSP_REG_DRR1 },
+};
+#else
+static const int omap2420_dma_reqs[][2] = {};
+static const unsigned long omap2420_mcbsp_port[][2] = {};
+#endif
+
+static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ int err = 0;
+
+ if (!cpu_dai->active)
+ err = omap_mcbsp_request(mcbsp_data->bus_id);
+
+ return err;
+}
+
+static void omap_mcbsp_dai_shutdown(struct snd_pcm_substream *substream)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+
+ if (!cpu_dai->active) {
+ omap_mcbsp_free(mcbsp_data->bus_id);
+ mcbsp_data->configured = 0;
+ }
+}
+
+static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ int err = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ if (!mcbsp_data->active++)
+ omap_mcbsp_start(mcbsp_data->bus_id);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ if (!--mcbsp_data->active)
+ omap_mcbsp_stop(mcbsp_data->bus_id);
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ return err;
+}
+
+static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+ int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
+ unsigned long port;
+
+ if (cpu_class_is_omap1()) {
+ dma = omap1_dma_reqs[bus_id][substream->stream];
+ port = omap1_mcbsp_port[bus_id][substream->stream];
+ } else if (cpu_is_omap2420()) {
+ dma = omap2420_dma_reqs[bus_id][substream->stream];
+ port = omap2420_mcbsp_port[bus_id][substream->stream];
+ } else {
+ /*
+ * TODO: Add support for 2430 and 3430
+ */
+ return -ENODEV;
+ }
+ omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
+ omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
+ cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
+
+ if (mcbsp_data->configured) {
+ /* McBSP already configured by another stream */
+ return 0;
+ }
+
+ switch (params_channels(params)) {
+ case 2:
+ /* Set 1 word per (McBPSP) frame and use dual-phase frames */
+ regs->rcr2 |= RFRLEN2(1 - 1) | RPHASE;
+ regs->rcr1 |= RFRLEN1(1 - 1);
+ regs->xcr2 |= XFRLEN2(1 - 1) | XPHASE;
+ regs->xcr1 |= XFRLEN1(1 - 1);
+ break;
+ default:
+ /* Unsupported number of channels */
+ return -EINVAL;
+ }
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ /* Set word lengths */
+ regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16);
+ regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16);
+ regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16);
+ regs->xcr1 |= XWDLEN1(OMAP_MCBSP_WORD_16);
+ /* Set FS period and length in terms of bit clock periods */
+ regs->srgr2 |= FPER(16 * 2 - 1);
+ regs->srgr1 |= FWID(16 - 1);
+ break;
+ default:
+ /* Unsupported PCM format */
+ return -EINVAL;
+ }
+
+ omap_mcbsp_config(bus_id, &mcbsp_data->regs);
+ mcbsp_data->configured = 1;
+
+ return 0;
+}
+
+/*
+ * This must be called before _set_clkdiv and _set_sysclk since McBSP register
+ * cache is initialized here
+ */
+static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+
+ if (mcbsp_data->configured)
+ return 0;
+
+ memset(regs, 0, sizeof(*regs));
+ /* Generic McBSP register settings */
+ regs->spcr2 |= XINTM(3) | FREE;
+ regs->spcr1 |= RINTM(3);
+ regs->rcr2 |= RFIG;
+ regs->xcr2 |= XFIG;
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* 1-bit data delay */
+ regs->rcr2 |= RDATDLY(1);
+ regs->xcr2 |= XDATDLY(1);
+ break;
+ default:
+ /* Unsupported data format */
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ /* McBSP master. Set FS and bit clocks as outputs */
+ regs->pcr0 |= FSXM | FSRM |
+ CLKXM | CLKRM;
+ /* Sample rate generator drives the FS */
+ regs->srgr2 |= FSGM;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFM:
+ /* McBSP slave */
+ break;
+ default:
+ /* Unsupported master/slave configuration */
+ return -EINVAL;
+ }
+
+ /* Set bit clock (CLKX/CLKR) and FS polarities */
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ /*
+ * Normal BCLK + FS.
+ * FS active low. TX data driven on falling edge of bit clock
+ * and RX data sampled on rising edge of bit clock.
+ */
+ regs->pcr0 |= FSXP | FSRP |
+ CLKXP | CLKRP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ regs->pcr0 |= CLKXP | CLKRP;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ regs->pcr0 |= FSXP | FSRP;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int omap_mcbsp_dai_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+ int div_id, int div)
+{
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+
+ if (div_id != OMAP_MCBSP_CLKGDV)
+ return -ENODEV;
+
+ regs->srgr1 |= CLKGDV(div - 1);
+
+ return 0;
+}
+
+static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data,
+ int clk_id)
+{
+ int sel_bit;
+ u16 reg;
+
+ if (cpu_class_is_omap1()) {
+ /* OMAP1's can use only external source clock */
+ if (unlikely(clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK))
+ return -EINVAL;
+ else
+ return 0;
+ }
+
+ switch (mcbsp_data->bus_id) {
+ case 0:
+ reg = OMAP2_CONTROL_DEVCONF0;
+ sel_bit = 2;
+ break;
+ case 1:
+ reg = OMAP2_CONTROL_DEVCONF0;
+ sel_bit = 6;
+ break;
+ /* TODO: Support for ports 3 - 5 in OMAP2430 and OMAP34xx */
+ default:
+ return -EINVAL;
+ }
+
+ if (cpu_class_is_omap2()) {
+ if (clk_id == OMAP_MCBSP_SYSCLK_CLKS_FCLK) {
+ omap_ctrl_writel(omap_ctrl_readl(reg) &
+ ~(1 << sel_bit), reg);
+ } else {
+ omap_ctrl_writel(omap_ctrl_readl(reg) |
+ (1 << sel_bit), reg);
+ }
+ }
+
+ return 0;
+}
+
+static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+ int clk_id, unsigned int freq,
+ int dir)
+{
+ struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+ struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
+ int err = 0;
+
+ switch (clk_id) {
+ case OMAP_MCBSP_SYSCLK_CLK:
+ regs->srgr2 |= CLKSM;
+ break;
+ case OMAP_MCBSP_SYSCLK_CLKS_FCLK:
+ case OMAP_MCBSP_SYSCLK_CLKS_EXT:
+ err = omap_mcbsp_dai_set_clks_src(mcbsp_data, clk_id);
+ break;
+
+ case OMAP_MCBSP_SYSCLK_CLKX_EXT:
+ regs->srgr2 |= CLKSM;
+ case OMAP_MCBSP_SYSCLK_CLKR_EXT:
+ regs->pcr0 |= SCLKME;
+ break;
+ default:
+ err = -ENODEV;
+ }
+
+ return err;
+}
+
+struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS] = {
+{
+ .name = "omap-mcbsp-dai",
+ .id = 0,
+ .type = SND_SOC_DAI_I2S,
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = OMAP_MCBSP_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = OMAP_MCBSP_RATES,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = {
+ .startup = omap_mcbsp_dai_startup,
+ .shutdown = omap_mcbsp_dai_shutdown,
+ .trigger = omap_mcbsp_dai_trigger,
+ .hw_params = omap_mcbsp_dai_hw_params,
+ },
+ .dai_ops = {
+ .set_fmt = omap_mcbsp_dai_set_dai_fmt,
+ .set_clkdiv = omap_mcbsp_dai_set_clkdiv,
+ .set_sysclk = omap_mcbsp_dai_set_dai_sysclk,
+ },
+ .private_data = &mcbsp_data[0].bus_id,
+},
+};
+EXPORT_SYMBOL_GPL(omap_mcbsp_dai);
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
+MODULE_DESCRIPTION("OMAP I2S SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h
new file mode 100644
index 0000000..9965fd4
--- /dev/null
+++ b/sound/soc/omap/omap-mcbsp.h
@@ -0,0 +1,49 @@
+/*
+ * omap-mcbsp.h
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_I2S_H__
+#define __OMAP_I2S_H__
+
+/* Source clocks for McBSP sample rate generator */
+enum omap_mcbsp_clksrg_clk {
+ OMAP_MCBSP_SYSCLK_CLKS_FCLK, /* Internal FCLK */
+ OMAP_MCBSP_SYSCLK_CLKS_EXT, /* External CLKS pin */
+ OMAP_MCBSP_SYSCLK_CLK, /* Internal ICLK */
+ OMAP_MCBSP_SYSCLK_CLKX_EXT, /* External CLKX pin */
+ OMAP_MCBSP_SYSCLK_CLKR_EXT, /* External CLKR pin */
+};
+
+/* McBSP dividers */
+enum omap_mcbsp_div {
+ OMAP_MCBSP_CLKGDV, /* Sample rate generator divider */
+};
+
+/*
+ * REVISIT: Preparation for the ASoC v2. Let the number of available links to
+ * be same than number of McBSP ports found in OMAP(s) we are compiling for.
+ */
+#define NUM_LINKS 1
+
+extern struct snd_soc_cpu_dai omap_mcbsp_dai[NUM_LINKS];
+
+#endif
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
new file mode 100644
index 0000000..6237020
--- /dev/null
+++ b/sound/soc/omap/omap-pcm.c
@@ -0,0 +1,357 @@
+/*
+ * omap-pcm.c -- ALSA PCM interface for the OMAP SoC
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/arch/dma.h>
+#include "omap-pcm.h"
+
+static const struct snd_pcm_hardware omap_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_PAUSE |
+ SNDRV_PCM_INFO_RESUME,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .period_bytes_min = 32,
+ .period_bytes_max = 64 * 1024,
+ .periods_min = 2,
+ .periods_max = 255,
+ .buffer_bytes_max = 128 * 1024,
+};
+
+struct omap_runtime_data {
+ spinlock_t lock;
+ struct omap_pcm_dma_data *dma_data;
+ int dma_ch;
+ int period_index;
+};
+
+static void omap_pcm_dma_irq(int ch, u16 stat, void *data)
+{
+ struct snd_pcm_substream *substream = data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct omap_runtime_data *prtd = runtime->private_data;
+ unsigned long flags;
+
+ if (cpu_is_omap1510()) {
+ /*
+ * OMAP1510 doesn't support DMA chaining so have to restart
+ * the transfer after all periods are transferred
+ */
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (prtd->period_index >= 0) {
+ if (++prtd->period_index == runtime->periods) {
+ prtd->period_index = 0;
+ omap_start_dma(prtd->dma_ch);
+ }
+ }
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ }
+
+ snd_pcm_period_elapsed(substream);
+}
+
+/* this may get called several times by oss emulation */
+static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct omap_runtime_data *prtd = runtime->private_data;
+ struct omap_pcm_dma_data *dma_data = rtd->dai->cpu_dai->dma_data;
+ int err = 0;
+
+ if (!dma_data)
+ return -ENODEV;
+
+ snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+ runtime->dma_bytes = params_buffer_bytes(params);
+
+ if (prtd->dma_data)
+ return 0;
+ prtd->dma_data = dma_data;
+ err = omap_request_dma(dma_data->dma_req, dma_data->name,
+ omap_pcm_dma_irq, substream, &prtd->dma_ch);
+ if (!cpu_is_omap1510()) {
+ /*
+ * Link channel with itself so DMA doesn't need any
+ * reprogramming while looping the buffer
+ */
+ omap_dma_link_lch(prtd->dma_ch, prtd->dma_ch);
+ }
+
+ return err;
+}
+
+static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct omap_runtime_data *prtd = runtime->private_data;
+
+ if (prtd->dma_data == NULL)
+ return 0;
+
+ if (!cpu_is_omap1510())
+ omap_dma_unlink_lch(prtd->dma_ch, prtd->dma_ch);
+ omap_free_dma(prtd->dma_ch);
+ prtd->dma_data = NULL;
+
+ snd_pcm_set_runtime_buffer(substream, NULL);
+
+ return 0;
+}
+
+static int omap_pcm_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct omap_runtime_data *prtd = runtime->private_data;
+ struct omap_pcm_dma_data *dma_data = prtd->dma_data;
+ struct omap_dma_channel_params dma_params;
+
+ memset(&dma_params, 0, sizeof(dma_params));
+ /*
+ * Note: Regardless of interface data formats supported by OMAP McBSP
+ * or EAC blocks, internal representation is always fixed 16-bit/sample
+ */
+ dma_params.data_type = OMAP_DMA_DATA_TYPE_S16;
+ dma_params.trigger = dma_data->dma_req;
+ dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dma_params.src_amode = OMAP_DMA_AMODE_POST_INC;
+ dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT;
+ dma_params.src_or_dst_synch = OMAP_DMA_DST_SYNC;
+ dma_params.src_start = runtime->dma_addr;
+ dma_params.dst_start = dma_data->port_addr;
+ } else {
+ dma_params.src_amode = OMAP_DMA_AMODE_CONSTANT;
+ dma_params.dst_amode = OMAP_DMA_AMODE_POST_INC;
+ dma_params.src_or_dst_synch = OMAP_DMA_SRC_SYNC;
+ dma_params.src_start = dma_data->port_addr;
+ dma_params.dst_start = runtime->dma_addr;
+ }
+ /*
+ * Set DMA transfer frame size equal to ALSA period size and frame
+ * count as no. of ALSA periods. Then with DMA frame interrupt enabled,
+ * we can transfer the whole ALSA buffer with single DMA transfer but
+ * still can get an interrupt at each period bounary
+ */
+ dma_params.elem_count = snd_pcm_lib_period_bytes(substream) / 2;
+ dma_params.frame_count = runtime->periods;
+ omap_set_dma_params(prtd->dma_ch, &dma_params);
+
+ omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
+
+ return 0;
+}
+
+static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct omap_runtime_data *prtd = runtime->private_data;
+ int ret = 0;
+
+ spin_lock_irq(&prtd->lock);
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ prtd->period_index = 0;
+ omap_start_dma(prtd->dma_ch);
+ break;
+
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ prtd->period_index = -1;
+ omap_stop_dma(prtd->dma_ch);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ spin_unlock_irq(&prtd->lock);
+
+ return ret;
+}
+
+static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct omap_runtime_data *prtd = runtime->private_data;
+ dma_addr_t ptr;
+ snd_pcm_uframes_t offset;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ptr = omap_get_dma_src_pos(prtd->dma_ch);
+ else
+ ptr = omap_get_dma_dst_pos(prtd->dma_ch);
+
+ offset = bytes_to_frames(runtime, ptr - runtime->dma_addr);
+ if (offset >= runtime->buffer_size)
+ offset = 0;
+
+ return offset;
+}
+
+static int omap_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct omap_runtime_data *prtd;
+ int ret;
+
+ snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
+
+ /* Ensure that buffer size is a multiple of period size */
+ ret = snd_pcm_hw_constraint_integer(runtime,
+ SNDRV_PCM_HW_PARAM_PERIODS);
+ if (ret < 0)
+ goto out;
+
+ prtd = kzalloc(sizeof(prtd), GFP_KERNEL);
+ if (prtd == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ spin_lock_init(&prtd->lock);
+ runtime->private_data = prtd;
+
+out:
+ return ret;
+}
+
+static int omap_pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ kfree(runtime->private_data);
+ return 0;
+}
+
+static int omap_pcm_mmap(struct snd_pcm_substream *substream,
+ struct vm_area_struct *vma)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
+}
+
+struct snd_pcm_ops omap_pcm_ops = {
+ .open = omap_pcm_open,
+ .close = omap_pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = omap_pcm_hw_params,
+ .hw_free = omap_pcm_hw_free,
+ .prepare = omap_pcm_prepare,
+ .trigger = omap_pcm_trigger,
+ .pointer = omap_pcm_pointer,
+ .mmap = omap_pcm_mmap,
+};
+
+static u64 omap_pcm_dmamask = DMA_BIT_MASK(32);
+
+static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
+ int stream)
+{
+ struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+ struct snd_dma_buffer *buf = &substream->dma_buffer;
+ size_t size = omap_pcm_hardware.buffer_bytes_max;
+
+ buf->dev.type = SNDRV_DMA_TYPE_DEV;
+ buf->dev.dev = pcm->card->dev;
+ buf->private_data = NULL;
+ buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+ &buf->addr, GFP_KERNEL);
+ if (!buf->area)
+ return -ENOMEM;
+
+ buf->bytes = size;
+ return 0;
+}
+
+static void omap_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+ struct snd_pcm_substream *substream;
+ struct snd_dma_buffer *buf;
+ int stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ substream = pcm->streams[stream].substream;
+ if (!substream)
+ continue;
+
+ buf = &substream->dma_buffer;
+ if (!buf->area)
+ continue;
+
+ dma_free_writecombine(pcm->card->dev, buf->bytes,
+ buf->area, buf->addr);
+ buf->area = NULL;
+ }
+}
+
+int omap_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
+ struct snd_pcm *pcm)
+{
+ int ret = 0;
+
+ if (!card->dev->dma_mask)
+ card->dev->dma_mask = &omap_pcm_dmamask;
+ if (!card->dev->coherent_dma_mask)
+ card->dev->coherent_dma_mask = DMA_32BIT_MASK;
+
+ if (dai->playback.channels_min) {
+ ret = omap_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_PLAYBACK);
+ if (ret)
+ goto out;
+ }
+
+ if (dai->capture.channels_min) {
+ ret = omap_pcm_preallocate_dma_buffer(pcm,
+ SNDRV_PCM_STREAM_CAPTURE);
+ if (ret)
+ goto out;
+ }
+
+out:
+ return ret;
+}
+
+struct snd_soc_platform omap_soc_platform = {
+ .name = "omap-pcm-audio",
+ .pcm_ops = &omap_pcm_ops,
+ .pcm_new = omap_pcm_new,
+ .pcm_free = omap_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(omap_soc_platform);
+
+MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@nokia.com>");
+MODULE_DESCRIPTION("OMAP PCM DMA module");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
new file mode 100644
index 0000000..e4369bd
--- /dev/null
+++ b/sound/soc/omap/omap-pcm.h
@@ -0,0 +1,35 @@
+/*
+ * omap-pcm.h
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ *
+ * Contact: Jarkko Nikula <jarkko.nikula@nokia.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.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef __OMAP_PCM_H__
+#define __OMAP_PCM_H__
+
+struct omap_pcm_dma_data {
+ char *name; /* stream identifier */
+ int dma_req; /* DMA request line */
+ unsigned long port_addr; /* transmit/receive register */
+};
+
+extern struct snd_soc_platform omap_soc_platform;
+
+#endif
diff --git a/sound/soc/s3c24xx/ln2440sbc_alc650.c b/sound/soc/s3c24xx/ln2440sbc_alc650.c
index 9ed8f2e..4eab2c1 100644
--- a/sound/soc/s3c24xx/ln2440sbc_alc650.c
+++ b/sound/soc/s3c24xx/ln2440sbc_alc650.c
@@ -1,10 +1,10 @@
/*
* SoC audio for ln2440sbc
- *
+ *
* Copyright 2007 KonekTel, a.s.
* Author: Ivan Kuten
* ivan.kuten@promwad.com
- *
+ *
* Heavily based on smdk2443_wm9710.c
* Copyright 2007 Wolfson Microelectronics PLC.
* Author: Graeme Gregory
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c
index 962cc20..0e9d1c5 100644
--- a/sound/soc/s3c24xx/neo1973_wm8753.c
+++ b/sound/soc/s3c24xx/neo1973_wm8753.c
@@ -33,7 +33,7 @@
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <asm/arch/audio.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/arch/spi-gpio.h>
#include <asm/plat-s3c24xx/regs-iis.h>
@@ -122,7 +122,7 @@
/* set MCLK division for sample rate */
ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK,
- S3C2410_IISMOD_32FS );
+ S3C2410_IISMOD_32FS);
if (ret < 0)
return ret;
@@ -133,7 +133,7 @@
/* set prescaler division for sample rate */
ret = cpu_dai->dai_ops.set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
- S3C24XX_PRESCALE(4,4));
+ S3C24XX_PRESCALE(4, 4));
if (ret < 0)
return ret;
@@ -222,7 +222,7 @@
.hw_free = neo1973_voice_hw_free,
};
-static int neo1973_scenario = 0;
+static int neo1973_scenario;
static int neo1973_get_scenario(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
@@ -233,7 +233,7 @@
static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
{
- switch(neo1973_scenario) {
+ switch (neo1973_scenario) {
case NEO_AUDIO_OFF:
snd_soc_dapm_set_endpoint(codec, "Audio Out", 0);
snd_soc_dapm_set_endpoint(codec, "GSM Line Out", 0);
@@ -334,7 +334,7 @@
static int lm4857_get_reg(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- int reg=kcontrol->private_value & 0xFF;
+ int reg = kcontrol->private_value & 0xFF;
int shift = (kcontrol->private_value >> 8) & 0x0F;
int mask = (kcontrol->private_value >> 16) & 0xFF;
@@ -349,11 +349,11 @@
int shift = (kcontrol->private_value >> 8) & 0x0F;
int mask = (kcontrol->private_value >> 16) & 0xFF;
- if (((lm4857_regs[reg] >> shift ) & mask) ==
+ if (((lm4857_regs[reg] >> shift) & mask) ==
ucontrol->value.integer.value[0])
return 0;
- lm4857_regs[reg] &= ~ (mask << shift);
+ lm4857_regs[reg] &= ~(mask << shift);
lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift;
lm4857_write_regs();
return 1;
@@ -398,7 +398,7 @@
/* example machine audio_mapnections */
-static const char* audio_map[][3] = {
+static const char *audio_map[][3] = {
/* Connections to the lm4857 amp */
{"Audio Out", NULL, "LOUT1"},
@@ -450,7 +450,7 @@
};
static const struct soc_enum neo_scenario_enum[] = {
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios),neo_scenarios),
+ SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios),
};
static const struct snd_kcontrol_new wm8753_neo1973_controls[] = {
@@ -521,8 +521,8 @@
/*
* BT Codec DAI
*/
-static struct snd_soc_cpu_dai bt_dai =
-{ .name = "Bluetooth",
+static struct snd_soc_cpu_dai bt_dai = {
+ .name = "Bluetooth",
.id = 0,
.type = SND_SOC_DAI_PCM,
.playback = {
@@ -616,6 +616,35 @@
return i2c_probe(adap, &addr_data, lm4857_amp_probe);
}
+static u8 lm4857_state;
+
+static int lm4857_suspend(struct i2c_client *dev, pm_message_t state)
+{
+ dev_dbg(&dev->dev, "lm4857_suspend\n");
+ lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf;
+ if (lm4857_state) {
+ lm4857_regs[LM4857_CTRL] &= 0xf0;
+ lm4857_write_regs();
+ }
+ return 0;
+}
+
+static int lm4857_resume(struct i2c_client *dev)
+{
+ if (lm4857_state) {
+ lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f);
+ lm4857_write_regs();
+ }
+ return 0;
+}
+
+static void lm4857_shutdown(struct i2c_client *dev)
+{
+ dev_dbg(&dev->dev, "lm4857_shutdown\n");
+ lm4857_regs[LM4857_CTRL] &= 0xf0;
+ lm4857_write_regs();
+}
+
/* corgi i2c codec control layer */
static struct i2c_driver lm4857_i2c_driver = {
.driver = {
@@ -623,6 +652,9 @@
.owner = THIS_MODULE,
},
.id = I2C_DRIVERID_LM4857,
+ .suspend = lm4857_suspend,
+ .resume = lm4857_resume,
+ .shutdown = lm4857_shutdown,
.attach_adapter = lm4857_i2c_attach,
.detach_client = lm4857_i2c_detach,
.command = NULL,
@@ -667,6 +699,6 @@
module_exit(neo1973_exit);
/* Module information */
-MODULE_AUTHOR("Graeme Gregory, graeme.gregory@wolfsonmicro.com, www.wolfsonmicro.com");
+MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org");
MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973");
MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c
index 1c1ddbf..e81d9a6 100644
--- a/sound/soc/s3c24xx/s3c2443-ac97.c
+++ b/sound/soc/s3c24xx/s3c2443-ac97.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/wait.h>
#include <linux/delay.h>
#include <linux/clk.h>
@@ -30,7 +31,6 @@
#include <sound/soc.h>
#include <asm/hardware.h>
-#include <asm/io.h>
#include <asm/plat-s3c/regs-ac97.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-clock.h>
@@ -47,7 +47,7 @@
};
static struct s3c24xx_ac97_info s3c24xx_ac97;
-DECLARE_COMPLETION(ac97_completion);
+static DECLARE_COMPLETION(ac97_completion);
static u32 codec_ready;
static DECLARE_MUTEX(ac97_mutex);
@@ -290,7 +290,7 @@
u32 ac_glbctrl;
ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
- switch(cmd) {
+ switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -333,7 +333,7 @@
u32 ac_glbctrl;
ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL);
- switch(cmd) {
+ switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -391,7 +391,6 @@
.trigger = s3c2443_ac97_mic_trigger,},
},
};
-
EXPORT_SYMBOL_GPL(s3c2443_ac97_dai);
EXPORT_SYMBOL_GPL(soc_ac97_ops);
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c
index 49580fb..6c70a81 100644
--- a/sound/soc/s3c24xx/s3c24xx-pcm.c
+++ b/sound/soc/s3c24xx/s3c24xx-pcm.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
@@ -30,7 +31,6 @@
#include <sound/soc.h>
#include <asm/dma.h>
-#include <asm/io.h>
#include <asm/hardware.h>
#include <asm/arch/dma.h>
#include <asm/arch/audio.h>
@@ -93,7 +93,7 @@
while (prtd->dma_loaded < prtd->dma_limit) {
unsigned long len = prtd->dma_period;
- DBG("dma_loaded: %d\n",prtd->dma_loaded);
+ DBG("dma_loaded: %d\n", prtd->dma_loaded);
if ((pos + len) > prtd->dma_end) {
len = prtd->dma_end - pos;
@@ -101,7 +101,7 @@
__func__, len);
}
- ret = s3c2410_dma_enqueue(prtd->params->channel,
+ ret = s3c2410_dma_enqueue(prtd->params->channel,
substream, pos, len);
if (ret == 0) {
@@ -129,7 +129,7 @@
return;
prtd = substream->runtime->private_data;
-
+
if (substream)
snd_pcm_period_elapsed(substream);
@@ -150,7 +150,7 @@
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct s3c24xx_pcm_dma_params *dma = rtd->dai->cpu_dai->dma_data;
unsigned long totbytes = params_buffer_bytes(params);
- int ret=0;
+ int ret = 0;
DBG("Entered %s\n", __func__);
@@ -223,7 +223,7 @@
/* return if this is a bufferless transfer e.g.
* codec <--> BT codec or GSM modem -- lg FIXME */
if (!prtd->params)
- return 0;
+ return 0;
/* channel needs configuring for mem=>device, increment memory addr,
* sync to pclk, half-word transfers to the IIS-FIFO. */
@@ -293,8 +293,8 @@
return ret;
}
-static snd_pcm_uframes_t
- s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
+static snd_pcm_uframes_t
+s3c24xx_pcm_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct s3c24xx_runtime_data *prtd = runtime->private_data;
@@ -313,7 +313,7 @@
spin_unlock(&prtd->lock);
- DBG("Pointer %x %x\n",src,dst);
+ DBG("Pointer %x %x\n", src, dst);
/* we seem to be getting the odd error from the pcm library due
* to out-of-bounds pointers. this is maybe due to the dma engine
@@ -355,11 +355,11 @@
DBG("Entered %s\n", __func__);
- if (prtd)
- kfree(prtd);
- else
+ if (!prtd)
DBG("s3c24xx_pcm_close called with prtd == NULL\n");
+ kfree(prtd);
+
return 0;
}
@@ -371,9 +371,9 @@
DBG("Entered %s\n", __func__);
return dma_mmap_writecombine(substream->pcm->card->dev, vma,
- runtime->dma_area,
- runtime->dma_addr,
- runtime->dma_bytes);
+ runtime->dma_area,
+ runtime->dma_addr,
+ runtime->dma_bytes);
}
static struct snd_pcm_ops s3c24xx_pcm_ops = {
@@ -432,7 +432,7 @@
static u64 s3c24xx_pcm_dmamask = DMA_32BIT_MASK;
-static int s3c24xx_pcm_new(struct snd_card *card,
+static int s3c24xx_pcm_new(struct snd_card *card,
struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
{
int ret = 0;
@@ -467,7 +467,6 @@
.pcm_new = s3c24xx_pcm_new,
.pcm_free = s3c24xx_pcm_free_dma_buffers,
};
-
EXPORT_SYMBOL_GPL(s3c24xx_soc_platform);
MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index c82cf15..e89338e 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -834,16 +834,9 @@
*/
static int create_vcpu_fd(struct kvm_vcpu *vcpu)
{
- int fd, r;
- struct inode *inode;
- struct file *file;
-
- r = anon_inode_getfd(&fd, &inode, &file,
- "kvm-vcpu", &kvm_vcpu_fops, vcpu);
- if (r) {
+ int fd = anon_inode_getfd("kvm-vcpu", &kvm_vcpu_fops, vcpu);
+ if (fd < 0)
kvm_put_kvm(vcpu->kvm);
- return r;
- }
return fd;
}
@@ -1168,19 +1161,15 @@
static int kvm_dev_ioctl_create_vm(void)
{
- int fd, r;
- struct inode *inode;
- struct file *file;
+ int fd;
struct kvm *kvm;
kvm = kvm_create_vm();
if (IS_ERR(kvm))
return PTR_ERR(kvm);
- r = anon_inode_getfd(&fd, &inode, &file, "kvm-vm", &kvm_vm_fops, kvm);
- if (r) {
+ fd = anon_inode_getfd("kvm-vm", &kvm_vm_fops, kvm);
+ if (fd < 0)
kvm_put_kvm(kvm);
- return r;
- }
return fd;
}