Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Dec 2009 18:09:16 +0000 (10:09 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 16 Dec 2009 18:09:16 +0000 (10:09 -0800)
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-2.6: (116 commits)
  V4L/DVB (13698): pms: replace asm/uaccess.h to linux/uaccess.h
  V4L/DVB (13690): radio/si470x: #include <sched.h>
  V4L/DVB (13688): au8522: modify the attributes of local filter coefficients
  V4L/DVB (13687): cx231xx: use NULL when pointer is needed
  V4L/DVB: Davinci VPFE Capture: remove unused #include <linux/version.h>
  V4L/DVB (13685): Correct code taking the size of a pointer
  V4L/DVB (13684): Fix some cut-and-paste noise in dib0090.h
  V4L/DVB (13683): sanio-ms: clean up init, exit and id_table
  V4L/DVB (13682): dib8000: make some constant static
  V4L/DVB: lgs8gxx: Use shifts rather than multiply/divide when possible
  V4L/DVB (13680b): DocBook/media: create links for included sources
  V4L/DVB (13680a): DocBook/media: copy images after building HTML
  V4L/DVB (13678): Add support for yet another DvbWorld, TeVii and Prof USB devices
  V4L/DVB (13676): configurable IRQ mode on NetUP Dual DVB-S2 CI; IRQ from CAM processing (CI interface works faster)
  V4L/DVB (13674): stv090x: Add DiSEqC envelope mode
  V4L/DVB (13673): lnbp21: Implement 22 kHz tone control
  V4L/DVB (13671): sh_mobile_ceu_camera: Remove frame size page alignment
  V4L/DVB (13670): soc-camera: Add mt9t112 camera driver
  V4L/DVB (13669): tw9910: Add sync polarity support
  V4L/DVB (13668): tw9910: remove cropping
  ...

217 files changed:
Documentation/DocBook/Makefile
Documentation/DocBook/procfs-guide.tmpl [deleted file]
Documentation/DocBook/procfs_example.c [deleted file]
Documentation/SubmitChecklist
Documentation/fb/viafb.txt
Documentation/filesystems/seq_file.txt
Documentation/gpio.txt
Documentation/kernel-parameters.txt
arch/alpha/include/asm/elf.h
arch/arm/include/asm/elf.h
arch/arm/mach-davinci/board-da850-evm.c
arch/avr32/include/asm/elf.h
arch/blackfin/include/asm/bfin-lq035q1.h [new file with mode: 0644]
arch/blackfin/include/asm/elf.h
arch/cris/include/asm/elf.h
arch/frv/include/asm/elf.h
arch/h8300/include/asm/elf.h
arch/ia64/ia32/elfcore32.h
arch/ia64/include/asm/dma-mapping.h
arch/ia64/include/asm/elf.h
arch/ia64/sn/pci/tioca_provider.c
arch/m32r/include/asm/elf.h
arch/m68k/include/asm/elf.h
arch/microblaze/include/asm/elf.h
arch/mips/include/asm/elf.h
arch/mn10300/include/asm/elf.h
arch/parisc/include/asm/elf.h
arch/powerpc/include/asm/dma-mapping.h
arch/powerpc/include/asm/elf.h
arch/powerpc/include/asm/ptrace.h
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/traps.c
arch/s390/include/asm/elf.h
arch/score/include/asm/elf.h
arch/sh/include/asm/elf.h
arch/sparc/include/asm/elf_32.h
arch/sparc/include/asm/elf_64.h
arch/sparc/kernel/iommu.c
arch/sparc/kernel/ldc.c
arch/sparc/mm/sun4c.c
arch/um/sys-i386/asm/elf.h
arch/um/sys-ppc/asm/elf.h
arch/um/sys-x86_64/asm/elf.h
arch/x86/include/asm/dma-mapping.h
arch/x86/include/asm/elf.h
arch/x86/include/asm/ptrace.h
arch/x86/include/asm/uv/bios.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/kernel/amd_iommu.c
arch/x86/kernel/bios_uv.c
arch/x86/kernel/pci-calgary_64.c
arch/x86/kernel/pci-gart_64.c
arch/x86/kernel/ptrace.c
arch/xtensa/include/asm/elf.h
drivers/char/efirtc.c
drivers/char/ipmi/ipmi_kcs_sm.c
drivers/char/sysrq.c
drivers/char/vt.c
drivers/edac/i5100_edac.c
drivers/gpio/Kconfig
drivers/gpio/Makefile
drivers/gpio/gpiolib.c
drivers/gpio/langwell_gpio.c
drivers/gpio/timbgpio.c [new file with mode: 0644]
drivers/misc/sgi-gru/gru.h
drivers/misc/sgi-gru/gru_instructions.h
drivers/misc/sgi-gru/grufault.c
drivers/misc/sgi-gru/grufile.c
drivers/misc/sgi-gru/gruhandles.c
drivers/misc/sgi-gru/gruhandles.h
drivers/misc/sgi-gru/grukdump.c
drivers/misc/sgi-gru/grukservices.c
drivers/misc/sgi-gru/grukservices.h
drivers/misc/sgi-gru/grulib.h
drivers/misc/sgi-gru/grumain.c
drivers/misc/sgi-gru/gruprocfs.c
drivers/misc/sgi-gru/grutables.h
drivers/misc/sgi-gru/grutlbpurge.c
drivers/misc/sgi-xp/xp.h
drivers/misc/sgi-xp/xp_main.c
drivers/misc/sgi-xp/xp_sn2.c
drivers/misc/sgi-xp/xp_uv.c
drivers/misc/sgi-xp/xpc_partition.c
drivers/misc/sgi-xp/xpc_uv.c
drivers/net/mlx4/alloc.c
drivers/parport/parport_pc.c
drivers/pnp/pnpbios/proc.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-at32ap700x.c
drivers/rtc/rtc-bq32k.c [new file with mode: 0644]
drivers/rtc/rtc-bq4802.c
drivers/rtc/rtc-cmos.c
drivers/rtc/rtc-ds1302.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-ds1553.c
drivers/rtc/rtc-ds1742.c
drivers/rtc/rtc-m48t35.c
drivers/rtc/rtc-m48t59.c
drivers/rtc/rtc-mc13783.c [new file with mode: 0644]
drivers/rtc/rtc-mv.c
drivers/rtc/rtc-nuc900.c [new file with mode: 0644]
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-pcf50633.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pcf8583.c
drivers/rtc/rtc-pl031.c
drivers/rtc/rtc-stk17ta8.c
drivers/rtc/rtc-tx4939.c
drivers/rtc/rtc-v3020.c
drivers/rtc/rtc-vr41xx.c
drivers/rtc/rtc-wm8350.c
drivers/rtc/rtc-x1205.c
drivers/usb/host/isp1362-hcd.c
drivers/video/Kconfig
drivers/video/Makefile
drivers/video/atafb.c
drivers/video/bfin-lq035q1-fb.c [new file with mode: 0644]
drivers/video/bfin-t350mcqb-fb.c
drivers/video/clps711xfb.c
drivers/video/da8xx-fb.c
drivers/video/ep93xx-fb.c
drivers/video/geode/lxfb.h
drivers/video/i810/i810_dvt.c
drivers/video/intelfb/intelfbdrv.c
drivers/video/intelfb/intelfbhw.c
drivers/video/intelfb/intelfbhw.h
drivers/video/matrox/g450_pll.c
drivers/video/maxinefb.c
drivers/video/mb862xx/Makefile
drivers/video/mb862xx/mb862xxfb.c
drivers/video/mb862xx/mb862xxfb.h
drivers/video/mb862xx/mb862xxfb_accel.c [new file with mode: 0644]
drivers/video/mb862xx/mb862xxfb_accel.h [new file with mode: 0644]
drivers/video/modedb.c
drivers/video/pmag-ba-fb.c
drivers/video/pmagb-b-fb.c
drivers/video/pxafb.c
drivers/video/sis/sis_main.c
drivers/video/sm501fb.c
drivers/video/via/lcd.c
drivers/video/via/viafbdev.c
fs/aio.c
fs/autofs4/autofs_i.h
fs/autofs4/expire.c
fs/autofs4/inode.c
fs/autofs4/root.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/direct-io.c
fs/ext2/dir.c
fs/ext2/ext2.h
fs/ext2/file.c
fs/ext2/super.c
fs/fat/misc.c
fs/fscache/object-list.c
fs/hpfs/super.c
fs/ocfs2/aops.c
fs/proc/base.c
fs/proc/generic.c
fs/proc/inode.c
fs/proc/internal.h
fs/qnx4/bitmap.c
fs/qnx4/inode.c
fs/reiserfs/Makefile
fs/reiserfs/procfs.c
fs/reiserfs/super.c
fs/ufs/dir.c
fs/ufs/namei.c
fs/ufs/super.c
fs/ufs/ufs.h
fs/xfs/linux-2.6/xfs_aops.c
include/asm-generic/gpio.h
include/linux/aio.h
include/linux/bitmap.h
include/linux/fs.h
include/linux/gpio.h
include/linux/iommu-helper.h
include/linux/ioport.h
include/linux/ipc_namespace.h
include/linux/kexec.h
include/linux/ksm.h
include/linux/memcontrol.h
include/linux/oom.h
include/linux/page_cgroup.h
include/linux/ptrace.h
include/linux/reiserfs_fs.h
include/linux/sched.h
include/linux/sem.h
include/linux/sm501-regs.h
include/linux/timb_gpio.h [new file with mode: 0644]
include/linux/tracehook.h
include/video/da8xx-fb.h
ipc/msg.c
ipc/sem.c
ipc/shm.c
kernel/fork.c
kernel/kexec.c
kernel/ksysfs.c
kernel/pid.c
kernel/relay.c
kernel/signal.c
kernel/time/timecompare.c
kernel/trace/trace.c
lib/bitmap.c
lib/genalloc.c
lib/iommu-helper.c
lib/swiotlb.c
mm/memcontrol.c
mm/memory.c
mm/oom_kill.c
mm/page_alloc.c
mm/rmap.c
mm/truncate.c
net/core/skbuff.c

index 50075df94962a81c3b52041ec90b9274bd8f3ffe..325cfd1d6d9929686c6f5c42f93272c3147a7b9c 100644 (file)
@@ -8,7 +8,7 @@
 
 DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
            kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
-           procfs-guide.xml writing_usb_driver.xml networking.xml \
+           writing_usb_driver.xml networking.xml \
            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 \
@@ -74,7 +74,7 @@ KERNELDOC = $(srctree)/scripts/kernel-doc
 DOCPROC   = $(objtree)/scripts/basic/docproc
 
 XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl
-#XMLTOFLAGS += --skip-validation
+XMLTOFLAGS += --skip-validation
 
 ###
 # DOCPROC is used for two purposes:
@@ -110,17 +110,6 @@ endif
 # Changes in kernel-doc force a rebuild of all documentation
 $(BOOKS): $(KERNELDOC)
 
-###
-# procfs guide uses a .c file as example code.
-# This requires an explicit dependency
-C-procfs-example = procfs_example.xml
-C-procfs-example2 = $(addprefix $(obj)/,$(C-procfs-example))
-$(obj)/procfs-guide.xml: $(C-procfs-example2)
-
-# List of programs to build
-##oops, this is a kernel module::hostprogs-y := procfs_example
-obj-m += procfs_example.o
-
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
 
@@ -247,7 +236,7 @@ clean-files := $(DOCBOOKS) \
        $(patsubst %.xml, %.pdf,  $(DOCBOOKS)) \
        $(patsubst %.xml, %.html, $(DOCBOOKS)) \
        $(patsubst %.xml, %.9,    $(DOCBOOKS)) \
-       $(C-procfs-example) $(index)
+       $(index)
 
 clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man
 
diff --git a/Documentation/DocBook/procfs-guide.tmpl b/Documentation/DocBook/procfs-guide.tmpl
deleted file mode 100644 (file)
index 9eba4b7..0000000
+++ /dev/null
@@ -1,626 +0,0 @@
-<?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" [
-<!ENTITY procfsexample SYSTEM "procfs_example.xml">
-]>
-
-<book id="LKProcfsGuide">
-  <bookinfo>
-    <title>Linux Kernel Procfs Guide</title>
-
-    <authorgroup>
-      <author>
-       <firstname>Erik</firstname>
-       <othername>(J.A.K.)</othername>
-       <surname>Mouw</surname>
-       <affiliation>
-         <address>
-            <email>mouw@nl.linux.org</email>
-          </address>
-       </affiliation>
-      </author>
-      <othercredit>
-       <contrib>
-       This software and documentation were written while working on the
-       LART computing board
-       (<ulink url="http://www.lartmaker.nl/">http://www.lartmaker.nl/</ulink>),
-       which was sponsored by the Delt University of Technology projects
-       Mobile Multi-media Communications and Ubiquitous Communications.
-       </contrib>
-      </othercredit>
-    </authorgroup>
-
-    <revhistory>
-      <revision>
-       <revnumber>1.0</revnumber>
-       <date>May 30, 2001</date>
-       <revremark>Initial revision posted to linux-kernel</revremark>
-      </revision>
-      <revision>
-       <revnumber>1.1</revnumber>
-       <date>June 3, 2001</date>
-       <revremark>Revised after comments from linux-kernel</revremark>
-      </revision>
-    </revhistory>
-
-    <copyright>
-      <year>2001</year>
-      <holder>Erik Mouw</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 as published by the Free Software Foundation; either
-        version 2 of the License, or (at your option) any later
-        version.
-      </para>
-      
-      <para>
-        This documentation 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>
-
-
-
-
-  <preface id="Preface">
-    <title>Preface</title>
-
-    <para>
-      This guide describes the use of the procfs file system from
-      within the Linux kernel. The idea to write this guide came up on
-      the #kernelnewbies IRC channel (see <ulink
-      url="http://www.kernelnewbies.org/">http://www.kernelnewbies.org/</ulink>),
-      when Jeff Garzik explained the use of procfs and forwarded me a
-      message Alexander Viro wrote to the linux-kernel mailing list. I
-      agreed to write it up nicely, so here it is.
-    </para>
-
-    <para>
-      I'd like to thank Jeff Garzik
-      <email>jgarzik@pobox.com</email> and Alexander Viro
-      <email>viro@parcelfarce.linux.theplanet.co.uk</email> for their input,
-      Tim Waugh <email>twaugh@redhat.com</email> for his <ulink
-      url="http://people.redhat.com/twaugh/docbook/selfdocbook/">Selfdocbook</ulink>,
-      and Marc Joosen <email>marcj@historia.et.tudelft.nl</email> for
-      proofreading.
-    </para>
-
-    <para>
-      Erik
-    </para>
-  </preface>
-
-
-
-
-  <chapter id="intro">
-    <title>Introduction</title>
-
-    <para>
-      The <filename class="directory">/proc</filename> file system
-      (procfs) is a special file system in the linux kernel. It's a
-      virtual file system: it is not associated with a block device
-      but exists only in memory. The files in the procfs are there to
-      allow userland programs access to certain information from the
-      kernel (like process information in <filename
-      class="directory">/proc/[0-9]+/</filename>), but also for debug
-      purposes (like <filename>/proc/ksyms</filename>).
-    </para>
-
-    <para>
-      This guide describes the use of the procfs file system from
-      within the Linux kernel. It starts by introducing all relevant
-      functions to manage the files within the file system. After that
-      it shows how to communicate with userland, and some tips and
-      tricks will be pointed out. Finally a complete example will be
-      shown.
-    </para>
-
-    <para>
-      Note that the files in <filename
-      class="directory">/proc/sys</filename> are sysctl files: they
-      don't belong to procfs and are governed by a completely
-      different API described in the Kernel API book.
-    </para>
-  </chapter>
-
-
-
-
-  <chapter id="managing">
-    <title>Managing procfs entries</title>
-    
-    <para>
-      This chapter describes the functions that various kernel
-      components use to populate the procfs with files, symlinks,
-      device nodes, and directories.
-    </para>
-
-    <para>
-      A minor note before we start: if you want to use any of the
-      procfs functions, be sure to include the correct header file! 
-      This should be one of the first lines in your code:
-    </para>
-
-    <programlisting>
-#include &lt;linux/proc_fs.h&gt;
-    </programlisting>
-
-
-
-
-    <sect1 id="regularfile">
-      <title>Creating a regular file</title>
-      
-      <funcsynopsis>
-       <funcprototype>
-         <funcdef>struct proc_dir_entry* <function>create_proc_entry</function></funcdef>
-         <paramdef>const char* <parameter>name</parameter></paramdef>
-         <paramdef>mode_t <parameter>mode</parameter></paramdef>
-         <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
-       </funcprototype>
-      </funcsynopsis>
-
-      <para>
-        This function creates a regular file with the name
-        <parameter>name</parameter>, file mode
-        <parameter>mode</parameter> in the directory
-        <parameter>parent</parameter>. To create a file in the root of
-        the procfs, use <constant>NULL</constant> as
-        <parameter>parent</parameter> parameter. When successful, the
-        function will return a pointer to the freshly created
-        <structname>struct proc_dir_entry</structname>; otherwise it
-        will return <constant>NULL</constant>. <xref
-        linkend="userland"/> describes how to do something useful with
-        regular files.
-      </para>
-
-      <para>
-        Note that it is specifically supported that you can pass a
-        path that spans multiple directories. For example
-        <function>create_proc_entry</function>(<parameter>"drivers/via0/info"</parameter>)
-        will create the <filename class="directory">via0</filename>
-        directory if necessary, with standard
-        <constant>0755</constant> permissions.
-      </para>
-
-    <para>
-      If you only want to be able to read the file, the function
-      <function>create_proc_read_entry</function> described in <xref
-      linkend="convenience"/> may be used to create and initialise
-      the procfs entry in one single call.
-    </para>
-    </sect1>
-
-
-
-
-    <sect1 id="Creating_a_symlink">
-      <title>Creating a symlink</title>
-
-      <funcsynopsis>
-       <funcprototype>
-         <funcdef>struct proc_dir_entry*
-         <function>proc_symlink</function></funcdef> <paramdef>const
-         char* <parameter>name</parameter></paramdef>
-         <paramdef>struct proc_dir_entry*
-         <parameter>parent</parameter></paramdef> <paramdef>const
-         char* <parameter>dest</parameter></paramdef>
-       </funcprototype>
-      </funcsynopsis>
-      
-      <para>
-        This creates a symlink in the procfs directory
-        <parameter>parent</parameter> that points from
-        <parameter>name</parameter> to
-        <parameter>dest</parameter>. This translates in userland to
-        <literal>ln -s</literal> <parameter>dest</parameter>
-        <parameter>name</parameter>.
-      </para>
-    </sect1>
-
-    <sect1 id="Creating_a_directory">
-      <title>Creating a directory</title>
-      
-      <funcsynopsis>
-       <funcprototype>
-         <funcdef>struct proc_dir_entry* <function>proc_mkdir</function></funcdef>
-         <paramdef>const char* <parameter>name</parameter></paramdef>
-         <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
-       </funcprototype>
-      </funcsynopsis>
-
-      <para>
-        Create a directory <parameter>name</parameter> in the procfs
-        directory <parameter>parent</parameter>.
-      </para>
-    </sect1>
-
-
-
-
-    <sect1 id="Removing_an_entry">
-      <title>Removing an entry</title>
-      
-      <funcsynopsis>
-       <funcprototype>
-         <funcdef>void <function>remove_proc_entry</function></funcdef>
-         <paramdef>const char* <parameter>name</parameter></paramdef>
-         <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
-       </funcprototype>
-      </funcsynopsis>
-
-      <para>
-        Removes the entry <parameter>name</parameter> in the directory
-        <parameter>parent</parameter> from the procfs. Entries are
-        removed by their <emphasis>name</emphasis>, not by the
-        <structname>struct proc_dir_entry</structname> returned by the
-        various create functions. Note that this function doesn't
-        recursively remove entries.
-      </para>
-
-      <para>
-        Be sure to free the <structfield>data</structfield> entry from
-        the <structname>struct proc_dir_entry</structname> before
-        <function>remove_proc_entry</function> is called (that is: if
-        there was some <structfield>data</structfield> allocated, of
-        course). See <xref linkend="usingdata"/> for more information
-        on using the <structfield>data</structfield> entry.
-      </para>
-    </sect1>
-  </chapter>
-
-
-
-
-  <chapter id="userland">
-    <title>Communicating with userland</title>
-    
-    <para>
-       Instead of reading (or writing) information directly from
-       kernel memory, procfs works with <emphasis>call back
-       functions</emphasis> for files: functions that are called when
-       a specific file is being read or written. Such functions have
-       to be initialised after the procfs file is created by setting
-       the <structfield>read_proc</structfield> and/or
-       <structfield>write_proc</structfield> fields in the
-       <structname>struct proc_dir_entry*</structname> that the
-       function <function>create_proc_entry</function> returned:
-    </para>
-
-    <programlisting>
-struct proc_dir_entry* entry;
-
-entry->read_proc = read_proc_foo;
-entry->write_proc = write_proc_foo;
-    </programlisting>
-
-    <para>
-      If you only want to use a the
-      <structfield>read_proc</structfield>, the function
-      <function>create_proc_read_entry</function> described in <xref
-      linkend="convenience"/> may be used to create and initialise the
-      procfs entry in one single call.
-    </para>
-
-
-
-    <sect1 id="Reading_data">
-      <title>Reading data</title>
-
-      <para>
-        The read function is a call back function that allows userland
-        processes to read data from the kernel. The read function
-        should have the following format:
-      </para>
-
-      <funcsynopsis>
-       <funcprototype>
-         <funcdef>int <function>read_func</function></funcdef>
-         <paramdef>char* <parameter>buffer</parameter></paramdef>
-         <paramdef>char** <parameter>start</parameter></paramdef>
-         <paramdef>off_t <parameter>off</parameter></paramdef>
-         <paramdef>int <parameter>count</parameter></paramdef>
-         <paramdef>int* <parameter>peof</parameter></paramdef>
-         <paramdef>void* <parameter>data</parameter></paramdef>
-       </funcprototype>
-      </funcsynopsis>
-
-      <para>
-        The read function should write its information into the
-        <parameter>buffer</parameter>, which will be exactly
-        <literal>PAGE_SIZE</literal> bytes long.
-      </para>
-
-      <para>
-        The parameter
-        <parameter>peof</parameter> should be used to signal that the
-        end of the file has been reached by writing
-        <literal>1</literal> to the memory location
-        <parameter>peof</parameter> points to.
-      </para>
-
-      <para>
-        The <parameter>data</parameter>
-        parameter can be used to create a single call back function for
-        several files, see <xref linkend="usingdata"/>.
-      </para>
-
-      <para>
-        The rest of the parameters and the return value are described
-       by a comment in <filename>fs/proc/generic.c</filename> as follows:
-      </para>
-
-      <blockquote>
-        <para>
-       You have three ways to return data:
-               </para>
-        <orderedlist>
-          <listitem>
-            <para>
-             Leave <literal>*start = NULL</literal>.  (This is the default.)
-             Put the data of the requested offset at that
-             offset within the buffer.  Return the number (<literal>n</literal>)
-             of bytes there are from the beginning of the
-             buffer up to the last byte of data.  If the
-             number of supplied bytes (<literal>= n - offset</literal>) is
-             greater than zero and you didn't signal eof
-             and the reader is prepared to take more data
-             you will be called again with the requested
-             offset advanced by the number of bytes
-             absorbed.  This interface is useful for files
-             no larger than the buffer.
-           </para>
-         </listitem>
-         <listitem>
-            <para>
-             Set <literal>*start</literal> to an unsigned long value less than
-             the buffer address but greater than zero.
-             Put the data of the requested offset at the
-             beginning of the buffer.  Return the number of
-             bytes of data placed there.  If this number is
-             greater than zero and you didn't signal eof
-             and the reader is prepared to take more data
-             you will be called again with the requested
-             offset advanced by <literal>*start</literal>.  This interface is
-             useful when you have a large file consisting
-             of a series of blocks which you want to count
-             and return as wholes.
-             (Hack by Paul.Russell@rustcorp.com.au)
-           </para>
-         </listitem>
-         <listitem>
-            <para>
-             Set <literal>*start</literal> to an address within the buffer.
-             Put the data of the requested offset at <literal>*start</literal>.
-             Return the number of bytes of data placed there.
-             If this number is greater than zero and you
-             didn't signal eof and the reader is prepared to
-             take more data you will be called again with the
-             requested offset advanced by the number of bytes
-             absorbed.
-           </para>
-         </listitem>
-       </orderedlist>
-      </blockquote>
-
-      <para>
-        <xref linkend="example"/> shows how to use a read call back
-        function.
-      </para>
-    </sect1>
-
-
-
-
-    <sect1 id="Writing_data">
-      <title>Writing data</title>
-
-      <para>
-        The write call back function allows a userland process to write
-        data to the kernel, so it has some kind of control over the
-        kernel. The write function should have the following format:
-      </para>
-
-      <funcsynopsis>
-       <funcprototype>
-         <funcdef>int <function>write_func</function></funcdef>
-         <paramdef>struct file* <parameter>file</parameter></paramdef>
-         <paramdef>const char* <parameter>buffer</parameter></paramdef>
-         <paramdef>unsigned long <parameter>count</parameter></paramdef>
-         <paramdef>void* <parameter>data</parameter></paramdef>
-       </funcprototype>
-      </funcsynopsis>
-
-      <para>
-        The write function should read <parameter>count</parameter>
-        bytes at maximum from the <parameter>buffer</parameter>. Note
-        that the <parameter>buffer</parameter> doesn't live in the
-        kernel's memory space, so it should first be copied to kernel
-        space with <function>copy_from_user</function>. The
-        <parameter>file</parameter> parameter is usually
-        ignored. <xref linkend="usingdata"/> shows how to use the
-        <parameter>data</parameter> parameter.
-      </para>
-
-      <para>
-        Again, <xref linkend="example"/> shows how to use this call back
-        function.
-      </para>
-    </sect1>
-
-
-
-
-    <sect1 id="usingdata">
-      <title>A single call back for many files</title>
-
-      <para>
-         When a large number of almost identical files is used, it's
-         quite inconvenient to use a separate call back function for
-         each file. A better approach is to have a single call back
-         function that distinguishes between the files by using the
-         <structfield>data</structfield> field in <structname>struct
-         proc_dir_entry</structname>. First of all, the
-         <structfield>data</structfield> field has to be initialised:
-      </para>
-
-      <programlisting>
-struct proc_dir_entry* entry;
-struct my_file_data *file_data;
-
-file_data = kmalloc(sizeof(struct my_file_data), GFP_KERNEL);
-entry->data = file_data;
-      </programlisting>
-     
-      <para>
-          The <structfield>data</structfield> field is a <type>void
-          *</type>, so it can be initialised with anything.
-      </para>
-
-      <para>
-        Now that the <structfield>data</structfield> field is set, the
-        <function>read_proc</function> and
-        <function>write_proc</function> can use it to distinguish
-        between files because they get it passed into their
-        <parameter>data</parameter> parameter:
-      </para>
-
-      <programlisting>
-int foo_read_func(char *page, char **start, off_t off,
-                  int count, int *eof, void *data)
-{
-        int len;
-
-        if(data == file_data) {
-                /* special case for this file */
-        } else {
-                /* normal processing */
-        }
-
-        return len;
-}
-      </programlisting>
-
-      <para>
-        Be sure to free the <structfield>data</structfield> data field
-        when removing the procfs entry.
-      </para>
-    </sect1>
-  </chapter>
-
-
-
-
-  <chapter id="tips">
-    <title>Tips and tricks</title>
-
-
-
-
-    <sect1 id="convenience">
-      <title>Convenience functions</title>
-
-      <funcsynopsis>
-       <funcprototype>
-         <funcdef>struct proc_dir_entry* <function>create_proc_read_entry</function></funcdef>
-         <paramdef>const char* <parameter>name</parameter></paramdef>
-         <paramdef>mode_t <parameter>mode</parameter></paramdef>
-         <paramdef>struct proc_dir_entry* <parameter>parent</parameter></paramdef>
-         <paramdef>read_proc_t* <parameter>read_proc</parameter></paramdef>
-         <paramdef>void* <parameter>data</parameter></paramdef>
-       </funcprototype>
-      </funcsynopsis>
-      
-      <para>
-        This function creates a regular file in exactly the same way
-        as <function>create_proc_entry</function> from <xref
-        linkend="regularfile"/> does, but also allows to set the read
-        function <parameter>read_proc</parameter> in one call. This
-        function can set the <parameter>data</parameter> as well, like
-        explained in <xref linkend="usingdata"/>.
-      </para>
-    </sect1>
-
-
-
-    <sect1 id="Modules">
-      <title>Modules</title>
-
-      <para>
-        If procfs is being used from within a module, be sure to set
-        the <structfield>owner</structfield> field in the
-        <structname>struct proc_dir_entry</structname> to
-        <constant>THIS_MODULE</constant>.
-      </para>
-
-      <programlisting>
-struct proc_dir_entry* entry;
-
-entry->owner = THIS_MODULE;
-      </programlisting>
-    </sect1>
-
-
-
-
-    <sect1 id="Mode_and_ownership">
-      <title>Mode and ownership</title>
-
-      <para>
-        Sometimes it is useful to change the mode and/or ownership of
-        a procfs entry. Here is an example that shows how to achieve
-        that:
-      </para>
-
-      <programlisting>
-struct proc_dir_entry* entry;
-
-entry->mode =  S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH;
-entry->uid = 0;
-entry->gid = 100;
-      </programlisting>
-
-    </sect1>
-  </chapter>
-
-
-
-
-  <chapter id="example">
-    <title>Example</title>
-
-    <!-- be careful with the example code: it shouldn't be wider than
-    approx. 60 columns, or otherwise it won't fit properly on a page
-    -->
-
-&procfsexample;
-
-  </chapter>
-</book>
diff --git a/Documentation/DocBook/procfs_example.c b/Documentation/DocBook/procfs_example.c
deleted file mode 100644 (file)
index a5b1179..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * procfs_example.c: an example proc interface
- *
- * Copyright (C) 2001, Erik Mouw (mouw@nl.linux.org)
- *
- * This file accompanies the procfs-guide in the Linux kernel
- * source. Its main use is to demonstrate the concepts and
- * functions described in the guide.
- *
- * This software has been developed while working on the LART
- * computing board (http://www.lartmaker.nl), which was sponsored
- * by the Delt University of Technology projects Mobile Multi-media
- * Communications and Ubiquitous Communications.
- *
- * This program is free software; you can redistribute
- * it and/or modify it under the terms of the 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/init.h>
-#include <linux/proc_fs.h>
-#include <linux/jiffies.h>
-#include <asm/uaccess.h>
-
-
-#define MODULE_VERS "1.0"
-#define MODULE_NAME "procfs_example"
-
-#define FOOBAR_LEN 8
-
-struct fb_data_t {
-       char name[FOOBAR_LEN + 1];
-       char value[FOOBAR_LEN + 1];
-};
-
-
-static struct proc_dir_entry *example_dir, *foo_file,
-       *bar_file, *jiffies_file, *symlink;
-
-
-struct fb_data_t foo_data, bar_data;
-
-
-static int proc_read_jiffies(char *page, char **start,
-                            off_t off, int count,
-                            int *eof, void *data)
-{
-       int len;
-
-       len = sprintf(page, "jiffies = %ld\n",
-                      jiffies);
-
-       return len;
-}
-
-
-static int proc_read_foobar(char *page, char **start,
-                           off_t off, int count, 
-                           int *eof, void *data)
-{
-       int len;
-       struct fb_data_t *fb_data = (struct fb_data_t *)data;
-
-       /* DON'T DO THAT - buffer overruns are bad */
-       len = sprintf(page, "%s = '%s'\n", 
-                     fb_data->name, fb_data->value);
-
-       return len;
-}
-
-
-static int proc_write_foobar(struct file *file,
-                            const char *buffer,
-                            unsigned long count, 
-                            void *data)
-{
-       int len;
-       struct fb_data_t *fb_data = (struct fb_data_t *)data;
-
-       if(count > FOOBAR_LEN)
-               len = FOOBAR_LEN;
-       else
-               len = count;
-
-       if(copy_from_user(fb_data->value, buffer, len))
-               return -EFAULT;
-
-       fb_data->value[len] = '\0';
-
-       return len;
-}
-
-
-static int __init init_procfs_example(void)
-{
-       int rv = 0;
-
-       /* create directory */
-       example_dir = proc_mkdir(MODULE_NAME, NULL);
-       if(example_dir == NULL) {
-               rv = -ENOMEM;
-               goto out;
-       }
-       /* create jiffies using convenience function */
-       jiffies_file = create_proc_read_entry("jiffies", 
-                                             0444, example_dir, 
-                                             proc_read_jiffies,
-                                             NULL);
-       if(jiffies_file == NULL) {
-               rv  = -ENOMEM;
-               goto no_jiffies;
-       }
-
-       /* create foo and bar files using same callback
-        * functions 
-        */
-       foo_file = create_proc_entry("foo", 0644, example_dir);
-       if(foo_file == NULL) {
-               rv = -ENOMEM;
-               goto no_foo;
-       }
-
-       strcpy(foo_data.name, "foo");
-       strcpy(foo_data.value, "foo");
-       foo_file->data = &foo_data;
-       foo_file->read_proc = proc_read_foobar;
-       foo_file->write_proc = proc_write_foobar;
-               
-       bar_file = create_proc_entry("bar", 0644, example_dir);
-       if(bar_file == NULL) {
-               rv = -ENOMEM;
-               goto no_bar;
-       }
-
-       strcpy(bar_data.name, "bar");
-       strcpy(bar_data.value, "bar");
-       bar_file->data = &bar_data;
-       bar_file->read_proc = proc_read_foobar;
-       bar_file->write_proc = proc_write_foobar;
-               
-       /* create symlink */
-       symlink = proc_symlink("jiffies_too", example_dir, 
-                              "jiffies");
-       if(symlink == NULL) {
-               rv = -ENOMEM;
-               goto no_symlink;
-       }
-
-       /* everything OK */
-       printk(KERN_INFO "%s %s initialised\n",
-              MODULE_NAME, MODULE_VERS);
-       return 0;
-
-no_symlink:
-       remove_proc_entry("bar", example_dir);
-no_bar:
-       remove_proc_entry("foo", example_dir);
-no_foo:
-       remove_proc_entry("jiffies", example_dir);
-no_jiffies:                          
-       remove_proc_entry(MODULE_NAME, NULL);
-out:
-       return rv;
-}
-
-
-static void __exit cleanup_procfs_example(void)
-{
-       remove_proc_entry("jiffies_too", example_dir);
-       remove_proc_entry("bar", example_dir);
-       remove_proc_entry("foo", example_dir);
-       remove_proc_entry("jiffies", example_dir);
-       remove_proc_entry(MODULE_NAME, NULL);
-
-       printk(KERN_INFO "%s %s removed\n",
-              MODULE_NAME, MODULE_VERS);
-}
-
-
-module_init(init_procfs_example);
-module_exit(cleanup_procfs_example);
-
-MODULE_AUTHOR("Erik Mouw");
-MODULE_DESCRIPTION("procfs examples");
-MODULE_LICENSE("GPL");
index 78a9168ff37784ff9692e18a241d930b268f543d..1053a56be3b180c8ce202380ed9e882b5d97914a 100644 (file)
@@ -15,7 +15,7 @@ kernel patches.
 2: Passes allnoconfig, allmodconfig
 
 3: Builds on multiple CPU architectures by using local cross-compile tools
-   or something like PLM at OSDL.
+   or some other build farm.
 
 4: ppc64 is a good architecture for cross-compilation checking because it
    tends to use `unsigned long' for 64-bit quantities.
@@ -88,3 +88,6 @@ kernel patches.
 
 24: All memory barriers {e.g., barrier(), rmb(), wmb()} need a comment in the
     source code that explains the logic of what they are doing and why.
+
+25: If any ioctl's are added by the patch, then also update
+    Documentation/ioctl/ioctl-number.txt.
index 67dbf442b0b6c6ce8a2a04a19c2b92946512619c..f3e046a6a987a685910bafc171c2cc9cf243df1b 100644 (file)
@@ -7,7 +7,7 @@
     VIA UniChrome Family(CLE266, PM800 / CN400 / CN300,
                         P4M800CE / P4M800Pro / CN700 / VN800,
                         CX700 / VX700, K8M890, P4M890,
-                        CN896 / P4M900, VX800)
+                        CN896 / P4M900, VX800, VX855)
 
 [Driver features]
 ------------------------
         0 : No Dual Edge Panel (default)
         1 : Dual Edge Panel
 
-    viafb_video_dev:
-        This option is used to specify video output devices(CRT, DVI, LCD) for
-        duoview case.
-        For example:
-        To output video on DVI, we should use:
-            modprobe viafb viafb_video_dev=DVI...
-
     viafb_lcd_port:
         This option is used to specify LCD output port,
         available values are "DVP0" "DVP1" "DFP_HIGHLOW" "DFP_HIGH" "DFP_LOW".
@@ -181,9 +174,6 @@ Notes:
        and bpp, need to call VIAFB specified ioctl interface VIAFB_SET_DEVICE
        instead of calling common ioctl function FBIOPUT_VSCREENINFO since
        viafb doesn't support multi-head well, or it will cause screen crush.
-    4. VX800 2D accelerator hasn't been supported in this driver yet. When
-       using driver on VX800, the driver will disable the acceleration
-       function as default.
 
 
 [Configure viafb with "fbset" tool]
index 0d15ebccf5b037a6590ee8ab9c616172d28cdf82..a1e2e0dda9074d1d8a3102df3488a8a5f29cfb17 100644 (file)
@@ -248,9 +248,7 @@ code, that is done in the initialization code in the usual way:
        {
                struct proc_dir_entry *entry;
 
-               entry = create_proc_entry("sequence", 0, NULL);
-               if (entry)
-                       entry->proc_fops = &ct_file_ops;
+               proc_create("sequence", 0, NULL, &ct_file_ops);
                return 0;
        }
 
index e4e7daed2ba88dc2dbf7d0bf9c9eb16037e3e6c7..1866c27eec693e7e88f7420e3ac895079cba02d9 100644 (file)
@@ -531,6 +531,13 @@ and have the following read/write attributes:
                This file exists only if the pin can be configured as an
                interrupt generating input pin.
 
+       "active_low" ... reads as either 0 (false) or 1 (true).  Write
+               any nonzero value to invert the value attribute both
+               for reading and writing.  Existing and subsequent
+               poll(2) support configuration via the edge attribute
+               for "rising" and "falling" edges will follow this
+               setting.
+
 GPIO controllers have paths like /sys/class/gpio/gpiochip42/ (for the
 controller implementing GPIOs starting at #42) and have the following
 read-only attributes:
@@ -566,6 +573,8 @@ requested using gpio_request():
        int gpio_export_link(struct device *dev, const char *name,
                unsigned gpio)
 
+       /* change the polarity of a GPIO node in sysfs */
+       int gpio_sysfs_set_active_low(unsigned gpio, int value);
 
 After a kernel driver requests a GPIO, it may only be made available in
 the sysfs interface by gpio_export().  The driver can control whether the
@@ -580,3 +589,9 @@ After the GPIO has been exported, gpio_export_link() allows creating
 symlinks from elsewhere in sysfs to the GPIO sysfs node.  Drivers can
 use this to provide the interface under their own device in sysfs with
 a descriptive name.
+
+Drivers can use gpio_sysfs_set_active_low() to hide GPIO line polarity
+differences between boards from user space.  This only affects the
+sysfs interface.  Polarity change can be done both before and after
+gpio_export(), and previously enabled poll(2) support for either
+rising or falling edge will be reconfigured to follow this setting.
index ab95d3ada5c7f7210d2a13adc619ec3d4b9548bd..c309515ae95990117bf5c81f381d6390a7b97259 100644 (file)
@@ -2729,6 +2729,11 @@ and is between 256 and 4096 characters. It is defined in the file
        vmpoff=         [KNL,S390] Perform z/VM CP command after power off.
                        Format: <command>
 
+       vt.cur_default= [VT] Default cursor shape.
+                       Format: 0xCCBBAA, where AA, BB, and CC are the same as
+                       the parameters of the <Esc>[?A;B;Cc escape sequence;
+                       see VGA-softcursor.txt. Default: 2 = underline.
+
        vt.default_blu= [VT]
                        Format: <blue0>,<blue1>,<blue2>,...,<blue15>
                        Change the default blue palette of the console.
index 5c75c1b2352a9cacf7c47de5c04d57b1bab7211b..9baae8afe8a372d20e88537691fc555d8dd6bb6d 100644 (file)
@@ -81,7 +81,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 #define ELF_DATA       ELFDATA2LSB
 #define ELF_ARCH       EM_ALPHA
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      8192
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
index 6aac3f5bb2f3ee1975f53578d2742a5e5d1295b9..a399bb5730f15210aa2b6b42527ea6ada7d19f15 100644 (file)
@@ -101,7 +101,6 @@ extern int arm_elf_read_implies_exec(const struct elf32_hdr *, int);
 int dump_task_regs(struct task_struct *t, elf_gregset_t *elfregs);
 #define ELF_CORE_COPY_TASK_REGS dump_task_regs
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
index 62b98bffc158c452e5a063e014f78e5b7c497cf7..07de8db145812c68a6cf386ef68ff10c2251f9b7 100644 (file)
@@ -339,6 +339,15 @@ static struct davinci_mmc_config da850_mmc_config = {
        .version        = MMC_CTLR_VERSION_2,
 };
 
+static void da850_panel_power_ctrl(int val)
+{
+       /* lcd backlight */
+       gpio_set_value(DA850_LCD_BL_PIN, val);
+
+       /* lcd power */
+       gpio_set_value(DA850_LCD_PWR_PIN, val);
+}
+
 static int da850_lcd_hw_init(void)
 {
        int status;
@@ -356,17 +365,11 @@ static int da850_lcd_hw_init(void)
        gpio_direction_output(DA850_LCD_BL_PIN, 0);
        gpio_direction_output(DA850_LCD_PWR_PIN, 0);
 
-       /* disable lcd backlight */
-       gpio_set_value(DA850_LCD_BL_PIN, 0);
-
-       /* disable lcd power */
-       gpio_set_value(DA850_LCD_PWR_PIN, 0);
-
-       /* enable lcd power */
-       gpio_set_value(DA850_LCD_PWR_PIN, 1);
+       /* Switch off panel power and backlight */
+       da850_panel_power_ctrl(0);
 
-       /* enable lcd backlight */
-       gpio_set_value(DA850_LCD_BL_PIN, 1);
+       /* Switch on panel power and backlight */
+       da850_panel_power_ctrl(1);
 
        return 0;
 }
@@ -674,6 +677,7 @@ static __init void da850_evm_init(void)
                pr_warning("da850_evm_init: lcd initialization failed: %d\n",
                                ret);
 
+       sharp_lk043t1dg01_pdata.panel_power_ctrl = da850_panel_power_ctrl,
        ret = da8xx_register_lcdc(&sharp_lk043t1dg01_pdata);
        if (ret)
                pr_warning("da850_evm_init: lcdc registration failed: %d\n",
index d5d1d41c600a81e6eea29bd07967fa2412ffce14..3b3159b710d42de528b487bc9758cf04dfb9a7fa 100644 (file)
@@ -77,7 +77,6 @@ typedef struct user_fpu_struct elf_fpregset_t;
 #endif
 #define ELF_ARCH       EM_AVR32
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
diff --git a/arch/blackfin/include/asm/bfin-lq035q1.h b/arch/blackfin/include/asm/bfin-lq035q1.h
new file mode 100644 (file)
index 0000000..57bc21a
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02
+ *
+ * Copyright 2008-2009 Analog Devices Inc.
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef BFIN_LQ035Q1_H
+#define BFIN_LQ035Q1_H
+
+#define LQ035_RL       (0 << 8)        /* Right -> Left Scan */
+#define LQ035_LR       (1 << 8)        /* Left -> Right Scan */
+#define LQ035_TB       (1 << 9)        /* Top -> Botton Scan */
+#define LQ035_BT       (0 << 9)        /* Botton -> Top Scan */
+#define LQ035_BGR      (1 << 11)       /* Use BGR format */
+#define LQ035_RGB      (0 << 11)       /* Use RGB format */
+#define LQ035_NORM     (1 << 13)       /* Reversal */
+#define LQ035_REV      (0 << 13)       /* Reversal */
+
+struct bfin_lq035q1fb_disp_info {
+
+       unsigned        mode;
+       /* GPIOs */
+       int             use_bl;
+       unsigned        gpio_bl;
+};
+
+#endif /* BFIN_LQ035Q1_H */
index 8e0764c81eaf18df6d2e0ee0167596b2fdea5e25..5b50f0ecacf8ebd77c0e4646c397fb2356034d80 100644 (file)
@@ -55,7 +55,6 @@ do {                                                                                  \
        _regs->p2       = _dynamic_addr;                                \
 } while(0)
 
-#define USE_ELF_CORE_DUMP
 #define ELF_FDPIC_CORE_EFLAGS  EF_BFIN_FDPIC
 #define ELF_EXEC_PAGESIZE      4096
 
index 0f51b10b9f4f39b397f5615377e229268a13df9e..8a3d8e2b33c1e41c384255ecb764cee17af4a3c4 100644 (file)
@@ -64,8 +64,6 @@ typedef unsigned long elf_fpregset_t;
 #define EF_CRIS_VARIANT_COMMON_V10_V32 0x00000004
 /* End of excerpt from {binutils}/include/elf/cris.h.  */
 
-#define USE_ELF_CORE_DUMP
-
 #define ELF_EXEC_PAGESIZE      8192
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
index 7bbf6e47f8c8a5cb216c9b8f5e0b8be3b902c5bb..c3819804a74b104765c60a16051ffeea4063cbb1 100644 (file)
@@ -115,7 +115,6 @@ do {                                                                                        \
        __kernel_frame0_ptr->gr29       = 0;                                            \
 } while(0)
 
-#define USE_ELF_CORE_DUMP
 #define CORE_DUMP_USE_REGSET
 #define ELF_FDPIC_CORE_EFLAGS  EF_FRV_FDPIC
 #define ELF_EXEC_PAGESIZE      16384
index 94e2284c88168fba8a42afc0008aa8cb1c53944e..c24fa250d6533cdb3a5429c102323ca19d356e0d 100644 (file)
@@ -34,7 +34,6 @@ typedef unsigned long elf_fpregset_t;
 
 #define ELF_PLAT_INIT(_r)      _r->er1 = 0
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
index 9a3abf58cea34580edc399f25d6d2750198214f7..6577257426176a4163db634bb7d4b4643a6203db 100644 (file)
@@ -11,8 +11,6 @@
 #include <asm/intrinsics.h>
 #include <asm/uaccess.h>
 
-#define USE_ELF_CORE_DUMP 1
-
 /* Override elfcore.h */
 #define _LINUX_ELFCORE_H 1
 typedef unsigned int elf_greg_t;
index 8d3c79cd81e7982f1ad5c3b9875bf302bd3731ab..7d09a09cdaadf5b1f26b8bf5009b71b986d61406 100644 (file)
@@ -73,7 +73,7 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
        if (!dev->dma_mask)
                return 0;
 
-       return addr + size <= *dev->dma_mask;
+       return addr + size - 1 <= *dev->dma_mask;
 }
 
 static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
index 86eddee029cb5238c00d4de2ef1c432f37e97e6d..e14108b19c091a654eb2a28cbf45ff104efa5ace 100644 (file)
@@ -25,7 +25,6 @@
 #define ELF_DATA       ELFDATA2LSB
 #define ELF_ARCH       EM_IA_64
 
-#define USE_ELF_CORE_DUMP
 #define CORE_DUMP_USE_REGSET
 
 /* Least-significant four bits of ELF header's e_flags are OS-specific.  The bits are
index 35b2a27d2e77055dd11b951fdd2b5dba149becfc..efb454534e525c2e9bbb76d4447dc2a97224332c 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
+#include <linux/bitmap.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/addrs.h>
 #include <asm/sn/io.h>
@@ -369,7 +370,7 @@ tioca_dma_d48(struct pci_dev *pdev, u64 paddr)
 static dma_addr_t
 tioca_dma_mapped(struct pci_dev *pdev, unsigned long paddr, size_t req_size)
 {
-       int i, ps, ps_shift, entry, entries, mapsize, last_entry;
+       int ps, ps_shift, entry, entries, mapsize;
        u64 xio_addr, end_xio_addr;
        struct tioca_common *tioca_common;
        struct tioca_kernel *tioca_kern;
@@ -410,23 +411,13 @@ tioca_dma_mapped(struct pci_dev *pdev, unsigned long paddr, size_t req_size)
        map = tioca_kern->ca_pcigart_pagemap;
        mapsize = tioca_kern->ca_pcigart_entries;
 
-       entry = find_first_zero_bit(map, mapsize);
-       while (entry < mapsize) {
-               last_entry = find_next_bit(map, mapsize, entry);
-
-               if (last_entry - entry >= entries)
-                       break;
-
-               entry = find_next_zero_bit(map, mapsize, last_entry);
-       }
-
-       if (entry > mapsize) {
+       entry = bitmap_find_next_zero_area(map, mapsize, 0, entries, 0);
+       if (entry >= mapsize) {
                kfree(ca_dmamap);
                goto map_return;
        }
 
-       for (i = 0; i < entries; i++)
-               set_bit(entry + i, map);
+       bitmap_set(map, entry, entries);
 
        bus_addr = tioca_kern->ca_pciap_base + (entry * ps);
 
index 0cc34c94bf2bf26a087a73a11ea32302d48eebf6..2f85412ef7302a0aedaf1b5e26f63719c69dc033 100644 (file)
@@ -102,7 +102,6 @@ typedef elf_fpreg_t elf_fpregset_t;
  */
 #define ELF_PLAT_INIT(_r, load_addr)   (_r)->r0 = 0
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
 /*
index 0b0f49eb876b11db0ce7eb6cd1703be2657fbd54..01c193d9141268c5f65ea1720ba1ecdd1db9d726 100644 (file)
@@ -59,7 +59,6 @@ typedef struct user_m68kfp_struct elf_fpregset_t;
    is actually used on ASV.  */
 #define ELF_PLAT_INIT(_r, load_addr)   _r->a1 = 0
 
-#define USE_ELF_CORE_DUMP
 #ifndef CONFIG_SUN3
 #define ELF_EXEC_PAGESIZE      4096
 #else
index f92fc0dda006d40b886d36b947bb3891cb83656a..7d4acf2b278e2061c9d73d9ef4b86faf09620e8a 100644 (file)
@@ -77,7 +77,6 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 #define ELF_DATA       ELFDATA2MSB
 #endif
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
 
index 7990694cda221dbd9f0da1c2b11b4f8e77688680..7a6a35dbe529c91ad71529e5d77218811be556cf 100644 (file)
@@ -326,7 +326,6 @@ extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *);
 #define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs)                  \
        dump_task_fpu(tsk, elf_fpregs)
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
 /* This yields a mask that user programs can use to figure out what
index 75a70aa9fd6f0da2ca9b7630f588c9bff91b1f38..e5fa97cd9a147222c567b39f1e8bd01cec18ff4a 100644 (file)
@@ -77,7 +77,6 @@ do {                                                                  \
        _ur->a1   = 0;  _ur->a0   = 0;  _ur->d1   = 0;  _ur->d0   = 0;  \
 } while (0)
 
-#define USE_ELF_CORE_DUMP
 #define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE      4096
 
index 9c802eb4be8491e95f932c9efb487f4b751ac5d4..19f6cb1a4a1c1aa06dd5abcaa4fd7c129863d5b1 100644 (file)
@@ -328,7 +328,6 @@ struct pt_regs;     /* forward declaration... */
    such function.  */
 #define ELF_PLAT_INIT(_r, load_addr)       _r->gr[23] = 0
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
index e281daebddca317e10c1263c3d7cccf93dcb5538..80a973bb9e71397a7f65497d034d9eb7f7958a62 100644 (file)
@@ -197,7 +197,7 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
        if (!dev->dma_mask)
                return 0;
 
-       return addr + size <= *dev->dma_mask;
+       return addr + size - 1 <= *dev->dma_mask;
 }
 
 static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
index 014a624f4c8efb054bd46da4e5711713b3e76b68..17828ad411ebbecdb920a1cbdd8ee44886b669af 100644 (file)
@@ -170,7 +170,6 @@ typedef elf_fpreg_t elf_vsrreghalf_t32[ELF_NVSRHALFREG];
 #define elf_check_arch(x) ((x)->e_machine == ELF_ARCH)
 #define compat_elf_check_arch(x)       ((x)->e_machine == EM_PPC)
 
-#define USE_ELF_CORE_DUMP
 #define CORE_DUMP_USE_REGSET
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
index 8c341490cfc5a9843719bb50a4590d3df24b024c..cbd759e3cd7879d106eec0dea779e40f1790f97b 100644 (file)
@@ -140,6 +140,8 @@ extern void user_enable_single_step(struct task_struct *);
 extern void user_enable_block_step(struct task_struct *);
 extern void user_disable_single_step(struct task_struct *);
 
+#define ARCH_HAS_USER_SINGLE_STEP_INFO
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index fd51578e29dda66b276061830e32da1f28dd37e1..5547ae6e6b0be605e293ae42c49dab911782f568 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/dma-mapping.h>
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
 #include <linux/iommu-helper.h>
 #include <linux/crash_dump.h>
 #include <asm/io.h>
@@ -251,7 +251,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
        }
 
        ppc_md.tce_free(tbl, entry, npages);
-       iommu_area_free(tbl->it_map, free_entry, npages);
+       bitmap_clear(tbl->it_map, free_entry, npages);
 }
 
 static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
index 804f0f30f227f692d949d49117b3c35da908fc6f..d069ff8a7e036c0022fe1e9f3a62112713033af6 100644 (file)
@@ -174,6 +174,15 @@ int die(const char *str, struct pt_regs *regs, long err)
        return 0;
 }
 
+void user_single_step_siginfo(struct task_struct *tsk,
+                               struct pt_regs *regs, siginfo_t *info)
+{
+       memset(info, 0, sizeof(*info));
+       info->si_signo = SIGTRAP;
+       info->si_code = TRAP_TRACE;
+       info->si_addr = (void __user *)regs->nip;
+}
+
 void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
 {
        siginfo_t info;
index e885442c1dfe99622217a06444ed680c18b23303..354d42616c7e6dc057a4bbf1bbfbb80805f7d880 100644 (file)
@@ -155,7 +155,6 @@ extern unsigned int vdso_enabled;
        } while (0)
 
 #define CORE_DUMP_USE_REGSET
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
index 43526d9fda936b07bd22c031b50dc30189cb598b..f478ce94181fb349324bf836e9fe5a01abfaa13d 100644 (file)
@@ -61,7 +61,6 @@ struct task_struct;
 struct pt_regs;
 
 #define CORE_DUMP_USE_REGSET
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
 /* This yields a mask that user programs can use to figure out what
index ccb1d93bb04361678b967fd80151c43427263b27..ac04255022b69548e6f71f07f0502e97664c881f 100644 (file)
@@ -114,7 +114,6 @@ typedef struct user_fpu_struct elf_fpregset_t;
  */
 #define CORE_DUMP_USE_REGSET
 
-#define USE_ELF_CORE_DUMP
 #define ELF_FDPIC_CORE_EFLAGS  EF_SH_FDPIC
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
index 381a1b5256d6c9f23e0cb683b90ba8307265a409..4269ca6ad18a9f2b46cb0064dcc9618e9d72dcb3 100644 (file)
@@ -104,8 +104,6 @@ typedef struct {
 #define ELF_CLASS      ELFCLASS32
 #define ELF_DATA       ELFDATA2MSB
 
-#define USE_ELF_CORE_DUMP
-
 #define ELF_EXEC_PAGESIZE      4096
 
 
index d42e393078c49c4cdda59392fdbd56dc1d6f6c6e..ff66bb88537b37539812173a7825d1da39a82810 100644 (file)
@@ -152,7 +152,6 @@ typedef struct {
                                         (x)->e_machine == EM_SPARC32PLUS)
 #define compat_start_thread            start_thread32
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
index 7690cc219ecc87b5399f327a826dc5f3ffcca8a5..5fad94950e7680b49a453686420bc9a85e316d78 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/errno.h>
 #include <linux/iommu-helper.h>
+#include <linux/bitmap.h>
 
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
@@ -169,7 +170,7 @@ void iommu_range_free(struct iommu *iommu, dma_addr_t dma_addr, unsigned long np
 
        entry = (dma_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT;
 
-       iommu_area_free(arena->map, entry, npages);
+       bitmap_clear(arena->map, entry, npages);
 }
 
 int iommu_table_init(struct iommu *iommu, int tsbsize,
index e0ba898e30cffa2438ee8cb569edf796ca96dfbc..df39a0f0d27af2c250a3c7da9a2b50208d240e5f 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/init.h>
+#include <linux/bitmap.h>
 
 #include <asm/hypervisor.h>
 #include <asm/iommu.h>
@@ -1875,7 +1876,7 @@ EXPORT_SYMBOL(ldc_read);
 static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages)
 {
        struct iommu_arena *arena = &iommu->arena;
-       unsigned long n, i, start, end, limit;
+       unsigned long n, start, end, limit;
        int pass;
 
        limit = arena->limit;
@@ -1883,7 +1884,7 @@ static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages)
        pass = 0;
 
 again:
-       n = find_next_zero_bit(arena->map, limit, start);
+       n = bitmap_find_next_zero_area(arena->map, limit, start, npages, 0);
        end = n + npages;
        if (unlikely(end >= limit)) {
                if (likely(pass < 1)) {
@@ -1896,16 +1897,7 @@ again:
                        return -1;
                }
        }
-
-       for (i = n; i < end; i++) {
-               if (test_bit(i, arena->map)) {
-                       start = i + 1;
-                       goto again;
-               }
-       }
-
-       for (i = n; i < end; i++)
-               __set_bit(i, arena->map);
+       bitmap_set(arena->map, n, npages);
 
        arena->hint = end;
 
index 2ffacd67c42403393013bd73cd191eddbdc3b22f..a89baf0d875af3ef7a557675b87a90398ee6fbd3 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/fs.h>
 #include <linux/seq_file.h>
 #include <linux/scatterlist.h>
+#include <linux/bitmap.h>
 
 #include <asm/sections.h>
 #include <asm/page.h>
@@ -1021,20 +1022,12 @@ static char *sun4c_lockarea(char *vaddr, unsigned long size)
        npages = (((unsigned long)vaddr & ~PAGE_MASK) +
                  size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
 
-       scan = 0;
        local_irq_save(flags);
-       for (;;) {
-               scan = find_next_zero_bit(sun4c_iobuffer_map,
-                                         iobuffer_map_size, scan);
-               if ((base = scan) + npages > iobuffer_map_size) goto abend;
-               for (;;) {
-                       if (scan >= base + npages) goto found;
-                       if (test_bit(scan, sun4c_iobuffer_map)) break;
-                       scan++;
-               }
-       }
+       base = bitmap_find_next_zero_area(sun4c_iobuffer_map, iobuffer_map_size,
+                                               0, npages, 0);
+       if (base >= iobuffer_map_size)
+               goto abend;
 
-found:
        high = ((base + npages) << PAGE_SHIFT) + sun4c_iobuffer_start;
        high = SUN4C_REAL_PGDIR_ALIGN(high);
        while (high > sun4c_iobuffer_high) {
index d0da9d7c53716fc294fd1d1c26759d03da784469..770885472ed4c850b59d5fea34ad1c0c5db1439f 100644 (file)
@@ -48,7 +48,6 @@ typedef struct user_i387_struct elf_fpregset_t;
        PT_REGS_EAX(regs) = 0; \
 } while (0)
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE 4096
 
 #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
index af9463cd8ce51f936af61c14d8ce217bf3eb5eec..8aacaf56508d408e425054e5991aeab78d8d9f9b 100644 (file)
@@ -17,8 +17,6 @@ extern long elf_aux_hwcap;
 #define ELF_CLASS ELFCLASS32
 #endif
 
-#define USE_ELF_CORE_DUMP
-
 #define R_386_NONE     0
 #define R_386_32       1
 #define R_386_PC32     2
index 04b9e87c8dadd38f5f0ebc60ae72b190e63c7920..49655c83efd2241b4d80b044b283207a3a3493ec 100644 (file)
@@ -104,7 +104,6 @@ extern int elf_core_copy_fpregs(struct task_struct *t, elf_fpregset_t *fpu);
         clear_thread_flag(TIF_IA32);
 #endif
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE 4096
 
 #define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
index 0f6c02f3b7d4f26126a590e3df2408c2af6c5d8c..ac91eed21061a5299bc39669f6e333d2b61ef4b3 100644 (file)
@@ -67,7 +67,7 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size)
        if (!dev->dma_mask)
                return 0;
 
-       return addr + size <= *dev->dma_mask;
+       return addr + size - 1 <= *dev->dma_mask;
 }
 
 static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr)
index 8a024babe5e646a3b1f8282deeae9edcf70088ba..b4501ee223ad66e4e589d1340aee77b483e8da7c 100644 (file)
@@ -239,7 +239,6 @@ extern int force_personality32;
 #endif /* !CONFIG_X86_32 */
 
 #define CORE_DUMP_USE_REGSET
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      4096
 
 /* This is the location that an ET_DYN program is loaded if exec'ed.  Typical
index 3d11fd0f44c5f4f86c060207417710db58758094..9d369f6803216cd365358d1660c6aab999287d51 100644 (file)
@@ -292,6 +292,8 @@ extern void user_enable_block_step(struct task_struct *);
 #define arch_has_block_step()  (boot_cpu_data.x86 >= 6)
 #endif
 
+#define ARCH_HAS_USER_SINGLE_STEP_INFO
+
 struct user_desc;
 extern int do_get_thread_area(struct task_struct *p, int idx,
                              struct user_desc __user *info);
index 7ed17ff502b9edd76afb96fe682609a4df1afffe..2751f3075d8bc746ad548cefe5543960956cc3bd 100644 (file)
@@ -76,15 +76,6 @@ union partition_info_u {
        };
 };
 
-union uv_watchlist_u {
-       u64     val;
-       struct {
-               u64     blade   : 16,
-                       size    : 32,
-                       filler  : 16;
-       };
-};
-
 enum uv_memprotect {
        UV_MEMPROT_RESTRICT_ACCESS,
        UV_MEMPROT_ALLOW_AMO,
@@ -100,7 +91,7 @@ extern s64 uv_bios_call_reentrant(enum uv_bios_cmd, u64, u64, u64, u64, u64);
 
 extern s64 uv_bios_get_sn_info(int, int *, long *, long *, long *);
 extern s64 uv_bios_freq_base(u64, u64 *);
-extern int uv_bios_mq_watchlist_alloc(int, unsigned long, unsigned int,
+extern int uv_bios_mq_watchlist_alloc(unsigned long, unsigned int,
                                        unsigned long *);
 extern int uv_bios_mq_watchlist_free(int, int);
 extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect);
index d1414af9855961ff52a1a952908995eacfb57b69..811bfabc80b7e91ce3c02bf56acdbb4809f4e1a3 100644 (file)
@@ -172,6 +172,8 @@ DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 #define UV_LOCAL_MMR_SIZE              (64UL * 1024 * 1024)
 #define UV_GLOBAL_MMR32_SIZE           (64UL * 1024 * 1024)
 
+#define UV_GLOBAL_GRU_MMR_BASE         0x4000000
+
 #define UV_GLOBAL_MMR32_PNODE_SHIFT    15
 #define UV_GLOBAL_MMR64_PNODE_SHIFT    26
 
@@ -232,6 +234,26 @@ static inline unsigned long uv_gpa(void *v)
        return uv_soc_phys_ram_to_gpa(__pa(v));
 }
 
+/* Top two bits indicate the requested address is in MMR space.  */
+static inline int
+uv_gpa_in_mmr_space(unsigned long gpa)
+{
+       return (gpa >> 62) == 0x3UL;
+}
+
+/* UV global physical address --> socket phys RAM */
+static inline unsigned long uv_gpa_to_soc_phys_ram(unsigned long gpa)
+{
+       unsigned long paddr = gpa & uv_hub_info->gpa_mask;
+       unsigned long remap_base = uv_hub_info->lowmem_remap_base;
+       unsigned long remap_top =  uv_hub_info->lowmem_remap_top;
+
+       if (paddr >= remap_base && paddr < remap_base + remap_top)
+               paddr -= remap_base;
+       return paddr;
+}
+
+
 /* gnode -> pnode */
 static inline unsigned long uv_gpa_to_gnode(unsigned long gpa)
 {
@@ -307,6 +329,15 @@ static inline unsigned long uv_read_global_mmr64(int pnode,
        return readq(uv_global_mmr64_address(pnode, offset));
 }
 
+/*
+ * Global MMR space addresses when referenced by the GRU. (GRU does
+ * NOT use socket addressing).
+ */
+static inline unsigned long uv_global_gru_mmr_address(int pnode, unsigned long offset)
+{
+       return UV_GLOBAL_GRU_MMR_BASE | offset | (pnode << uv_hub_info->m_val);
+}
+
 /*
  * Access hub local MMRs. Faster than using global space but only local MMRs
  * are accessible.
@@ -434,6 +465,14 @@ static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
        }
 }
 
+static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode)
+{
+       return (1UL << UVH_IPI_INT_SEND_SHFT) |
+                       ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
+                       (mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) |
+                       (vector << UVH_IPI_INT_VECTOR_SHFT);
+}
+
 static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
 {
        unsigned long val;
@@ -442,10 +481,7 @@ static inline void uv_hub_send_ipi(int pnode, int apicid, int vector)
        if (vector == NMI_VECTOR)
                dmode = dest_NMI;
 
-       val = (1UL << UVH_IPI_INT_SEND_SHFT) |
-                       ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) |
-                       (dmode << UVH_IPI_INT_DELIVERY_MODE_SHFT) |
-                       (vector << UVH_IPI_INT_VECTOR_SHFT);
+       val = uv_hub_ipi_value(apicid, vector, dmode);
        uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
 }
 
index b990b5cc95418df45f1c94f1b748cb5d59d45e1c..23824fef789cb458d909b12ffd7e9e9ffe1bc53e 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <linux/pci.h>
 #include <linux/gfp.h>
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
 #include <linux/debugfs.h>
 #include <linux/scatterlist.h>
 #include <linux/dma-mapping.h>
@@ -1162,7 +1162,7 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
 
        address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT;
 
-       iommu_area_free(range->bitmap, address, pages);
+       bitmap_clear(range->bitmap, address, pages);
 
 }
 
index 63a88e1f987d35b9ff94ccbd2d53d499b5c783ee..b0206a211b09db5bb050fdd56775add9bbb80e43 100644 (file)
@@ -101,21 +101,17 @@ s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher,
 }
 
 int
-uv_bios_mq_watchlist_alloc(int blade, unsigned long addr, unsigned int mq_size,
+uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size,
                           unsigned long *intr_mmr_offset)
 {
-       union uv_watchlist_u size_blade;
        u64 watchlist;
        s64 ret;
 
-       size_blade.size = mq_size;
-       size_blade.blade = blade;
-
        /*
         * bios returns watchlist number or negative error number.
         */
        ret = (int)uv_bios_call_irqsave(UV_BIOS_WATCHLIST_ALLOC, addr,
-                       size_blade.val, (u64)intr_mmr_offset,
+                       mq_size, (u64)intr_mmr_offset,
                        (u64)&watchlist, 0);
        if (ret < BIOS_STATUS_SUCCESS)
                return ret;
index c563e4c8ff395efe92522c80212a237968897b4a..2bbde607814334a811b91b21448c4d3ac75cfe00 100644 (file)
@@ -31,7 +31,7 @@
 #include <linux/string.h>
 #include <linux/crash_dump.h>
 #include <linux/dma-mapping.h>
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
 #include <linux/pci_ids.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
@@ -212,7 +212,7 @@ static void iommu_range_reserve(struct iommu_table *tbl,
 
        spin_lock_irqsave(&tbl->it_lock, flags);
 
-       iommu_area_reserve(tbl->it_map, index, npages);
+       bitmap_set(tbl->it_map, index, npages);
 
        spin_unlock_irqrestore(&tbl->it_lock, flags);
 }
@@ -303,7 +303,7 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
 
        spin_lock_irqsave(&tbl->it_lock, flags);
 
-       iommu_area_free(tbl->it_map, entry, npages);
+       bitmap_clear(tbl->it_map, entry, npages);
 
        spin_unlock_irqrestore(&tbl->it_lock, flags);
 }
index 56c0e730d3fe7bd09913d092c01f009f94f53974..34de53b46f8759ad90ec23575cca26828b07093a 100644 (file)
@@ -23,7 +23,7 @@
 #include <linux/module.h>
 #include <linux/topology.h>
 #include <linux/interrupt.h>
-#include <linux/bitops.h>
+#include <linux/bitmap.h>
 #include <linux/kdebug.h>
 #include <linux/scatterlist.h>
 #include <linux/iommu-helper.h>
@@ -126,7 +126,7 @@ static void free_iommu(unsigned long offset, int size)
        unsigned long flags;
 
        spin_lock_irqsave(&iommu_bitmap_lock, flags);
-       iommu_area_free(iommu_gart_bitmap, offset, size);
+       bitmap_clear(iommu_gart_bitmap, offset, size);
        if (offset >= next_bit)
                next_bit = offset + size;
        spin_unlock_irqrestore(&iommu_bitmap_lock, flags);
@@ -792,7 +792,7 @@ int __init gart_iommu_init(void)
         * Out of IOMMU space handling.
         * Reserve some invalid pages at the beginning of the GART.
         */
-       iommu_area_reserve(iommu_gart_bitmap, 0, EMERGENCY_PAGES);
+       bitmap_set(iommu_gart_bitmap, 0, EMERGENCY_PAGES);
 
        pr_info("PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n",
               iommu_size >> 20);
index 7079ddaf0731e949d99940f7a036d82f3b613954..2779321046bd53e789847b10c18c99893e054e31 100644 (file)
@@ -1676,21 +1676,33 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task)
 #endif
 }
 
-void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
-                                        int error_code, int si_code)
+static void fill_sigtrap_info(struct task_struct *tsk,
+                               struct pt_regs *regs,
+                               int error_code, int si_code,
+                               struct siginfo *info)
 {
-       struct siginfo info;
-
        tsk->thread.trap_no = 1;
        tsk->thread.error_code = error_code;
 
-       memset(&info, 0, sizeof(info));
-       info.si_signo = SIGTRAP;
-       info.si_code = si_code;
+       memset(info, 0, sizeof(*info));
+       info->si_signo = SIGTRAP;
+       info->si_code = si_code;
+       info->si_addr = user_mode_vm(regs) ? (void __user *)regs->ip : NULL;
+}
 
-       /* User-mode ip? */
-       info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL;
+void user_single_step_siginfo(struct task_struct *tsk,
+                               struct pt_regs *regs,
+                               struct siginfo *info)
+{
+       fill_sigtrap_info(tsk, regs, 0, TRAP_BRKPT, info);
+}
 
+void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
+                                        int error_code, int si_code)
+{
+       struct siginfo info;
+
+       fill_sigtrap_info(tsk, regs, error_code, si_code, &info);
        /* Send us the fake SIGTRAP */
        force_sig_info(SIGTRAP, &info, tsk);
 }
@@ -1755,29 +1767,22 @@ asmregparm long syscall_trace_enter(struct pt_regs *regs)
 
 asmregparm void syscall_trace_leave(struct pt_regs *regs)
 {
+       bool step;
+
        if (unlikely(current->audit_context))
                audit_syscall_exit(AUDITSC_RESULT(regs->ax), regs->ax);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
                trace_sys_exit(regs, regs->ax);
 
-       if (test_thread_flag(TIF_SYSCALL_TRACE))
-               tracehook_report_syscall_exit(regs, 0);
-
        /*
         * If TIF_SYSCALL_EMU is set, we only get here because of
         * TIF_SINGLESTEP (i.e. this is PTRACE_SYSEMU_SINGLESTEP).
         * We already reported this syscall instruction in
-        * syscall_trace_enter(), so don't do any more now.
-        */
-       if (unlikely(test_thread_flag(TIF_SYSCALL_EMU)))
-               return;
-
-       /*
-        * If we are single-stepping, synthesize a trap to follow the
-        * system call instruction.
+        * syscall_trace_enter().
         */
-       if (test_thread_flag(TIF_SINGLESTEP) &&
-           tracehook_consider_fatal_signal(current, SIGTRAP))
-               send_sigtrap(current, regs, 0, TRAP_BRKPT);
+       step = unlikely(test_thread_flag(TIF_SINGLESTEP)) &&
+                       !test_thread_flag(TIF_SYSCALL_EMU);
+       if (step || test_thread_flag(TIF_SYSCALL_TRACE))
+               tracehook_report_syscall_exit(regs, step);
 }
index c3f53e755ca5c16fabff550b1c7859c6521c9e17..5eb6d695e9872563ab9cd14a2cf67b2a9ad142bc 100644 (file)
@@ -123,7 +123,6 @@ extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *);
 #define ELF_CLASS      ELFCLASS32
 #define ELF_ARCH       EM_XTENSA
 
-#define USE_ELF_CORE_DUMP
 #define ELF_EXEC_PAGESIZE      PAGE_SIZE
 
 /*
index 26a47dc88f6194ed7c0402f01fe31477a27e2af2..53c524e7b82928a78ff04e26be135ca4c1a4e428 100644 (file)
@@ -285,6 +285,7 @@ static const struct file_operations efi_rtc_fops = {
        .unlocked_ioctl = efi_rtc_ioctl,
        .open           = efi_rtc_open,
        .release        = efi_rtc_close,
+       .llseek         = no_llseek,
 };
 
 static struct miscdevice efi_rtc_dev= {
index 80704875794c38795505f945262448bb6f43cb25..cf82fedae09975272fd6517b1fa5346eff95a814 100644 (file)
@@ -370,7 +370,7 @@ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time)
                        return SI_SM_IDLE;
 
        case KCS_START_OP:
-               if (state != KCS_IDLE) {
+               if (state != KCS_IDLE_STATE) {
                        start_error_recovery(kcs,
                                             "State machine not idle at start");
                        break;
index 44203ff599daa10420407265db91f88116473413..1ae2de7d8b4f333bed6a3bc5e2e63460cb4e1336 100644 (file)
@@ -339,7 +339,7 @@ static struct sysrq_key_op sysrq_term_op = {
 
 static void moom_callback(struct work_struct *ignored)
 {
-       out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0);
+       out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0, NULL);
 }
 
 static DECLARE_WORK(moom_work, moom_callback);
index e43fbc66aef0094557defaa474929675b97034a2..50faa1fb0f06f57f419e96f5e9c974d6a7d08b70 100644 (file)
@@ -164,6 +164,9 @@ module_param(default_utf8, int, S_IRUGO | S_IWUSR);
 int global_cursor_default = -1;
 module_param(global_cursor_default, int, S_IRUGO | S_IWUSR);
 
+static int cur_default = CUR_DEFAULT;
+module_param(cur_default, int, S_IRUGO | S_IWUSR);
+
 /*
  * ignore_poke: don't unblank the screen when things are typed.  This is
  * mainly for the privacy of braille terminal users.
@@ -1636,7 +1639,7 @@ static void reset_terminal(struct vc_data *vc, int do_clear)
        /* do not do set_leds here because this causes an endless tasklet loop
           when the keyboard hasn't been initialized yet */
 
-       vc->vc_cursor_type = CUR_DEFAULT;
+       vc->vc_cursor_type = cur_default;
        vc->vc_complement_mask = vc->vc_s_complement_mask;
 
        default_attr(vc);
@@ -1838,7 +1841,7 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c)
                                if (vc->vc_par[0])
                                        vc->vc_cursor_type = vc->vc_par[0] | (vc->vc_par[1] << 8) | (vc->vc_par[2] << 16);
                                else
-                                       vc->vc_cursor_type = CUR_DEFAULT;
+                                       vc->vc_cursor_type = cur_default;
                                return;
                        }
                        break;
index 22db05a67bfbc2beb107e6f09650f6700bbcea6f..7785d8ffa40486841e3d3f09d66f50416fb91b6e 100644 (file)
@@ -9,6 +9,11 @@
  * Intel 5100X Chipset Memory Controller Hub (MCH) - Datasheet
  *      http://download.intel.com/design/chipsets/datashts/318378.pdf
  *
+ * The intel 5100 has two independent channels. EDAC core currently
+ * can not reflect this configuration so instead the chip-select
+ * rows for each respective channel are layed out one after another,
+ * the first half belonging to channel 0, the second half belonging
+ * to channel 1.
  */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -25,6 +30,8 @@
 
 /* device 16, func 1 */
 #define I5100_MC               0x40    /* Memory Control Register */
+#define        I5100_MC_SCRBEN_MASK    (1 << 7)
+#define        I5100_MC_SCRBDONE_MASK  (1 << 4)
 #define I5100_MS               0x44    /* Memory Status Register */
 #define I5100_SPDDATA          0x48    /* Serial Presence Detect Status Reg */
 #define I5100_SPDCMD           0x4c    /* Serial Presence Detect Command Reg */
 
 /* bit field accessors */
 
+static inline u32 i5100_mc_scrben(u32 mc)
+{
+       return mc >> 7 & 1;
+}
+
 static inline u32 i5100_mc_errdeten(u32 mc)
 {
        return mc >> 5 & 1;
 }
 
+static inline u32 i5100_mc_scrbdone(u32 mc)
+{
+       return mc >> 4 & 1;
+}
+
 static inline u16 i5100_spddata_rdo(u16 a)
 {
        return a >> 15 & 1;
@@ -265,42 +282,43 @@ static inline u32 i5100_recmemb_ras(u32 a)
 }
 
 /* some generic limits */
-#define I5100_MAX_RANKS_PER_CTLR       6
-#define I5100_MAX_CTLRS                        2
+#define I5100_MAX_RANKS_PER_CHAN       6
+#define I5100_CHANNELS                     2
 #define I5100_MAX_RANKS_PER_DIMM       4
 #define I5100_DIMM_ADDR_LINES          (6 - 3) /* 64 bits / 8 bits per byte */
-#define I5100_MAX_DIMM_SLOTS_PER_CTLR  4
+#define I5100_MAX_DIMM_SLOTS_PER_CHAN  4
 #define I5100_MAX_RANK_INTERLEAVE      4
 #define I5100_MAX_DMIRS                        5
+#define I5100_SCRUB_REFRESH_RATE       (5 * 60 * HZ)
 
 struct i5100_priv {
        /* ranks on each dimm -- 0 maps to not present -- obtained via SPD */
-       int dimm_numrank[I5100_MAX_CTLRS][I5100_MAX_DIMM_SLOTS_PER_CTLR];
+       int dimm_numrank[I5100_CHANNELS][I5100_MAX_DIMM_SLOTS_PER_CHAN];
 
        /*
         * mainboard chip select map -- maps i5100 chip selects to
         * DIMM slot chip selects.  In the case of only 4 ranks per
-        * controller, the mapping is fairly obvious but not unique.
-        * we map -1 -> NC and assume both controllers use the same
+        * channel, the mapping is fairly obvious but not unique.
+        * we map -1 -> NC and assume both channels use the same
         * map...
         *
         */
-       int dimm_csmap[I5100_MAX_DIMM_SLOTS_PER_CTLR][I5100_MAX_RANKS_PER_DIMM];
+       int dimm_csmap[I5100_MAX_DIMM_SLOTS_PER_CHAN][I5100_MAX_RANKS_PER_DIMM];
 
        /* memory interleave range */
        struct {
                u64      limit;
                unsigned way[2];
-       } mir[I5100_MAX_CTLRS];
+       } mir[I5100_CHANNELS];
 
        /* adjusted memory interleave range register */
-       unsigned amir[I5100_MAX_CTLRS];
+       unsigned amir[I5100_CHANNELS];
 
        /* dimm interleave range */
        struct {
                unsigned rank[I5100_MAX_RANK_INTERLEAVE];
                u64      limit;
-       } dmir[I5100_MAX_CTLRS][I5100_MAX_DMIRS];
+       } dmir[I5100_CHANNELS][I5100_MAX_DMIRS];
 
        /* memory technology registers... */
        struct {
@@ -310,30 +328,33 @@ struct i5100_priv {
                unsigned numbank;       /* 2 or 3 lines */
                unsigned numrow;        /* 13 .. 16 lines */
                unsigned numcol;        /* 11 .. 12 lines */
-       } mtr[I5100_MAX_CTLRS][I5100_MAX_RANKS_PER_CTLR];
+       } mtr[I5100_CHANNELS][I5100_MAX_RANKS_PER_CHAN];
 
        u64 tolm;               /* top of low memory in bytes */
-       unsigned ranksperctlr;  /* number of ranks per controller */
+       unsigned ranksperchan;  /* number of ranks per channel */
 
        struct pci_dev *mc;     /* device 16 func 1 */
        struct pci_dev *ch0mm;  /* device 21 func 0 */
        struct pci_dev *ch1mm;  /* device 22 func 0 */
+
+       struct delayed_work i5100_scrubbing;
+       int scrub_enable;
 };
 
-/* map a rank/ctlr to a slot number on the mainboard */
+/* map a rank/chan to a slot number on the mainboard */
 static int i5100_rank_to_slot(const struct mem_ctl_info *mci,
-                             int ctlr, int rank)
+                             int chan, int rank)
 {
        const struct i5100_priv *priv = mci->pvt_info;
        int i;
 
-       for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CTLR; i++) {
+       for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CHAN; i++) {
                int j;
-               const int numrank = priv->dimm_numrank[ctlr][i];
+               const int numrank = priv->dimm_numrank[chan][i];
 
                for (j = 0; j < numrank; j++)
                        if (priv->dimm_csmap[i][j] == rank)
-                               return i * 2 + ctlr;
+                               return i * 2 + chan;
        }
 
        return -1;
@@ -374,32 +395,32 @@ static const char *i5100_err_msg(unsigned err)
        return "none";
 }
 
-/* convert csrow index into a rank (per controller -- 0..5) */
+/* convert csrow index into a rank (per channel -- 0..5) */
 static int i5100_csrow_to_rank(const struct mem_ctl_info *mci, int csrow)
 {
        const struct i5100_priv *priv = mci->pvt_info;
 
-       return csrow % priv->ranksperctlr;
+       return csrow % priv->ranksperchan;
 }
 
-/* convert csrow index into a controller (0..1) */
-static int i5100_csrow_to_cntlr(const struct mem_ctl_info *mci, int csrow)
+/* convert csrow index into a channel (0..1) */
+static int i5100_csrow_to_chan(const struct mem_ctl_info *mci, int csrow)
 {
        const struct i5100_priv *priv = mci->pvt_info;
 
-       return csrow / priv->ranksperctlr;
+       return csrow / priv->ranksperchan;
 }
 
 static unsigned i5100_rank_to_csrow(const struct mem_ctl_info *mci,
-                                   int ctlr, int rank)
+                                   int chan, int rank)
 {
        const struct i5100_priv *priv = mci->pvt_info;
 
-       return ctlr * priv->ranksperctlr + rank;
+       return chan * priv->ranksperchan + rank;
 }
 
 static void i5100_handle_ce(struct mem_ctl_info *mci,
-                           int ctlr,
+                           int chan,
                            unsigned bank,
                            unsigned rank,
                            unsigned long syndrome,
@@ -407,12 +428,12 @@ static void i5100_handle_ce(struct mem_ctl_info *mci,
                            unsigned ras,
                            const char *msg)
 {
-       const int csrow = i5100_rank_to_csrow(mci, ctlr, rank);
+       const int csrow = i5100_rank_to_csrow(mci, chan, rank);
 
        printk(KERN_ERR
-               "CE ctlr %d, bank %u, rank %u, syndrome 0x%lx, "
+               "CE chan %d, bank %u, rank %u, syndrome 0x%lx, "
                "cas %u, ras %u, csrow %u, label \"%s\": %s\n",
-               ctlr, bank, rank, syndrome, cas, ras,
+               chan, bank, rank, syndrome, cas, ras,
                csrow, mci->csrows[csrow].channels[0].label, msg);
 
        mci->ce_count++;
@@ -421,7 +442,7 @@ static void i5100_handle_ce(struct mem_ctl_info *mci,
 }
 
 static void i5100_handle_ue(struct mem_ctl_info *mci,
-                           int ctlr,
+                           int chan,
                            unsigned bank,
                            unsigned rank,
                            unsigned long syndrome,
@@ -429,23 +450,23 @@ static void i5100_handle_ue(struct mem_ctl_info *mci,
                            unsigned ras,
                            const char *msg)
 {
-       const int csrow = i5100_rank_to_csrow(mci, ctlr, rank);
+       const int csrow = i5100_rank_to_csrow(mci, chan, rank);
 
        printk(KERN_ERR
-               "UE ctlr %d, bank %u, rank %u, syndrome 0x%lx, "
+               "UE chan %d, bank %u, rank %u, syndrome 0x%lx, "
                "cas %u, ras %u, csrow %u, label \"%s\": %s\n",
-               ctlr, bank, rank, syndrome, cas, ras,
+               chan, bank, rank, syndrome, cas, ras,
                csrow, mci->csrows[csrow].channels[0].label, msg);
 
        mci->ue_count++;
        mci->csrows[csrow].ue_count++;
 }
 
-static void i5100_read_log(struct mem_ctl_info *mci, int ctlr,
+static void i5100_read_log(struct mem_ctl_info *mci, int chan,
                           u32 ferr, u32 nerr)
 {
        struct i5100_priv *priv = mci->pvt_info;
-       struct pci_dev *pdev = (ctlr) ? priv->ch1mm : priv->ch0mm;
+       struct pci_dev *pdev = (chan) ? priv->ch1mm : priv->ch0mm;
        u32 dw;
        u32 dw2;
        unsigned syndrome = 0;
@@ -484,7 +505,7 @@ static void i5100_read_log(struct mem_ctl_info *mci, int ctlr,
                else
                        msg = i5100_err_msg(nerr);
 
-               i5100_handle_ce(mci, ctlr, bank, rank, syndrome, cas, ras, msg);
+               i5100_handle_ce(mci, chan, bank, rank, syndrome, cas, ras, msg);
        }
 
        if (i5100_validlog_nrecmemvalid(dw)) {
@@ -506,7 +527,7 @@ static void i5100_read_log(struct mem_ctl_info *mci, int ctlr,
                else
                        msg = i5100_err_msg(nerr);
 
-               i5100_handle_ue(mci, ctlr, bank, rank, syndrome, cas, ras, msg);
+               i5100_handle_ue(mci, chan, bank, rank, syndrome, cas, ras, msg);
        }
 
        pci_write_config_dword(pdev, I5100_VALIDLOG, dw);
@@ -534,6 +555,80 @@ static void i5100_check_error(struct mem_ctl_info *mci)
        }
 }
 
+/* The i5100 chipset will scrub the entire memory once, then
+ * set a done bit. Continuous scrubbing is achieved by enqueing
+ * delayed work to a workqueue, checking every few minutes if
+ * the scrubbing has completed and if so reinitiating it.
+ */
+
+static void i5100_refresh_scrubbing(struct work_struct *work)
+{
+       struct delayed_work *i5100_scrubbing = container_of(work,
+                                                           struct delayed_work,
+                                                           work);
+       struct i5100_priv *priv = container_of(i5100_scrubbing,
+                                              struct i5100_priv,
+                                              i5100_scrubbing);
+       u32 dw;
+
+       pci_read_config_dword(priv->mc, I5100_MC, &dw);
+
+       if (priv->scrub_enable) {
+
+               pci_read_config_dword(priv->mc, I5100_MC, &dw);
+
+               if (i5100_mc_scrbdone(dw)) {
+                       dw |= I5100_MC_SCRBEN_MASK;
+                       pci_write_config_dword(priv->mc, I5100_MC, dw);
+                       pci_read_config_dword(priv->mc, I5100_MC, &dw);
+               }
+
+               schedule_delayed_work(&(priv->i5100_scrubbing),
+                                     I5100_SCRUB_REFRESH_RATE);
+       }
+}
+/*
+ * The bandwidth is based on experimentation, feel free to refine it.
+ */
+static int i5100_set_scrub_rate(struct mem_ctl_info *mci,
+                                      u32 *bandwidth)
+{
+       struct i5100_priv *priv = mci->pvt_info;
+       u32 dw;
+
+       pci_read_config_dword(priv->mc, I5100_MC, &dw);
+       if (*bandwidth) {
+               priv->scrub_enable = 1;
+               dw |= I5100_MC_SCRBEN_MASK;
+               schedule_delayed_work(&(priv->i5100_scrubbing),
+                                     I5100_SCRUB_REFRESH_RATE);
+       } else {
+               priv->scrub_enable = 0;
+               dw &= ~I5100_MC_SCRBEN_MASK;
+               cancel_delayed_work(&(priv->i5100_scrubbing));
+       }
+       pci_write_config_dword(priv->mc, I5100_MC, dw);
+
+       pci_read_config_dword(priv->mc, I5100_MC, &dw);
+
+       *bandwidth = 5900000 * i5100_mc_scrben(dw);
+
+       return 0;
+}
+
+static int i5100_get_scrub_rate(struct mem_ctl_info *mci,
+                               u32 *bandwidth)
+{
+       struct i5100_priv *priv = mci->pvt_info;
+       u32 dw;
+
+       pci_read_config_dword(priv->mc, I5100_MC, &dw);
+
+       *bandwidth = 5900000 * i5100_mc_scrben(dw);
+
+       return 0;
+}
+
 static struct pci_dev *pci_get_device_func(unsigned vendor,
                                           unsigned device,
                                           unsigned func)
@@ -557,19 +652,19 @@ static unsigned long __devinit i5100_npages(struct mem_ctl_info *mci,
                                            int csrow)
 {
        struct i5100_priv *priv = mci->pvt_info;
-       const unsigned ctlr_rank = i5100_csrow_to_rank(mci, csrow);
-       const unsigned ctlr = i5100_csrow_to_cntlr(mci, csrow);
+       const unsigned chan_rank = i5100_csrow_to_rank(mci, csrow);
+       const unsigned chan = i5100_csrow_to_chan(mci, csrow);
        unsigned addr_lines;
 
        /* dimm present? */
-       if (!priv->mtr[ctlr][ctlr_rank].present)
+       if (!priv->mtr[chan][chan_rank].present)
                return 0ULL;
 
        addr_lines =
                I5100_DIMM_ADDR_LINES +
-               priv->mtr[ctlr][ctlr_rank].numcol +
-               priv->mtr[ctlr][ctlr_rank].numrow +
-               priv->mtr[ctlr][ctlr_rank].numbank;
+               priv->mtr[chan][chan_rank].numcol +
+               priv->mtr[chan][chan_rank].numrow +
+               priv->mtr[chan][chan_rank].numbank;
 
        return (unsigned long)
                ((unsigned long long) (1ULL << addr_lines) / PAGE_SIZE);
@@ -581,11 +676,11 @@ static void __devinit i5100_init_mtr(struct mem_ctl_info *mci)
        struct pci_dev *mms[2] = { priv->ch0mm, priv->ch1mm };
        int i;
 
-       for (i = 0; i < I5100_MAX_CTLRS; i++) {
+       for (i = 0; i < I5100_CHANNELS; i++) {
                int j;
                struct pci_dev *pdev = mms[i];
 
-               for (j = 0; j < I5100_MAX_RANKS_PER_CTLR; j++) {
+               for (j = 0; j < I5100_MAX_RANKS_PER_CHAN; j++) {
                        const unsigned addr =
                                (j < 4) ? I5100_MTR_0 + j * 2 :
                                          I5100_MTR_4 + (j - 4) * 2;
@@ -644,7 +739,6 @@ static int i5100_read_spd_byte(const struct mem_ctl_info *mci,
  * fill dimm chip select map
  *
  * FIXME:
- *   o only valid for 4 ranks per controller
  *   o not the only way to may chip selects to dimm slots
  *   o investigate if there is some way to obtain this map from the bios
  */
@@ -653,9 +747,7 @@ static void __devinit i5100_init_dimm_csmap(struct mem_ctl_info *mci)
        struct i5100_priv *priv = mci->pvt_info;
        int i;
 
-       WARN_ON(priv->ranksperctlr != 4);
-
-       for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CTLR; i++) {
+       for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CHAN; i++) {
                int j;
 
                for (j = 0; j < I5100_MAX_RANKS_PER_DIMM; j++)
@@ -663,12 +755,21 @@ static void __devinit i5100_init_dimm_csmap(struct mem_ctl_info *mci)
        }
 
        /* only 2 chip selects per slot... */
-       priv->dimm_csmap[0][0] = 0;
-       priv->dimm_csmap[0][1] = 3;
-       priv->dimm_csmap[1][0] = 1;
-       priv->dimm_csmap[1][1] = 2;
-       priv->dimm_csmap[2][0] = 2;
-       priv->dimm_csmap[3][0] = 3;
+       if (priv->ranksperchan == 4) {
+               priv->dimm_csmap[0][0] = 0;
+               priv->dimm_csmap[0][1] = 3;
+               priv->dimm_csmap[1][0] = 1;
+               priv->dimm_csmap[1][1] = 2;
+               priv->dimm_csmap[2][0] = 2;
+               priv->dimm_csmap[3][0] = 3;
+       } else {
+               priv->dimm_csmap[0][0] = 0;
+               priv->dimm_csmap[0][1] = 1;
+               priv->dimm_csmap[1][0] = 2;
+               priv->dimm_csmap[1][1] = 3;
+               priv->dimm_csmap[2][0] = 4;
+               priv->dimm_csmap[2][1] = 5;
+       }
 }
 
 static void __devinit i5100_init_dimm_layout(struct pci_dev *pdev,
@@ -677,10 +778,10 @@ static void __devinit i5100_init_dimm_layout(struct pci_dev *pdev,
        struct i5100_priv *priv = mci->pvt_info;
        int i;
 
-       for (i = 0; i < I5100_MAX_CTLRS; i++) {
+       for (i = 0; i < I5100_CHANNELS; i++) {
                int j;
 
-               for (j = 0; j < I5100_MAX_DIMM_SLOTS_PER_CTLR; j++) {
+               for (j = 0; j < I5100_MAX_DIMM_SLOTS_PER_CHAN; j++) {
                        u8 rank;
 
                        if (i5100_read_spd_byte(mci, i, j, 5, &rank) < 0)
@@ -720,7 +821,7 @@ static void __devinit i5100_init_interleaving(struct pci_dev *pdev,
        pci_read_config_word(pdev, I5100_AMIR_1, &w);
        priv->amir[1] = w;
 
-       for (i = 0; i < I5100_MAX_CTLRS; i++) {
+       for (i = 0; i < I5100_CHANNELS; i++) {
                int j;
 
                for (j = 0; j < 5; j++) {
@@ -747,7 +848,7 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
 
        for (i = 0; i < mci->nr_csrows; i++) {
                const unsigned long npages = i5100_npages(mci, i);
-               const unsigned cntlr = i5100_csrow_to_cntlr(mci, i);
+               const unsigned chan = i5100_csrow_to_chan(mci, i);
                const unsigned rank = i5100_csrow_to_rank(mci, i);
 
                if (!npages)
@@ -765,7 +866,7 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
                mci->csrows[i].grain = 32;
                mci->csrows[i].csrow_idx = i;
                mci->csrows[i].dtype =
-                       (priv->mtr[cntlr][rank].width == 4) ? DEV_X4 : DEV_X8;
+                       (priv->mtr[chan][rank].width == 4) ? DEV_X4 : DEV_X8;
                mci->csrows[i].ue_count = 0;
                mci->csrows[i].ce_count = 0;
                mci->csrows[i].mtype = MEM_RDDR2;
@@ -777,7 +878,7 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
                mci->csrows[i].channels[0].csrow = mci->csrows + i;
                snprintf(mci->csrows[i].channels[0].label,
                         sizeof(mci->csrows[i].channels[0].label),
-                        "DIMM%u", i5100_rank_to_slot(mci, cntlr, rank));
+                        "DIMM%u", i5100_rank_to_slot(mci, chan, rank));
 
                total_pages += npages;
        }
@@ -815,13 +916,6 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
        pci_read_config_dword(pdev, I5100_MS, &dw);
        ranksperch = !!(dw & (1 << 8)) * 2 + 4;
 
-       if (ranksperch != 4) {
-               /* FIXME: get 6 ranks / controller to work - need hw... */
-               printk(KERN_INFO "i5100_edac: unsupported configuration.\n");
-               ret = -ENODEV;
-               goto bail_pdev;
-       }
-
        /* enable error reporting... */
        pci_read_config_dword(pdev, I5100_EMASK_MEM, &dw);
        dw &= ~I5100_FERR_NF_MEM_ANY_MASK;
@@ -864,11 +958,21 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
        mci->dev = &pdev->dev;
 
        priv = mci->pvt_info;
-       priv->ranksperctlr = ranksperch;
+       priv->ranksperchan = ranksperch;
        priv->mc = pdev;
        priv->ch0mm = ch0mm;
        priv->ch1mm = ch1mm;
 
+       INIT_DELAYED_WORK(&(priv->i5100_scrubbing), i5100_refresh_scrubbing);
+
+       /* If scrubbing was already enabled by the bios, start maintaining it */
+       pci_read_config_dword(pdev, I5100_MC, &dw);
+       if (i5100_mc_scrben(dw)) {
+               priv->scrub_enable = 1;
+               schedule_delayed_work(&(priv->i5100_scrubbing),
+                                     I5100_SCRUB_REFRESH_RATE);
+       }
+
        i5100_init_dimm_layout(pdev, mci);
        i5100_init_interleaving(pdev, mci);
 
@@ -882,6 +986,8 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
        mci->ctl_page_to_phys = NULL;
 
        mci->edac_check = i5100_check_error;
+       mci->set_sdram_scrub_rate = i5100_set_scrub_rate;
+       mci->get_sdram_scrub_rate = i5100_get_scrub_rate;
 
        i5100_init_csrows(mci);
 
@@ -897,12 +1003,14 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
 
        if (edac_mc_add_mc(mci)) {
                ret = -ENODEV;
-               goto bail_mc;
+               goto bail_scrub;
        }
 
        return ret;
 
-bail_mc:
+bail_scrub:
+       priv->scrub_enable = 0;
+       cancel_delayed_work_sync(&(priv->i5100_scrubbing));
        edac_mc_free(mci);
 
 bail_disable_ch1:
@@ -935,6 +1043,10 @@ static void __devexit i5100_remove_one(struct pci_dev *pdev)
                return;
 
        priv = mci->pvt_info;
+
+       priv->scrub_enable = 0;
+       cancel_delayed_work_sync(&(priv->i5100_scrubbing));
+
        pci_disable_device(pdev);
        pci_disable_device(priv->ch0mm);
        pci_disable_device(priv->ch1mm);
index 57ca339924efa5fceb09018b4f2096609a3194ab..a019b49ecc9b0b06816d64d2c5d1e2fa2ddac08c 100644 (file)
@@ -206,6 +206,12 @@ config GPIO_LANGWELL
        help
          Say Y here to support Intel Moorestown platform GPIO.
 
+config GPIO_TIMBERDALE
+       bool "Support for timberdale GPIO IP"
+       depends on MFD_TIMBERDALE && GPIOLIB && HAS_IOMEM
+       ---help---
+       Add support for the GPIO IP in the timberdale FPGA.
+
 comment "SPI GPIO expanders:"
 
 config GPIO_MAX7301
index 270b6d7839f5dde53e7d02b01e7065bdf08011d4..52fe4cf734c77498b3d66417eb2260b1bd1c3681 100644 (file)
@@ -13,6 +13,7 @@ obj-$(CONFIG_GPIO_MCP23S08)   += mcp23s08.o
 obj-$(CONFIG_GPIO_PCA953X)     += pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)     += pcf857x.o
 obj-$(CONFIG_GPIO_PL061)       += pl061.o
+obj-$(CONFIG_GPIO_TIMBERDALE)  += timbgpio.o
 obj-$(CONFIG_GPIO_TWL4030)     += twl4030-gpio.o
 obj-$(CONFIG_GPIO_UCB1400)     += ucb1400_gpio.o
 obj-$(CONFIG_GPIO_XILINX)      += xilinx_gpio.o
index 50de0f5750d8b4f5e76c853fe590f08fe52c1a22..a25ad284a272799d2b4f91634fa8d985e41a885c 100644 (file)
@@ -53,6 +53,7 @@ struct gpio_desc {
 #define FLAG_SYSFS     4       /* exported via /sys/class/gpio/control */
 #define FLAG_TRIG_FALL 5       /* trigger on falling edge */
 #define FLAG_TRIG_RISE 6       /* trigger on rising edge */
+#define FLAG_ACTIVE_LOW        7       /* sysfs value has active low */
 
 #define PDESC_ID_SHIFT 16      /* add new flags before this one */
 
@@ -210,6 +211,11 @@ static DEFINE_MUTEX(sysfs_lock);
  *      * configures behavior of poll(2) on /value
  *      * available only if pin can generate IRQs on input
  *      * is read/write as "none", "falling", "rising", or "both"
+ *   /active_low
+ *      * configures polarity of /value
+ *      * is read/write as zero/nonzero
+ *      * also affects existing and subsequent "falling" and "rising"
+ *        /edge configuration
  */
 
 static ssize_t gpio_direction_show(struct device *dev,
@@ -255,7 +261,7 @@ static ssize_t gpio_direction_store(struct device *dev,
        return status ? : size;
 }
 
-static const DEVICE_ATTR(direction, 0644,
+static /* const */ DEVICE_ATTR(direction, 0644,
                gpio_direction_show, gpio_direction_store);
 
 static ssize_t gpio_value_show(struct device *dev,
@@ -267,10 +273,17 @@ static ssize_t gpio_value_show(struct device *dev,
 
        mutex_lock(&sysfs_lock);
 
-       if (!test_bit(FLAG_EXPORT, &desc->flags))
+       if (!test_bit(FLAG_EXPORT, &desc->flags)) {
                status = -EIO;
-       else
-               status = sprintf(buf, "%d\n", !!gpio_get_value_cansleep(gpio));
+       } else {
+               int value;
+
+               value = !!gpio_get_value_cansleep(gpio);
+               if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+                       value = !value;
+
+               status = sprintf(buf, "%d\n", value);
+       }
 
        mutex_unlock(&sysfs_lock);
        return status;
@@ -294,6 +307,8 @@ static ssize_t gpio_value_store(struct device *dev,
 
                status = strict_strtol(buf, 0, &value);
                if (status == 0) {
+                       if (test_bit(FLAG_ACTIVE_LOW, &desc->flags))
+                               value = !value;
                        gpio_set_value_cansleep(gpio, value != 0);
                        status = size;
                }
@@ -303,7 +318,7 @@ static ssize_t gpio_value_store(struct device *dev,
        return status;
 }
 
-static /*const*/ DEVICE_ATTR(value, 0644,
+static const DEVICE_ATTR(value, 0644,
                gpio_value_show, gpio_value_store);
 
 static irqreturn_t gpio_sysfs_irq(int irq, void *priv)
@@ -352,9 +367,11 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
 
        irq_flags = IRQF_SHARED;
        if (test_bit(FLAG_TRIG_FALL, &gpio_flags))
-               irq_flags |= IRQF_TRIGGER_FALLING;
+               irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+                       IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
        if (test_bit(FLAG_TRIG_RISE, &gpio_flags))
-               irq_flags |= IRQF_TRIGGER_RISING;
+               irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+                       IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
 
        if (!pdesc) {
                pdesc = kmalloc(sizeof(*pdesc), GFP_KERNEL);
@@ -475,9 +492,79 @@ found:
 
 static DEVICE_ATTR(edge, 0644, gpio_edge_show, gpio_edge_store);
 
+static int sysfs_set_active_low(struct gpio_desc *desc, struct device *dev,
+                               int value)
+{
+       int                     status = 0;
+
+       if (!!test_bit(FLAG_ACTIVE_LOW, &desc->flags) == !!value)
+               return 0;
+
+       if (value)
+               set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+       else
+               clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+       /* reconfigure poll(2) support if enabled on one edge only */
+       if (dev != NULL && (!!test_bit(FLAG_TRIG_RISE, &desc->flags) ^
+                               !!test_bit(FLAG_TRIG_FALL, &desc->flags))) {
+               unsigned long trigger_flags = desc->flags & GPIO_TRIGGER_MASK;
+
+               gpio_setup_irq(desc, dev, 0);
+               status = gpio_setup_irq(desc, dev, trigger_flags);
+       }
+
+       return status;
+}
+
+static ssize_t gpio_active_low_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       const struct gpio_desc  *desc = dev_get_drvdata(dev);
+       ssize_t                 status;
+
+       mutex_lock(&sysfs_lock);
+
+       if (!test_bit(FLAG_EXPORT, &desc->flags))
+               status = -EIO;
+       else
+               status = sprintf(buf, "%d\n",
+                               !!test_bit(FLAG_ACTIVE_LOW, &desc->flags));
+
+       mutex_unlock(&sysfs_lock);
+
+       return status;
+}
+
+static ssize_t gpio_active_low_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       struct gpio_desc        *desc = dev_get_drvdata(dev);
+       ssize_t                 status;
+
+       mutex_lock(&sysfs_lock);
+
+       if (!test_bit(FLAG_EXPORT, &desc->flags)) {
+               status = -EIO;
+       } else {
+               long            value;
+
+               status = strict_strtol(buf, 0, &value);
+               if (status == 0)
+                       status = sysfs_set_active_low(desc, dev, value != 0);
+       }
+
+       mutex_unlock(&sysfs_lock);
+
+       return status ? : size;
+}
+
+static const DEVICE_ATTR(active_low, 0644,
+               gpio_active_low_show, gpio_active_low_store);
+
 static const struct attribute *gpio_attrs[] = {
-       &dev_attr_direction.attr,
        &dev_attr_value.attr,
+       &dev_attr_active_low.attr,
        NULL,
 };
 
@@ -662,12 +749,12 @@ int gpio_export(unsigned gpio, bool direction_may_change)
                dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
                                desc, ioname ? ioname : "gpio%d", gpio);
                if (!IS_ERR(dev)) {
-                       if (direction_may_change)
-                               status = sysfs_create_group(&dev->kobj,
+                       status = sysfs_create_group(&dev->kobj,
                                                &gpio_attr_group);
-                       else
+
+                       if (!status && direction_may_change)
                                status = device_create_file(dev,
-                                               &dev_attr_value);
+                                               &dev_attr_direction);
 
                        if (!status && gpio_to_irq(gpio) >= 0
                                        && (direction_may_change
@@ -744,6 +831,55 @@ done:
 }
 EXPORT_SYMBOL_GPL(gpio_export_link);
 
+
+/**
+ * gpio_sysfs_set_active_low - set the polarity of gpio sysfs value
+ * @gpio: gpio to change
+ * @value: non-zero to use active low, i.e. inverted values
+ *
+ * Set the polarity of /sys/class/gpio/gpioN/value sysfs attribute.
+ * The GPIO does not have to be exported yet.  If poll(2) support has
+ * been enabled for either rising or falling edge, it will be
+ * reconfigured to follow the new polarity.
+ *
+ * Returns zero on success, else an error.
+ */
+int gpio_sysfs_set_active_low(unsigned gpio, int value)
+{
+       struct gpio_desc        *desc;
+       struct device           *dev = NULL;
+       int                     status = -EINVAL;
+
+       if (!gpio_is_valid(gpio))
+               goto done;
+
+       mutex_lock(&sysfs_lock);
+
+       desc = &gpio_desc[gpio];
+
+       if (test_bit(FLAG_EXPORT, &desc->flags)) {
+               struct device *dev;
+
+               dev = class_find_device(&gpio_class, NULL, desc, match_export);
+               if (dev == NULL) {
+                       status = -ENODEV;
+                       goto unlock;
+               }
+       }
+
+       status = sysfs_set_active_low(desc, dev, value);
+
+unlock:
+       mutex_unlock(&sysfs_lock);
+
+done:
+       if (status)
+               pr_debug("%s: gpio%d status %d\n", __func__, gpio, status);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(gpio_sysfs_set_active_low);
+
 /**
  * gpio_unexport - reverse effect of gpio_export()
  * @gpio: gpio to make unavailable
@@ -1094,6 +1230,7 @@ void gpio_free(unsigned gpio)
                }
                desc_set_label(desc, NULL);
                module_put(desc->chip->owner);
+               clear_bit(FLAG_ACTIVE_LOW, &desc->flags);
                clear_bit(FLAG_REQUESTED, &desc->flags);
        } else
                WARN_ON(extra_checks);
index 4baf3d7d0f8e6e4f1f7887625b7f73a62dba1a83..6c0ebbdc659ee3bdba7fa17256b74462c4858ff2 100644 (file)
@@ -123,7 +123,7 @@ static int lnw_irq_type(unsigned irq, unsigned type)
        void __iomem *grer = (void __iomem *)(&lnw->reg_base->GRER[reg]);
        void __iomem *gfer = (void __iomem *)(&lnw->reg_base->GFER[reg]);
 
-       if (gpio < 0 || gpio > lnw->chip.ngpio)
+       if (gpio >= lnw->chip.ngpio)
                return -EINVAL;
        spin_lock_irqsave(&lnw->lock, flags);
        if (type & IRQ_TYPE_EDGE_RISING)
diff --git a/drivers/gpio/timbgpio.c b/drivers/gpio/timbgpio.c
new file mode 100644 (file)
index 0000000..a4d344b
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ * timbgpio.c timberdale FPGA GPIO driver
+ * Copyright (c) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+/* Supports:
+ * Timberdale FPGA GPIO
+ */
+
+#include <linux/module.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/timb_gpio.h>
+#include <linux/interrupt.h>
+
+#define DRIVER_NAME "timb-gpio"
+
+#define TGPIOVAL       0x00
+#define TGPIODIR       0x04
+#define TGPIO_IER      0x08
+#define TGPIO_ISR      0x0c
+#define TGPIO_IPR      0x10
+#define TGPIO_ICR      0x14
+#define TGPIO_FLR      0x18
+#define TGPIO_LVR      0x1c
+
+struct timbgpio {
+       void __iomem            *membase;
+       spinlock_t              lock; /* mutual exclusion */
+       struct gpio_chip        gpio;
+       int                     irq_base;
+};
+
+static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
+       unsigned offset, bool enabled)
+{
+       struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio);
+       u32 reg;
+
+       spin_lock(&tgpio->lock);
+       reg = ioread32(tgpio->membase + offset);
+
+       if (enabled)
+               reg |= (1 << index);
+       else
+               reg &= ~(1 << index);
+
+       iowrite32(reg, tgpio->membase + offset);
+       spin_unlock(&tgpio->lock);
+
+       return 0;
+}
+
+static int timbgpio_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
+{
+       return timbgpio_update_bit(gpio, nr, TGPIODIR, true);
+}
+
+static int timbgpio_gpio_get(struct gpio_chip *gpio, unsigned nr)
+{
+       struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio);
+       u32 value;
+
+       value = ioread32(tgpio->membase + TGPIOVAL);
+       return (value & (1 << nr)) ? 1 : 0;
+}
+
+static int timbgpio_gpio_direction_output(struct gpio_chip *gpio,
+                                               unsigned nr, int val)
+{
+       return timbgpio_update_bit(gpio, nr, TGPIODIR, false);
+}
+
+static void timbgpio_gpio_set(struct gpio_chip *gpio,
+                               unsigned nr, int val)
+{
+       timbgpio_update_bit(gpio, nr, TGPIOVAL, val != 0);
+}
+
+static int timbgpio_to_irq(struct gpio_chip *gpio, unsigned offset)
+{
+       struct timbgpio *tgpio = container_of(gpio, struct timbgpio, gpio);
+
+       if (tgpio->irq_base <= 0)
+               return -EINVAL;
+
+       return tgpio->irq_base + offset;
+}
+
+/*
+ * GPIO IRQ
+ */
+static void timbgpio_irq_disable(unsigned irq)
+{
+       struct timbgpio *tgpio = get_irq_chip_data(irq);
+       int offset = irq - tgpio->irq_base;
+
+       timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 0);
+}
+
+static void timbgpio_irq_enable(unsigned irq)
+{
+       struct timbgpio *tgpio = get_irq_chip_data(irq);
+       int offset = irq - tgpio->irq_base;
+
+       timbgpio_update_bit(&tgpio->gpio, offset, TGPIO_IER, 1);
+}
+
+static int timbgpio_irq_type(unsigned irq, unsigned trigger)
+{
+       struct timbgpio *tgpio = get_irq_chip_data(irq);
+       int offset = irq - tgpio->irq_base;
+       unsigned long flags;
+       u32 lvr, flr;
+
+       if (offset < 0 || offset > tgpio->gpio.ngpio)
+               return -EINVAL;
+
+       spin_lock_irqsave(&tgpio->lock, flags);
+
+       lvr = ioread32(tgpio->membase + TGPIO_LVR);
+       flr = ioread32(tgpio->membase + TGPIO_FLR);
+
+       if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
+               flr &= ~(1 << offset);
+               if (trigger & IRQ_TYPE_LEVEL_HIGH)
+                       lvr |= 1 << offset;
+               else
+                       lvr &= ~(1 << offset);
+       }
+
+       if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+               return -EINVAL;
+       else {
+               flr |= 1 << offset;
+               /* opposite compared to the datasheet, but it mirrors the
+                * reality
+                */
+               if (trigger & IRQ_TYPE_EDGE_FALLING)
+                       lvr |= 1 << offset;
+               else
+                       lvr &= ~(1 << offset);
+       }
+
+       iowrite32(lvr, tgpio->membase + TGPIO_LVR);
+       iowrite32(flr, tgpio->membase + TGPIO_FLR);
+       iowrite32(1 << offset, tgpio->membase + TGPIO_ICR);
+       spin_unlock_irqrestore(&tgpio->lock, flags);
+
+       return 0;
+}
+
+static void timbgpio_irq(unsigned int irq, struct irq_desc *desc)
+{
+       struct timbgpio *tgpio = get_irq_data(irq);
+       unsigned long ipr;
+       int offset;
+
+       desc->chip->ack(irq);
+       ipr = ioread32(tgpio->membase + TGPIO_IPR);
+       iowrite32(ipr, tgpio->membase + TGPIO_ICR);
+
+       for_each_bit(offset, &ipr, tgpio->gpio.ngpio)
+               generic_handle_irq(timbgpio_to_irq(&tgpio->gpio, offset));
+}
+
+static struct irq_chip timbgpio_irqchip = {
+       .name           = "GPIO",
+       .enable         = timbgpio_irq_enable,
+       .disable        = timbgpio_irq_disable,
+       .set_type       = timbgpio_irq_type,
+};
+
+static int __devinit timbgpio_probe(struct platform_device *pdev)
+{
+       int err, i;
+       struct gpio_chip *gc;
+       struct timbgpio *tgpio;
+       struct resource *iomem;
+       struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
+       int irq = platform_get_irq(pdev, 0);
+
+       if (!pdata || pdata->nr_pins > 32) {
+               err = -EINVAL;
+               goto err_mem;
+       }
+
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!iomem) {
+               err = -EINVAL;
+               goto err_mem;
+       }
+
+       tgpio = kzalloc(sizeof(*tgpio), GFP_KERNEL);
+       if (!tgpio) {
+               err = -EINVAL;
+               goto err_mem;
+       }
+       tgpio->irq_base = pdata->irq_base;
+
+       spin_lock_init(&tgpio->lock);
+
+       if (!request_mem_region(iomem->start, resource_size(iomem),
+               DRIVER_NAME)) {
+               err = -EBUSY;
+               goto err_request;
+       }
+
+       tgpio->membase = ioremap(iomem->start, resource_size(iomem));
+       if (!tgpio->membase) {
+               err = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       gc = &tgpio->gpio;
+
+       gc->label = dev_name(&pdev->dev);
+       gc->owner = THIS_MODULE;
+       gc->dev = &pdev->dev;
+       gc->direction_input = timbgpio_gpio_direction_input;
+       gc->get = timbgpio_gpio_get;
+       gc->direction_output = timbgpio_gpio_direction_output;
+       gc->set = timbgpio_gpio_set;
+       gc->to_irq = (irq >= 0 && tgpio->irq_base > 0) ? timbgpio_to_irq : NULL;
+       gc->dbg_show = NULL;
+       gc->base = pdata->gpio_base;
+       gc->ngpio = pdata->nr_pins;
+       gc->can_sleep = 0;
+
+       err = gpiochip_add(gc);
+       if (err)
+               goto err_chipadd;
+
+       platform_set_drvdata(pdev, tgpio);
+
+       /* make sure to disable interrupts */
+       iowrite32(0x0, tgpio->membase + TGPIO_IER);
+
+       if (irq < 0 || tgpio->irq_base <= 0)
+               return 0;
+
+       for (i = 0; i < pdata->nr_pins; i++) {
+               set_irq_chip_and_handler_name(tgpio->irq_base + i,
+                       &timbgpio_irqchip, handle_simple_irq, "mux");
+               set_irq_chip_data(tgpio->irq_base + i, tgpio);
+#ifdef CONFIG_ARM
+               set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE);
+#endif
+       }
+
+       set_irq_data(irq, tgpio);
+       set_irq_chained_handler(irq, timbgpio_irq);
+
+       return 0;
+
+err_chipadd:
+       iounmap(tgpio->membase);
+err_ioremap:
+       release_mem_region(iomem->start, resource_size(iomem));
+err_request:
+       kfree(tgpio);
+err_mem:
+       printk(KERN_ERR DRIVER_NAME": Failed to register GPIOs: %d\n", err);
+
+       return err;
+}
+
+static int __devexit timbgpio_remove(struct platform_device *pdev)
+{
+       int err;
+       struct timbgpio_platform_data *pdata = pdev->dev.platform_data;
+       struct timbgpio *tgpio = platform_get_drvdata(pdev);
+       struct resource *iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       int irq = platform_get_irq(pdev, 0);
+
+       if (irq >= 0 && tgpio->irq_base > 0) {
+               int i;
+               for (i = 0; i < pdata->nr_pins; i++) {
+                       set_irq_chip(tgpio->irq_base + i, NULL);
+                       set_irq_chip_data(tgpio->irq_base + i, NULL);
+               }
+
+               set_irq_handler(irq, NULL);
+               set_irq_data(irq, NULL);
+       }
+
+       err = gpiochip_remove(&tgpio->gpio);
+       if (err)
+               printk(KERN_ERR DRIVER_NAME": failed to remove gpio_chip\n");
+
+       iounmap(tgpio->membase);
+       release_mem_region(iomem->start, resource_size(iomem));
+       kfree(tgpio);
+
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver timbgpio_platform_driver = {
+       .driver = {
+               .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
+       },
+       .probe          = timbgpio_probe,
+       .remove         = timbgpio_remove,
+};
+
+/*--------------------------------------------------------------------------*/
+
+static int __init timbgpio_init(void)
+{
+       return platform_driver_register(&timbgpio_platform_driver);
+}
+
+static void __exit timbgpio_exit(void)
+{
+       platform_driver_unregister(&timbgpio_platform_driver);
+}
+
+module_init(timbgpio_init);
+module_exit(timbgpio_exit);
+
+MODULE_DESCRIPTION("Timberdale GPIO driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Mocean Laboratories");
+MODULE_ALIAS("platform:"DRIVER_NAME);
+
index f93f03a9e6e9e3c0cb1d034b7f746386df76bfe2..3ad76cd18b4bb41afec47c2e7b6b1ec6ad9268bc 100644 (file)
@@ -53,6 +53,17 @@ struct gru_chiplet_info {
        int     free_user_cbr;
 };
 
+/*
+ * Statictics kept for each context.
+ */
+struct gru_gseg_statistics {
+       unsigned long   fmm_tlbmiss;
+       unsigned long   upm_tlbmiss;
+       unsigned long   tlbdropin;
+       unsigned long   context_stolen;
+       unsigned long   reserved[10];
+};
+
 /* Flags for GRU options on the gru_create_context() call */
 /* Select one of the follow 4 options to specify how TLB misses are handled */
 #define GRU_OPT_MISS_DEFAULT   0x0000  /* Use default mode */
index 3c9c06618e6adaf0b3febba4cc74d9c45356bc5c..d95587cc794c81288f2211bf311f8823b9258321 100644 (file)
@@ -34,17 +34,17 @@ extern void gru_wait_abort_proc(void *cb);
 #include <asm/intrinsics.h>
 #define __flush_cache(p)               ia64_fc((unsigned long)p)
 /* Use volatile on IA64 to ensure ordering via st4.rel */
-#define gru_ordered_store_int(p, v)                                    \
+#define gru_ordered_store_ulong(p, v)                                  \
                do {                                                    \
                        barrier();                                      \
-                       *((volatile int *)(p)) = v; /* force st.rel */  \
+                       *((volatile unsigned long *)(p)) = v; /* force st.rel */        \
                } while (0)
 #elif defined(CONFIG_X86_64)
 #define __flush_cache(p)               clflush(p)
-#define gru_ordered_store_int(p, v)                                    \
+#define gru_ordered_store_ulong(p, v)                                  \
                do {                                                    \
                        barrier();                                      \
-                       *(int *)p = v;                                  \
+                       *(unsigned long *)p = v;                        \
                } while (0)
 #else
 #error "Unsupported architecture"
@@ -129,8 +129,13 @@ struct gru_instruction_bits {
  */
 struct gru_instruction {
     /* DW 0 */
-    unsigned int               op32;    /* icmd,xtype,iaa0,ima,opc */
-    unsigned int               tri0;
+    union {
+       unsigned long           op64;    /* icmd,xtype,iaa0,ima,opc,tri0 */
+       struct {
+               unsigned int    op32;
+               unsigned int    tri0;
+       };
+    };
     unsigned long              tri1_bufsize;           /* DW 1 */
     unsigned long              baddr0;                 /* DW 2 */
     unsigned long              nelem;                  /* DW 3 */
@@ -140,7 +145,7 @@ struct gru_instruction {
     unsigned long              avalue;                 /* DW 7 */
 };
 
-/* Some shifts and masks for the low 32 bits of a GRU command */
+/* Some shifts and masks for the low 64 bits of a GRU command */
 #define GRU_CB_ICMD_SHFT       0
 #define GRU_CB_ICMD_MASK       0x1
 #define GRU_CB_XTYPE_SHFT      8
@@ -155,6 +160,10 @@ struct gru_instruction {
 #define GRU_CB_OPC_MASK                0xff
 #define GRU_CB_EXOPC_SHFT      24
 #define GRU_CB_EXOPC_MASK      0xff
+#define GRU_IDEF2_SHFT         32
+#define GRU_IDEF2_MASK         0x3ffff
+#define GRU_ISTATUS_SHFT       56
+#define GRU_ISTATUS_MASK       0x3
 
 /* GRU instruction opcodes (opc field) */
 #define OP_NOP         0x00
@@ -256,6 +265,7 @@ struct gru_instruction {
 #define CBE_CAUSE_PROTOCOL_STATE_DATA_ERROR    (1 << 16)
 #define CBE_CAUSE_RA_RESPONSE_DATA_ERROR       (1 << 17)
 #define CBE_CAUSE_HA_RESPONSE_DATA_ERROR       (1 << 18)
+#define CBE_CAUSE_FORCED_ERROR                 (1 << 19)
 
 /* CBE cbrexecstatus bits */
 #define CBR_EXS_ABORT_OCC_BIT                  0
@@ -264,13 +274,15 @@ struct gru_instruction {
 #define CBR_EXS_QUEUED_BIT                     3
 #define CBR_EXS_TLB_INVAL_BIT                  4
 #define CBR_EXS_EXCEPTION_BIT                  5
+#define CBR_EXS_CB_INT_PENDING_BIT             6
 
 #define CBR_EXS_ABORT_OCC                      (1 << CBR_EXS_ABORT_OCC_BIT)
 #define CBR_EXS_INT_OCC                                (1 << CBR_EXS_INT_OCC_BIT)
 #define CBR_EXS_PENDING                                (1 << CBR_EXS_PENDING_BIT)
 #define CBR_EXS_QUEUED                         (1 << CBR_EXS_QUEUED_BIT)
-#define CBR_TLB_INVAL                          (1 << CBR_EXS_TLB_INVAL_BIT)
+#define CBR_EXS_TLB_INVAL                      (1 << CBR_EXS_TLB_INVAL_BIT)
 #define CBR_EXS_EXCEPTION                      (1 << CBR_EXS_EXCEPTION_BIT)
+#define CBR_EXS_CB_INT_PENDING                 (1 << CBR_EXS_CB_INT_PENDING_BIT)
 
 /*
  * Exceptions are retried for the following cases. If any OTHER bits are set
@@ -296,12 +308,14 @@ union gru_mesqhead {
 
 
 /* Generate the low word of a GRU instruction */
-static inline unsigned int
-__opword(unsigned char opcode, unsigned char exopc, unsigned char xtype,
+static inline unsigned long
+__opdword(unsigned char opcode, unsigned char exopc, unsigned char xtype,
        unsigned char iaa0, unsigned char iaa1,
-       unsigned char ima)
+       unsigned long idef2, unsigned char ima)
 {
     return (1 << GRU_CB_ICMD_SHFT) |
+          ((unsigned long)CBS_ACTIVE << GRU_ISTATUS_SHFT) |
+          (idef2<< GRU_IDEF2_SHFT) |
           (iaa0 << GRU_CB_IAA0_SHFT) |
           (iaa1 << GRU_CB_IAA1_SHFT) |
           (ima << GRU_CB_IMA_SHFT) |
@@ -319,12 +333,13 @@ static inline void gru_flush_cache(void *p)
 }
 
 /*
- * Store the lower 32 bits of the command including the "start" bit. Then
+ * Store the lower 64 bits of the command including the "start" bit. Then
  * start the instruction executing.
  */
-static inline void gru_start_instruction(struct gru_instruction *ins, int op32)
+static inline void gru_start_instruction(struct gru_instruction *ins, unsigned long op64)
 {
-       gru_ordered_store_int(ins, op32);
+       gru_ordered_store_ulong(ins, op64);
+       mb();
        gru_flush_cache(ins);
 }
 
@@ -340,6 +355,30 @@ static inline void gru_start_instruction(struct gru_instruction *ins, int op32)
  *             - nelem and stride are in elements
  *             - tri0/tri1 is in bytes for the beginning of the data segment.
  */
+static inline void gru_vload_phys(void *cb, unsigned long gpa,
+               unsigned int tri0, int iaa, unsigned long hints)
+{
+       struct gru_instruction *ins = (struct gru_instruction *)cb;
+
+       ins->baddr0 = (long)gpa | ((unsigned long)iaa << 62);
+       ins->nelem = 1;
+       ins->op1_stride = 1;
+       gru_start_instruction(ins, __opdword(OP_VLOAD, 0, XTYPE_DW, iaa, 0,
+                                       (unsigned long)tri0, CB_IMA(hints)));
+}
+
+static inline void gru_vstore_phys(void *cb, unsigned long gpa,
+               unsigned int tri0, int iaa, unsigned long hints)
+{
+       struct gru_instruction *ins = (struct gru_instruction *)cb;
+
+       ins->baddr0 = (long)gpa | ((unsigned long)iaa << 62);
+       ins->nelem = 1;
+       ins->op1_stride = 1;
+       gru_start_instruction(ins, __opdword(OP_VSTORE, 0, XTYPE_DW, iaa, 0,
+                                       (unsigned long)tri0, CB_IMA(hints)));
+}
+
 static inline void gru_vload(void *cb, unsigned long mem_addr,
                unsigned int tri0, unsigned char xtype, unsigned long nelem,
                unsigned long stride, unsigned long hints)
@@ -348,10 +387,9 @@ static inline void gru_vload(void *cb, unsigned long mem_addr,
 
        ins->baddr0 = (long)mem_addr;
        ins->nelem = nelem;
-       ins->tri0 = tri0;
        ins->op1_stride = stride;
-       gru_start_instruction(ins, __opword(OP_VLOAD, 0, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_VLOAD, 0, xtype, IAA_RAM, 0,
+                                       (unsigned long)tri0, CB_IMA(hints)));
 }
 
 static inline void gru_vstore(void *cb, unsigned long mem_addr,
@@ -362,10 +400,9 @@ static inline void gru_vstore(void *cb, unsigned long mem_addr,
 
        ins->baddr0 = (long)mem_addr;
        ins->nelem = nelem;
-       ins->tri0 = tri0;
        ins->op1_stride = stride;
-       gru_start_instruction(ins, __opword(OP_VSTORE, 0, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_VSTORE, 0, xtype, IAA_RAM, 0,
+                                       tri0, CB_IMA(hints)));
 }
 
 static inline void gru_ivload(void *cb, unsigned long mem_addr,
@@ -376,10 +413,9 @@ static inline void gru_ivload(void *cb, unsigned long mem_addr,
 
        ins->baddr0 = (long)mem_addr;
        ins->nelem = nelem;
-       ins->tri0 = tri0;
        ins->tri1_bufsize = tri1;
-       gru_start_instruction(ins, __opword(OP_IVLOAD, 0, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_IVLOAD, 0, xtype, IAA_RAM, 0,
+                                       tri0, CB_IMA(hints)));
 }
 
 static inline void gru_ivstore(void *cb, unsigned long mem_addr,
@@ -390,10 +426,9 @@ static inline void gru_ivstore(void *cb, unsigned long mem_addr,
 
        ins->baddr0 = (long)mem_addr;
        ins->nelem = nelem;
-       ins->tri0 = tri0;
        ins->tri1_bufsize = tri1;
-       gru_start_instruction(ins, __opword(OP_IVSTORE, 0, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_IVSTORE, 0, xtype, IAA_RAM, 0,
+                                       tri0, CB_IMA(hints)));
 }
 
 static inline void gru_vset(void *cb, unsigned long mem_addr,
@@ -406,8 +441,8 @@ static inline void gru_vset(void *cb, unsigned long mem_addr,
        ins->op2_value_baddr1 = value;
        ins->nelem = nelem;
        ins->op1_stride = stride;
-       gru_start_instruction(ins, __opword(OP_VSET, 0, xtype, IAA_RAM, 0,
-                                        CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_VSET, 0, xtype, IAA_RAM, 0,
+                                        0, CB_IMA(hints)));
 }
 
 static inline void gru_ivset(void *cb, unsigned long mem_addr,
@@ -420,8 +455,8 @@ static inline void gru_ivset(void *cb, unsigned long mem_addr,
        ins->op2_value_baddr1 = value;
        ins->nelem = nelem;
        ins->tri1_bufsize = tri1;
-       gru_start_instruction(ins, __opword(OP_IVSET, 0, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_IVSET, 0, xtype, IAA_RAM, 0,
+                                       0, CB_IMA(hints)));
 }
 
 static inline void gru_vflush(void *cb, unsigned long mem_addr,
@@ -433,15 +468,15 @@ static inline void gru_vflush(void *cb, unsigned long mem_addr,
        ins->baddr0 = (long)mem_addr;
        ins->op1_stride = stride;
        ins->nelem = nelem;
-       gru_start_instruction(ins, __opword(OP_VFLUSH, 0, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_VFLUSH, 0, xtype, IAA_RAM, 0,
+                                       0, CB_IMA(hints)));
 }
 
 static inline void gru_nop(void *cb, int hints)
 {
        struct gru_instruction *ins = (void *)cb;
 
-       gru_start_instruction(ins, __opword(OP_NOP, 0, 0, 0, 0, CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_NOP, 0, 0, 0, 0, 0, CB_IMA(hints)));
 }
 
 
@@ -455,10 +490,9 @@ static inline void gru_bcopy(void *cb, const unsigned long src,
        ins->baddr0 = (long)src;
        ins->op2_value_baddr1 = (long)dest;
        ins->nelem = nelem;
-       ins->tri0 = tri0;
        ins->tri1_bufsize = bufsize;
-       gru_start_instruction(ins, __opword(OP_BCOPY, 0, xtype, IAA_RAM,
-                                       IAA_RAM, CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_BCOPY, 0, xtype, IAA_RAM,
+                                       IAA_RAM, tri0, CB_IMA(hints)));
 }
 
 static inline void gru_bstore(void *cb, const unsigned long src,
@@ -470,9 +504,8 @@ static inline void gru_bstore(void *cb, const unsigned long src,
        ins->baddr0 = (long)src;
        ins->op2_value_baddr1 = (long)dest;
        ins->nelem = nelem;
-       ins->tri0 = tri0;
-       gru_start_instruction(ins, __opword(OP_BSTORE, 0, xtype, 0, IAA_RAM,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_BSTORE, 0, xtype, 0, IAA_RAM,
+                                       tri0, CB_IMA(hints)));
 }
 
 static inline void gru_gamir(void *cb, int exopc, unsigned long src,
@@ -481,8 +514,8 @@ static inline void gru_gamir(void *cb, int exopc, unsigned long src,
        struct gru_instruction *ins = (void *)cb;
 
        ins->baddr0 = (long)src;
-       gru_start_instruction(ins, __opword(OP_GAMIR, exopc, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_GAMIR, exopc, xtype, IAA_RAM, 0,
+                                       0, CB_IMA(hints)));
 }
 
 static inline void gru_gamirr(void *cb, int exopc, unsigned long src,
@@ -491,8 +524,8 @@ static inline void gru_gamirr(void *cb, int exopc, unsigned long src,
        struct gru_instruction *ins = (void *)cb;
 
        ins->baddr0 = (long)src;
-       gru_start_instruction(ins, __opword(OP_GAMIRR, exopc, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_GAMIRR, exopc, xtype, IAA_RAM, 0,
+                                       0, CB_IMA(hints)));
 }
 
 static inline void gru_gamer(void *cb, int exopc, unsigned long src,
@@ -505,8 +538,8 @@ static inline void gru_gamer(void *cb, int exopc, unsigned long src,
        ins->baddr0 = (long)src;
        ins->op1_stride = operand1;
        ins->op2_value_baddr1 = operand2;
-       gru_start_instruction(ins, __opword(OP_GAMER, exopc, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_GAMER, exopc, xtype, IAA_RAM, 0,
+                                       0, CB_IMA(hints)));
 }
 
 static inline void gru_gamerr(void *cb, int exopc, unsigned long src,
@@ -518,8 +551,8 @@ static inline void gru_gamerr(void *cb, int exopc, unsigned long src,
        ins->baddr0 = (long)src;
        ins->op1_stride = operand1;
        ins->op2_value_baddr1 = operand2;
-       gru_start_instruction(ins, __opword(OP_GAMERR, exopc, xtype, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_GAMERR, exopc, xtype, IAA_RAM, 0,
+                                       0, CB_IMA(hints)));
 }
 
 static inline void gru_gamxr(void *cb, unsigned long src,
@@ -529,8 +562,8 @@ static inline void gru_gamxr(void *cb, unsigned long src,
 
        ins->baddr0 = (long)src;
        ins->nelem = 4;
-       gru_start_instruction(ins, __opword(OP_GAMXR, EOP_XR_CSWAP, XTYPE_DW,
-                                IAA_RAM, 0, CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_GAMXR, EOP_XR_CSWAP, XTYPE_DW,
+                                IAA_RAM, 0, 0, CB_IMA(hints)));
 }
 
 static inline void gru_mesq(void *cb, unsigned long queue,
@@ -541,9 +574,8 @@ static inline void gru_mesq(void *cb, unsigned long queue,
 
        ins->baddr0 = (long)queue;
        ins->nelem = nelem;
-       ins->tri0 = tri0;
-       gru_start_instruction(ins, __opword(OP_MESQ, 0, XTYPE_CL, IAA_RAM, 0,
-                                       CB_IMA(hints)));
+       gru_start_instruction(ins, __opdword(OP_MESQ, 0, XTYPE_CL, IAA_RAM, 0,
+                                       tri0, CB_IMA(hints)));
 }
 
 static inline unsigned long gru_get_amo_value(void *cb)
@@ -662,6 +694,14 @@ static inline void gru_wait_abort(void *cb)
        gru_wait_abort_proc(cb);
 }
 
+/*
+ * Get a pointer to the start of a gseg
+ *     p       - Any valid pointer within the gseg
+ */
+static inline void *gru_get_gseg_pointer (void *p)
+{
+       return (void *)((unsigned long)p & ~(GRU_GSEG_PAGESIZE - 1));
+}
 
 /*
  * Get a pointer to a control block
index 679e01778286029bf21299db49e6284ee001475f..38657cdaf54d32b247c89e105611f0b96a267c75 100644 (file)
 #include "gru_instructions.h"
 #include <asm/uv/uv_hub.h>
 
+/* Return codes for vtop functions */
+#define VTOP_SUCCESS               0
+#define VTOP_INVALID               -1
+#define VTOP_RETRY                 -2
+
+
 /*
  * Test if a physical address is a valid GRU GSEG address
  */
@@ -90,19 +96,22 @@ static struct gru_thread_state *gru_alloc_locked_gts(unsigned long vaddr)
 {
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
-       struct gru_thread_state *gts = NULL;
+       struct gru_thread_state *gts = ERR_PTR(-EINVAL);
 
        down_write(&mm->mmap_sem);
        vma = gru_find_vma(vaddr);
-       if (vma)
-               gts = gru_alloc_thread_state(vma, TSID(vaddr, vma));
-       if (gts) {
-               mutex_lock(&gts->ts_ctxlock);
-               downgrade_write(&mm->mmap_sem);
-       } else {
-               up_write(&mm->mmap_sem);
-       }
+       if (!vma)
+               goto err;
 
+       gts = gru_alloc_thread_state(vma, TSID(vaddr, vma));
+       if (IS_ERR(gts))
+               goto err;
+       mutex_lock(&gts->ts_ctxlock);
+       downgrade_write(&mm->mmap_sem);
+       return gts;
+
+err:
+       up_write(&mm->mmap_sem);
        return gts;
 }
 
@@ -122,38 +131,14 @@ static void gru_unlock_gts(struct gru_thread_state *gts)
  * is necessary to prevent the user from seeing a stale cb.istatus that will
  * change as soon as the TFH restart is complete. Races may cause an
  * occasional failure to clear the cb.istatus, but that is ok.
- *
- * If the cb address is not valid (should not happen, but...), nothing
- * bad will happen.. The get_user()/put_user() will fail but there
- * are no bad side-effects.
  */
-static void gru_cb_set_istatus_active(unsigned long __user *cb)
+static void gru_cb_set_istatus_active(struct gru_instruction_bits *cbk)
 {
-       union {
-               struct gru_instruction_bits bits;
-               unsigned long dw;
-       } u;
-
-       if (cb) {
-               get_user(u.dw, cb);
-               u.bits.istatus = CBS_ACTIVE;
-               put_user(u.dw, cb);
+       if (cbk) {
+               cbk->istatus = CBS_ACTIVE;
        }
 }
 
-/*
- * Convert a interrupt IRQ to a pointer to the GRU GTS that caused the
- * interrupt. Interrupts are always sent to a cpu on the blade that contains the
- * GRU (except for headless blades which are not currently supported). A blade
- * has N grus; a block of N consecutive IRQs is assigned to the GRUs. The IRQ
- * number uniquely identifies the GRU chiplet on the local blade that caused the
- * interrupt. Always called in interrupt context.
- */
-static inline struct gru_state *irq_to_gru(int irq)
-{
-       return &gru_base[uv_numa_blade_id()]->bs_grus[irq - IRQ_GRU];
-}
-
 /*
  * Read & clear a TFM
  *
@@ -207,10 +192,11 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,
 {
        struct page *page;
 
-       /* ZZZ Need to handle HUGE pages */
-       if (is_vm_hugetlb_page(vma))
-               return -EFAULT;
+#ifdef CONFIG_HUGETLB_PAGE
+       *pageshift = is_vm_hugetlb_page(vma) ? HPAGE_SHIFT : PAGE_SHIFT;
+#else
        *pageshift = PAGE_SHIFT;
+#endif
        if (get_user_pages
            (current, current->mm, vaddr, 1, write, 0, &page, NULL) <= 0)
                return -EFAULT;
@@ -268,7 +254,6 @@ static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr,
        return 0;
 
 err:
-       local_irq_enable();
        return 1;
 }
 
@@ -301,14 +286,69 @@ static int gru_vtop(struct gru_thread_state *gts, unsigned long vaddr,
        paddr = paddr & ~((1UL << ps) - 1);
        *gpa = uv_soc_phys_ram_to_gpa(paddr);
        *pageshift = ps;
-       return 0;
+       return VTOP_SUCCESS;
 
 inval:
-       return -1;
+       return VTOP_INVALID;
 upm:
-       return -2;
+       return VTOP_RETRY;
+}
+
+
+/*
+ * Flush a CBE from cache. The CBE is clean in the cache. Dirty the
+ * CBE cacheline so that the line will be written back to home agent.
+ * Otherwise the line may be silently dropped. This has no impact
+ * except on performance.
+ */
+static void gru_flush_cache_cbe(struct gru_control_block_extended *cbe)
+{
+       if (unlikely(cbe)) {
+               cbe->cbrexecstatus = 0;         /* make CL dirty */
+               gru_flush_cache(cbe);
+       }
 }
 
+/*
+ * Preload the TLB with entries that may be required. Currently, preloading
+ * is implemented only for BCOPY. Preload  <tlb_preload_count> pages OR to
+ * the end of the bcopy tranfer, whichever is smaller.
+ */
+static void gru_preload_tlb(struct gru_state *gru,
+                       struct gru_thread_state *gts, int atomic,
+                       unsigned long fault_vaddr, int asid, int write,
+                       unsigned char tlb_preload_count,
+                       struct gru_tlb_fault_handle *tfh,
+                       struct gru_control_block_extended *cbe)
+{
+       unsigned long vaddr = 0, gpa;
+       int ret, pageshift;
+
+       if (cbe->opccpy != OP_BCOPY)
+               return;
+
+       if (fault_vaddr == cbe->cbe_baddr0)
+               vaddr = fault_vaddr + GRU_CACHE_LINE_BYTES * cbe->cbe_src_cl - 1;
+       else if (fault_vaddr == cbe->cbe_baddr1)
+               vaddr = fault_vaddr + (1 << cbe->xtypecpy) * cbe->cbe_nelemcur - 1;
+
+       fault_vaddr &= PAGE_MASK;
+       vaddr &= PAGE_MASK;
+       vaddr = min(vaddr, fault_vaddr + tlb_preload_count * PAGE_SIZE);
+
+       while (vaddr > fault_vaddr) {
+               ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift);
+               if (ret || tfh_write_only(tfh, gpa, GAA_RAM, vaddr, asid, write,
+                                         GRU_PAGESIZE(pageshift)))
+                       return;
+               gru_dbg(grudev,
+                       "%s: gid %d, gts 0x%p, tfh 0x%p, vaddr 0x%lx, asid 0x%x, rw %d, ps %d, gpa 0x%lx\n",
+                       atomic ? "atomic" : "non-atomic", gru->gs_gid, gts, tfh,
+                       vaddr, asid, write, pageshift, gpa);
+               vaddr -= PAGE_SIZE;
+               STAT(tlb_preload_page);
+       }
+}
 
 /*
  * Drop a TLB entry into the GRU. The fault is described by info in an TFH.
@@ -320,11 +360,14 @@ upm:
  *             < 0 = error code
  *
  */
-static int gru_try_dropin(struct gru_thread_state *gts,
+static int gru_try_dropin(struct gru_state *gru,
+                         struct gru_thread_state *gts,
                          struct gru_tlb_fault_handle *tfh,
-                         unsigned long __user *cb)
+                         struct gru_instruction_bits *cbk)
 {
-       int pageshift = 0, asid, write, ret, atomic = !cb;
+       struct gru_control_block_extended *cbe = NULL;
+       unsigned char tlb_preload_count = gts->ts_tlb_preload_count;
+       int pageshift = 0, asid, write, ret, atomic = !cbk, indexway;
        unsigned long gpa = 0, vaddr = 0;
 
        /*
@@ -334,6 +377,14 @@ static int gru_try_dropin(struct gru_thread_state *gts,
         * the dropin is ignored. This eliminates the need for additional locks.
         */
 
+       /*
+        * Prefetch the CBE if doing TLB preloading
+        */
+       if (unlikely(tlb_preload_count)) {
+               cbe = gru_tfh_to_cbe(tfh);
+               prefetchw(cbe);
+       }
+
        /*
         * Error if TFH state is IDLE or FMM mode & the user issuing a UPM call.
         * Might be a hardware race OR a stupid user. Ignore FMM because FMM
@@ -341,18 +392,20 @@ static int gru_try_dropin(struct gru_thread_state *gts,
         */
        if (tfh->status != TFHSTATUS_EXCEPTION) {
                gru_flush_cache(tfh);
+               sync_core();
                if (tfh->status != TFHSTATUS_EXCEPTION)
                        goto failnoexception;
                STAT(tfh_stale_on_fault);
        }
        if (tfh->state == TFHSTATE_IDLE)
                goto failidle;
-       if (tfh->state == TFHSTATE_MISS_FMM && cb)
+       if (tfh->state == TFHSTATE_MISS_FMM && cbk)
                goto failfmm;
 
        write = (tfh->cause & TFHCAUSE_TLB_MOD) != 0;
        vaddr = tfh->missvaddr;
        asid = tfh->missasid;
+       indexway = tfh->indexway;
        if (asid == 0)
                goto failnoasid;
 
@@ -366,41 +419,51 @@ static int gru_try_dropin(struct gru_thread_state *gts,
                goto failactive;
 
        ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift);
-       if (ret == -1)
+       if (ret == VTOP_INVALID)
                goto failinval;
-       if (ret == -2)
+       if (ret == VTOP_RETRY)
                goto failupm;
 
        if (!(gts->ts_sizeavail & GRU_SIZEAVAIL(pageshift))) {
                gts->ts_sizeavail |= GRU_SIZEAVAIL(pageshift);
-               if (atomic || !gru_update_cch(gts, 0)) {
+               if (atomic || !gru_update_cch(gts)) {
                        gts->ts_force_cch_reload = 1;
                        goto failupm;
                }
        }
-       gru_cb_set_istatus_active(cb);
+
+       if (unlikely(cbe) && pageshift == PAGE_SHIFT) {
+               gru_preload_tlb(gru, gts, atomic, vaddr, asid, write, tlb_preload_count, tfh, cbe);
+               gru_flush_cache_cbe(cbe);
+       }
+
+       gru_cb_set_istatus_active(cbk);
+       gts->ustats.tlbdropin++;
        tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write,
                          GRU_PAGESIZE(pageshift));
-       STAT(tlb_dropin);
        gru_dbg(grudev,
-               "%s: tfh 0x%p, vaddr 0x%lx, asid 0x%x, ps %d, gpa 0x%lx\n",
-               ret ? "non-atomic" : "atomic", tfh, vaddr, asid,
-               pageshift, gpa);
+               "%s: gid %d, gts 0x%p, tfh 0x%p, vaddr 0x%lx, asid 0x%x, indexway 0x%x,"
+               " rw %d, ps %d, gpa 0x%lx\n",
+               atomic ? "atomic" : "non-atomic", gru->gs_gid, gts, tfh, vaddr, asid,
+               indexway, write, pageshift, gpa);
+       STAT(tlb_dropin);
        return 0;
 
 failnoasid:
        /* No asid (delayed unload). */
        STAT(tlb_dropin_fail_no_asid);
        gru_dbg(grudev, "FAILED no_asid tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr);
-       if (!cb)
+       if (!cbk)
                tfh_user_polling_mode(tfh);
        else
                gru_flush_cache(tfh);
+       gru_flush_cache_cbe(cbe);
        return -EAGAIN;
 
 failupm:
        /* Atomic failure switch CBR to UPM */
        tfh_user_polling_mode(tfh);
+       gru_flush_cache_cbe(cbe);
        STAT(tlb_dropin_fail_upm);
        gru_dbg(grudev, "FAILED upm tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr);
        return 1;
@@ -408,6 +471,7 @@ failupm:
 failfmm:
        /* FMM state on UPM call */
        gru_flush_cache(tfh);
+       gru_flush_cache_cbe(cbe);
        STAT(tlb_dropin_fail_fmm);
        gru_dbg(grudev, "FAILED fmm tfh: 0x%p, state %d\n", tfh, tfh->state);
        return 0;
@@ -415,17 +479,20 @@ failfmm:
 failnoexception:
        /* TFH status did not show exception pending */
        gru_flush_cache(tfh);
-       if (cb)
-               gru_flush_cache(cb);
+       gru_flush_cache_cbe(cbe);
+       if (cbk)
+               gru_flush_cache(cbk);
        STAT(tlb_dropin_fail_no_exception);
-       gru_dbg(grudev, "FAILED non-exception tfh: 0x%p, status %d, state %d\n", tfh, tfh->status, tfh->state);
+       gru_dbg(grudev, "FAILED non-exception tfh: 0x%p, status %d, state %d\n",
+               tfh, tfh->status, tfh->state);
        return 0;
 
 failidle:
        /* TFH state was idle  - no miss pending */
        gru_flush_cache(tfh);
-       if (cb)
-               gru_flush_cache(cb);
+       gru_flush_cache_cbe(cbe);
+       if (cbk)
+               gru_flush_cache(cbk);
        STAT(tlb_dropin_fail_idle);
        gru_dbg(grudev, "FAILED idle tfh: 0x%p, state %d\n", tfh, tfh->state);
        return 0;
@@ -433,16 +500,18 @@ failidle:
 failinval:
        /* All errors (atomic & non-atomic) switch CBR to EXCEPTION state */
        tfh_exception(tfh);
+       gru_flush_cache_cbe(cbe);
        STAT(tlb_dropin_fail_invalid);
        gru_dbg(grudev, "FAILED inval tfh: 0x%p, vaddr 0x%lx\n", tfh, vaddr);
        return -EFAULT;
 
 failactive:
        /* Range invalidate active. Switch to UPM iff atomic */
-       if (!cb)
+       if (!cbk)
                tfh_user_polling_mode(tfh);
        else
                gru_flush_cache(tfh);
+       gru_flush_cache_cbe(cbe);
        STAT(tlb_dropin_fail_range_active);
        gru_dbg(grudev, "FAILED range active: tfh 0x%p, vaddr 0x%lx\n",
                tfh, vaddr);
@@ -455,31 +524,41 @@ failactive:
  * Note that this is the interrupt handler that is registered with linux
  * interrupt handlers.
  */
-irqreturn_t gru_intr(int irq, void *dev_id)
+static irqreturn_t gru_intr(int chiplet, int blade)
 {
        struct gru_state *gru;
        struct gru_tlb_fault_map imap, dmap;
        struct gru_thread_state *gts;
        struct gru_tlb_fault_handle *tfh = NULL;
+       struct completion *cmp;
        int cbrnum, ctxnum;
 
        STAT(intr);
 
-       gru = irq_to_gru(irq);
+       gru = &gru_base[blade]->bs_grus[chiplet];
        if (!gru) {
-               dev_err(grudev, "GRU: invalid interrupt: cpu %d, irq %d\n",
-                       raw_smp_processor_id(), irq);
+               dev_err(grudev, "GRU: invalid interrupt: cpu %d, chiplet %d\n",
+                       raw_smp_processor_id(), chiplet);
                return IRQ_NONE;
        }
        get_clear_fault_map(gru, &imap, &dmap);
+       gru_dbg(grudev,
+               "cpu %d, chiplet %d, gid %d, imap %016lx %016lx, dmap %016lx %016lx\n",
+               smp_processor_id(), chiplet, gru->gs_gid,
+               imap.fault_bits[0], imap.fault_bits[1],
+               dmap.fault_bits[0], dmap.fault_bits[1]);
 
        for_each_cbr_in_tfm(cbrnum, dmap.fault_bits) {
-               complete(gru->gs_blade->bs_async_wq);
+               STAT(intr_cbr);
+               cmp = gru->gs_blade->bs_async_wq;
+               if (cmp)
+                       complete(cmp);
                gru_dbg(grudev, "gid %d, cbr_done %d, done %d\n",
-                       gru->gs_gid, cbrnum, gru->gs_blade->bs_async_wq->done);
+                       gru->gs_gid, cbrnum, cmp ? cmp->done : -1);
        }
 
        for_each_cbr_in_tfm(cbrnum, imap.fault_bits) {
+               STAT(intr_tfh);
                tfh = get_tfh_by_index(gru, cbrnum);
                prefetchw(tfh); /* Helps on hdw, required for emulator */
 
@@ -492,14 +571,20 @@ irqreturn_t gru_intr(int irq, void *dev_id)
                ctxnum = tfh->ctxnum;
                gts = gru->gs_gts[ctxnum];
 
+               /* Spurious interrupts can cause this. Ignore. */
+               if (!gts) {
+                       STAT(intr_spurious);
+                       continue;
+               }
+
                /*
                 * This is running in interrupt context. Trylock the mmap_sem.
                 * If it fails, retry the fault in user context.
                 */
+               gts->ustats.fmm_tlbmiss++;
                if (!gts->ts_force_cch_reload &&
                                        down_read_trylock(&gts->ts_mm->mmap_sem)) {
-                       gts->ustats.fmm_tlbdropin++;
-                       gru_try_dropin(gts, tfh, NULL);
+                       gru_try_dropin(gru, gts, tfh, NULL);
                        up_read(&gts->ts_mm->mmap_sem);
                } else {
                        tfh_user_polling_mode(tfh);
@@ -509,20 +594,43 @@ irqreturn_t gru_intr(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+irqreturn_t gru0_intr(int irq, void *dev_id)
+{
+       return gru_intr(0, uv_numa_blade_id());
+}
+
+irqreturn_t gru1_intr(int irq, void *dev_id)
+{
+       return gru_intr(1, uv_numa_blade_id());
+}
+
+irqreturn_t gru_intr_mblade(int irq, void *dev_id)
+{
+       int blade;
+
+       for_each_possible_blade(blade) {
+               if (uv_blade_nr_possible_cpus(blade))
+                       continue;
+                gru_intr(0, blade);
+                gru_intr(1, blade);
+       }
+       return IRQ_HANDLED;
+}
+
 
 static int gru_user_dropin(struct gru_thread_state *gts,
                           struct gru_tlb_fault_handle *tfh,
-                          unsigned long __user *cb)
+                          void *cb)
 {
        struct gru_mm_struct *gms = gts->ts_gms;
        int ret;
 
-       gts->ustats.upm_tlbdropin++;
+       gts->ustats.upm_tlbmiss++;
        while (1) {
                wait_event(gms->ms_wait_queue,
                           atomic_read(&gms->ms_range_active) == 0);
                prefetchw(tfh); /* Helps on hdw, required for emulator */
-               ret = gru_try_dropin(gts, tfh, cb);
+               ret = gru_try_dropin(gts->ts_gru, gts, tfh, cb);
                if (ret <= 0)
                        return ret;
                STAT(call_os_wait_queue);
@@ -538,52 +646,41 @@ int gru_handle_user_call_os(unsigned long cb)
 {
        struct gru_tlb_fault_handle *tfh;
        struct gru_thread_state *gts;
-       unsigned long __user *cbp;
+       void *cbk;
        int ucbnum, cbrnum, ret = -EINVAL;
 
        STAT(call_os);
-       gru_dbg(grudev, "address 0x%lx\n", cb);
 
        /* sanity check the cb pointer */
        ucbnum = get_cb_number((void *)cb);
        if ((cb & (GRU_HANDLE_STRIDE - 1)) || ucbnum >= GRU_NUM_CB)
                return -EINVAL;
-       cbp = (unsigned long *)cb;
 
        gts = gru_find_lock_gts(cb);
        if (!gts)
                return -EINVAL;
+       gru_dbg(grudev, "address 0x%lx, gid %d, gts 0x%p\n", cb, gts->ts_gru ? gts->ts_gru->gs_gid : -1, gts);
 
        if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE)
                goto exit;
 
-       /*
-        * If force_unload is set, the UPM TLB fault is phony. The task
-        * has migrated to another node and the GSEG must be moved. Just
-        * unload the context. The task will page fault and assign a new
-        * context.
-        */
-       if (gts->ts_tgid_owner == current->tgid && gts->ts_blade >= 0 &&
-                               gts->ts_blade != uv_numa_blade_id()) {
-               STAT(call_os_offnode_reference);
-               gts->ts_force_unload = 1;
-       }
+       gru_check_context_placement(gts);
 
        /*
         * CCH may contain stale data if ts_force_cch_reload is set.
         */
        if (gts->ts_gru && gts->ts_force_cch_reload) {
                gts->ts_force_cch_reload = 0;
-               gru_update_cch(gts, 0);
+               gru_update_cch(gts);
        }
 
        ret = -EAGAIN;
        cbrnum = thread_cbr_number(gts, ucbnum);
-       if (gts->ts_force_unload) {
-               gru_unload_context(gts, 1);
-       } else if (gts->ts_gru) {
+       if (gts->ts_gru) {
                tfh = get_tfh_by_index(gts->ts_gru, cbrnum);
-               ret = gru_user_dropin(gts, tfh, cbp);
+               cbk = get_gseg_base_address_cb(gts->ts_gru->gs_gru_base_vaddr,
+                               gts->ts_ctxnum, ucbnum);
+               ret = gru_user_dropin(gts, tfh, cbk);
        }
 exit:
        gru_unlock_gts(gts);
@@ -605,11 +702,11 @@ int gru_get_exception_detail(unsigned long arg)
        if (copy_from_user(&excdet, (void __user *)arg, sizeof(excdet)))
                return -EFAULT;
 
-       gru_dbg(grudev, "address 0x%lx\n", excdet.cb);
        gts = gru_find_lock_gts(excdet.cb);
        if (!gts)
                return -EINVAL;
 
+       gru_dbg(grudev, "address 0x%lx, gid %d, gts 0x%p\n", excdet.cb, gts->ts_gru ? gts->ts_gru->gs_gid : -1, gts);
        ucbnum = get_cb_number((void *)excdet.cb);
        if (ucbnum >= gts->ts_cbr_au_count * GRU_CBR_AU_SIZE) {
                ret = -EINVAL;
@@ -617,6 +714,7 @@ int gru_get_exception_detail(unsigned long arg)
                cbrnum = thread_cbr_number(gts, ucbnum);
                cbe = get_cbe_by_index(gts->ts_gru, cbrnum);
                gru_flush_cache(cbe);   /* CBE not coherent */
+               sync_core();            /* make sure we are have current data */
                excdet.opc = cbe->opccpy;
                excdet.exopc = cbe->exopccpy;
                excdet.ecause = cbe->ecause;
@@ -624,7 +722,7 @@ int gru_get_exception_detail(unsigned long arg)
                excdet.exceptdet1 = cbe->idef3upd;
                excdet.cbrstate = cbe->cbrstate;
                excdet.cbrexecstatus = cbe->cbrexecstatus;
-               gru_flush_cache(cbe);
+               gru_flush_cache_cbe(cbe);
                ret = 0;
        } else {
                ret = -EAGAIN;
@@ -733,6 +831,11 @@ long gru_get_gseg_statistics(unsigned long arg)
        if (copy_from_user(&req, (void __user *)arg, sizeof(req)))
                return -EFAULT;
 
+       /*
+        * The library creates arrays of contexts for threaded programs.
+        * If no gts exists in the array, the context has never been used & all
+        * statistics are implicitly 0.
+        */
        gts = gru_find_lock_gts(req.gseg);
        if (gts) {
                memcpy(&req.stats, &gts->ustats, sizeof(gts->ustats));
@@ -762,11 +865,25 @@ int gru_set_context_option(unsigned long arg)
                return -EFAULT;
        gru_dbg(grudev, "op %d, gseg 0x%lx, value1 0x%lx\n", req.op, req.gseg, req.val1);
 
-       gts = gru_alloc_locked_gts(req.gseg);
-       if (!gts)
-               return -EINVAL;
+       gts = gru_find_lock_gts(req.gseg);
+       if (!gts) {
+               gts = gru_alloc_locked_gts(req.gseg);
+               if (IS_ERR(gts))
+                       return PTR_ERR(gts);
+       }
 
        switch (req.op) {
+       case sco_blade_chiplet:
+               /* Select blade/chiplet for GRU context */
+               if (req.val1 < -1 || req.val1 >= GRU_MAX_BLADES || !gru_base[req.val1] ||
+                   req.val0 < -1 || req.val0 >= GRU_CHIPLETS_PER_HUB) {
+                       ret = -EINVAL;
+               } else {
+                       gts->ts_user_blade_id = req.val1;
+                       gts->ts_user_chiplet_id = req.val0;
+                       gru_check_context_placement(gts);
+               }
+               break;
        case sco_gseg_owner:
                /* Register the current task as the GSEG owner */
                gts->ts_tgid_owner = current->tgid;
index ce5eda985ab0ebbed365a9a65dd56fe1ce7949bc..cb3b4d228475905fbdc25bc00605188e2afc53c4 100644 (file)
@@ -35,6 +35,9 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/uaccess.h>
+#ifdef CONFIG_X86_64
+#include <asm/uv/uv_irq.h>
+#endif
 #include <asm/uv/uv.h>
 #include "gru.h"
 #include "grulib.h"
@@ -130,7 +133,6 @@ static int gru_create_new_context(unsigned long arg)
        struct gru_vma_data *vdata;
        int ret = -EINVAL;
 
-
        if (copy_from_user(&req, (void __user *)arg, sizeof(req)))
                return -EFAULT;
 
@@ -150,6 +152,7 @@ static int gru_create_new_context(unsigned long arg)
                vdata->vd_dsr_au_count =
                    GRU_DS_BYTES_TO_AU(req.data_segment_bytes);
                vdata->vd_cbr_au_count = GRU_CB_COUNT_TO_AU(req.control_blocks);
+               vdata->vd_tlb_preload_count = req.tlb_preload_count;
                ret = 0;
        }
        up_write(&current->mm->mmap_sem);
@@ -190,7 +193,7 @@ static long gru_file_unlocked_ioctl(struct file *file, unsigned int req,
 {
        int err = -EBADRQC;
 
-       gru_dbg(grudev, "file %p\n", file);
+       gru_dbg(grudev, "file %p, req 0x%x, 0x%lx\n", file, req, arg);
 
        switch (req) {
        case GRU_CREATE_CONTEXT:
@@ -232,23 +235,24 @@ static long gru_file_unlocked_ioctl(struct file *file, unsigned int req,
  * system.
  */
 static void gru_init_chiplet(struct gru_state *gru, unsigned long paddr,
-                            void *vaddr, int nid, int bid, int grunum)
+                            void *vaddr, int blade_id, int chiplet_id)
 {
        spin_lock_init(&gru->gs_lock);
        spin_lock_init(&gru->gs_asid_lock);
        gru->gs_gru_base_paddr = paddr;
        gru->gs_gru_base_vaddr = vaddr;
-       gru->gs_gid = bid * GRU_CHIPLETS_PER_BLADE + grunum;
-       gru->gs_blade = gru_base[bid];
-       gru->gs_blade_id = bid;
+       gru->gs_gid = blade_id * GRU_CHIPLETS_PER_BLADE + chiplet_id;
+       gru->gs_blade = gru_base[blade_id];
+       gru->gs_blade_id = blade_id;
+       gru->gs_chiplet_id = chiplet_id;
        gru->gs_cbr_map = (GRU_CBR_AU == 64) ? ~0 : (1UL << GRU_CBR_AU) - 1;
        gru->gs_dsr_map = (1UL << GRU_DSR_AU) - 1;
        gru->gs_asid_limit = MAX_ASID;
        gru_tgh_flush_init(gru);
        if (gru->gs_gid >= gru_max_gids)
                gru_max_gids = gru->gs_gid + 1;
-       gru_dbg(grudev, "bid %d, nid %d, gid %d, vaddr %p (0x%lx)\n",
-               bid, nid, gru->gs_gid, gru->gs_gru_base_vaddr,
+       gru_dbg(grudev, "bid %d, gid %d, vaddr %p (0x%lx)\n",
+               blade_id, gru->gs_gid, gru->gs_gru_base_vaddr,
                gru->gs_gru_base_paddr);
 }
 
@@ -264,12 +268,10 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
 
        max_user_cbrs = GRU_NUM_CB;
        max_user_dsr_bytes = GRU_NUM_DSR_BYTES;
-       for_each_online_node(nid) {
-               bid = uv_node_to_blade_id(nid);
-               pnode = uv_node_to_pnode(nid);
-               if (bid < 0 || gru_base[bid])
-                       continue;
-               page = alloc_pages_exact_node(nid, GFP_KERNEL, order);
+       for_each_possible_blade(bid) {
+               pnode = uv_blade_to_pnode(bid);
+               nid = uv_blade_to_memory_nid(bid);/* -1 if no memory on blade */
+               page = alloc_pages_node(nid, GFP_KERNEL, order);
                if (!page)
                        goto fail;
                gru_base[bid] = page_address(page);
@@ -285,7 +287,7 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
                                chip++, gru++) {
                        paddr = gru_chiplet_paddr(gru_base_paddr, pnode, chip);
                        vaddr = gru_chiplet_vaddr(gru_base_vaddr, pnode, chip);
-                       gru_init_chiplet(gru, paddr, vaddr, nid, bid, chip);
+                       gru_init_chiplet(gru, paddr, vaddr, bid, chip);
                        n = hweight64(gru->gs_cbr_map) * GRU_CBR_AU_SIZE;
                        cbrs = max(cbrs, n);
                        n = hweight64(gru->gs_dsr_map) * GRU_DSR_AU_BYTES;
@@ -298,39 +300,215 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr)
        return 0;
 
 fail:
-       for (nid--; nid >= 0; nid--)
-               free_pages((unsigned long)gru_base[nid], order);
+       for (bid--; bid >= 0; bid--)
+               free_pages((unsigned long)gru_base[bid], order);
        return -ENOMEM;
 }
 
-#ifdef CONFIG_IA64
+static void gru_free_tables(void)
+{
+       int bid;
+       int order = get_order(sizeof(struct gru_state) *
+                             GRU_CHIPLETS_PER_BLADE);
 
-static int get_base_irq(void)
+       for (bid = 0; bid < GRU_MAX_BLADES; bid++)
+               free_pages((unsigned long)gru_base[bid], order);
+}
+
+static unsigned long gru_chiplet_cpu_to_mmr(int chiplet, int cpu, int *corep)
 {
-       return IRQ_GRU;
+       unsigned long mmr = 0;
+       int core;
+
+       /*
+        * We target the cores of a blade and not the hyperthreads themselves.
+        * There is a max of 8 cores per socket and 2 sockets per blade,
+        * making for a max total of 16 cores (i.e., 16 CPUs without
+        * hyperthreading and 32 CPUs with hyperthreading).
+        */
+       core = uv_cpu_core_number(cpu) + UV_MAX_INT_CORES * uv_cpu_socket_number(cpu);
+       if (core >= GRU_NUM_TFM || uv_cpu_ht_number(cpu))
+               return 0;
+
+       if (chiplet == 0) {
+               mmr = UVH_GR0_TLB_INT0_CONFIG +
+                   core * (UVH_GR0_TLB_INT1_CONFIG - UVH_GR0_TLB_INT0_CONFIG);
+       } else if (chiplet == 1) {
+               mmr = UVH_GR1_TLB_INT0_CONFIG +
+                   core * (UVH_GR1_TLB_INT1_CONFIG - UVH_GR1_TLB_INT0_CONFIG);
+       } else {
+               BUG();
+       }
+
+       *corep = core;
+       return mmr;
 }
 
-#elif defined CONFIG_X86_64
+#ifdef CONFIG_IA64
 
-static void noop(unsigned int irq)
+static int gru_irq_count[GRU_CHIPLETS_PER_BLADE];
+
+static void gru_noop(unsigned int irq)
 {
 }
 
-static struct irq_chip gru_chip = {
-       .name           = "gru",
-       .mask           = noop,
-       .unmask         = noop,
-       .ack            = noop,
+static struct irq_chip gru_chip[GRU_CHIPLETS_PER_BLADE] = {
+       [0 ... GRU_CHIPLETS_PER_BLADE - 1] {
+               .mask           = gru_noop,
+               .unmask         = gru_noop,
+               .ack            = gru_noop
+       }
 };
 
-static int get_base_irq(void)
+static int gru_chiplet_setup_tlb_irq(int chiplet, char *irq_name,
+                       irq_handler_t irq_handler, int cpu, int blade)
+{
+       unsigned long mmr;
+       int irq = IRQ_GRU + chiplet;
+       int ret, core;
+
+       mmr = gru_chiplet_cpu_to_mmr(chiplet, cpu, &core);
+       if (mmr == 0)
+               return 0;
+
+       if (gru_irq_count[chiplet] == 0) {
+               gru_chip[chiplet].name = irq_name;
+               ret = set_irq_chip(irq, &gru_chip[chiplet]);
+               if (ret) {
+                       printk(KERN_ERR "%s: set_irq_chip failed, errno=%d\n",
+                              GRU_DRIVER_ID_STR, -ret);
+                       return ret;
+               }
+
+               ret = request_irq(irq, irq_handler, 0, irq_name, NULL);
+               if (ret) {
+                       printk(KERN_ERR "%s: request_irq failed, errno=%d\n",
+                              GRU_DRIVER_ID_STR, -ret);
+                       return ret;
+               }
+       }
+       gru_irq_count[chiplet]++;
+
+       return 0;
+}
+
+static void gru_chiplet_teardown_tlb_irq(int chiplet, int cpu, int blade)
+{
+       unsigned long mmr;
+       int core, irq = IRQ_GRU + chiplet;
+
+       if (gru_irq_count[chiplet] == 0)
+               return;
+
+       mmr = gru_chiplet_cpu_to_mmr(chiplet, cpu, &core);
+       if (mmr == 0)
+               return;
+
+       if (--gru_irq_count[chiplet] == 0)
+               free_irq(irq, NULL);
+}
+
+#elif defined CONFIG_X86_64
+
+static int gru_chiplet_setup_tlb_irq(int chiplet, char *irq_name,
+                       irq_handler_t irq_handler, int cpu, int blade)
+{
+       unsigned long mmr;
+       int irq, core;
+       int ret;
+
+       mmr = gru_chiplet_cpu_to_mmr(chiplet, cpu, &core);
+       if (mmr == 0)
+               return 0;
+
+       irq = uv_setup_irq(irq_name, cpu, blade, mmr, UV_AFFINITY_CPU);
+       if (irq < 0) {
+               printk(KERN_ERR "%s: uv_setup_irq failed, errno=%d\n",
+                      GRU_DRIVER_ID_STR, -irq);
+               return irq;
+       }
+
+       ret = request_irq(irq, irq_handler, 0, irq_name, NULL);
+       if (ret) {
+               uv_teardown_irq(irq);
+               printk(KERN_ERR "%s: request_irq failed, errno=%d\n",
+                      GRU_DRIVER_ID_STR, -ret);
+               return ret;
+       }
+       gru_base[blade]->bs_grus[chiplet].gs_irq[core] = irq;
+       return 0;
+}
+
+static void gru_chiplet_teardown_tlb_irq(int chiplet, int cpu, int blade)
 {
-       set_irq_chip(IRQ_GRU, &gru_chip);
-       set_irq_chip(IRQ_GRU + 1, &gru_chip);
-       return IRQ_GRU;
+       int irq, core;
+       unsigned long mmr;
+
+       mmr = gru_chiplet_cpu_to_mmr(chiplet, cpu, &core);
+       if (mmr) {
+               irq = gru_base[blade]->bs_grus[chiplet].gs_irq[core];
+               if (irq) {
+                       free_irq(irq, NULL);
+                       uv_teardown_irq(irq);
+               }
+       }
 }
+
 #endif
 
+static void gru_teardown_tlb_irqs(void)
+{
+       int blade;
+       int cpu;
+
+       for_each_online_cpu(cpu) {
+               blade = uv_cpu_to_blade_id(cpu);
+               gru_chiplet_teardown_tlb_irq(0, cpu, blade);
+               gru_chiplet_teardown_tlb_irq(1, cpu, blade);
+       }
+       for_each_possible_blade(blade) {
+               if (uv_blade_nr_possible_cpus(blade))
+                       continue;
+               gru_chiplet_teardown_tlb_irq(0, 0, blade);
+               gru_chiplet_teardown_tlb_irq(1, 0, blade);
+       }
+}
+
+static int gru_setup_tlb_irqs(void)
+{
+       int blade;
+       int cpu;
+       int ret;
+
+       for_each_online_cpu(cpu) {
+               blade = uv_cpu_to_blade_id(cpu);
+               ret = gru_chiplet_setup_tlb_irq(0, "GRU0_TLB", gru0_intr, cpu, blade);
+               if (ret != 0)
+                       goto exit1;
+
+               ret = gru_chiplet_setup_tlb_irq(1, "GRU1_TLB", gru1_intr, cpu, blade);
+               if (ret != 0)
+                       goto exit1;
+       }
+       for_each_possible_blade(blade) {
+               if (uv_blade_nr_possible_cpus(blade))
+                       continue;
+               ret = gru_chiplet_setup_tlb_irq(0, "GRU0_TLB", gru_intr_mblade, 0, blade);
+               if (ret != 0)
+                       goto exit1;
+
+               ret = gru_chiplet_setup_tlb_irq(1, "GRU1_TLB", gru_intr_mblade, 0, blade);
+               if (ret != 0)
+                       goto exit1;
+       }
+
+       return 0;
+
+exit1:
+       gru_teardown_tlb_irqs();
+       return ret;
+}
+
 /*
  * gru_init
  *
@@ -338,8 +516,7 @@ static int get_base_irq(void)
  */
 static int __init gru_init(void)
 {
-       int ret, irq, chip;
-       char id[10];
+       int ret;
 
        if (!is_uv_system())
                return 0;
@@ -354,41 +531,29 @@ static int __init gru_init(void)
        gru_end_paddr = gru_start_paddr + GRU_MAX_BLADES * GRU_SIZE;
        printk(KERN_INFO "GRU space: 0x%lx - 0x%lx\n",
               gru_start_paddr, gru_end_paddr);
-       irq = get_base_irq();
-       for (chip = 0; chip < GRU_CHIPLETS_PER_BLADE; chip++) {
-               ret = request_irq(irq + chip, gru_intr, 0, id, NULL);
-               /* TODO: fix irq handling on x86. For now ignore failure because
-                * interrupts are not required & not yet fully supported */
-               if (ret) {
-                       printk(KERN_WARNING
-                              "!!!WARNING: GRU ignoring request failure!!!\n");
-                       ret = 0;
-               }
-               if (ret) {
-                       printk(KERN_ERR "%s: request_irq failed\n",
-                              GRU_DRIVER_ID_STR);
-                       goto exit1;
-               }
-       }
-
        ret = misc_register(&gru_miscdev);
        if (ret) {
                printk(KERN_ERR "%s: misc_register failed\n",
                       GRU_DRIVER_ID_STR);
-               goto exit1;
+               goto exit0;
        }
 
        ret = gru_proc_init();
        if (ret) {
                printk(KERN_ERR "%s: proc init failed\n", GRU_DRIVER_ID_STR);
-               goto exit2;
+               goto exit1;
        }
 
        ret = gru_init_tables(gru_start_paddr, gru_start_vaddr);
        if (ret) {
                printk(KERN_ERR "%s: init tables failed\n", GRU_DRIVER_ID_STR);
-               goto exit3;
+               goto exit2;
        }
+
+       ret = gru_setup_tlb_irqs();
+       if (ret != 0)
+               goto exit3;
+
        gru_kservices_init();
 
        printk(KERN_INFO "%s: v%s\n", GRU_DRIVER_ID_STR,
@@ -396,31 +561,24 @@ static int __init gru_init(void)
        return 0;
 
 exit3:
-       gru_proc_exit();
+       gru_free_tables();
 exit2:
-       misc_deregister(&gru_miscdev);
+       gru_proc_exit();
 exit1:
-       for (--chip; chip >= 0; chip--)
-               free_irq(irq + chip, NULL);
+       misc_deregister(&gru_miscdev);
+exit0:
        return ret;
 
 }
 
 static void __exit gru_exit(void)
 {
-       int i, bid;
-       int order = get_order(sizeof(struct gru_state) *
-                             GRU_CHIPLETS_PER_BLADE);
-
        if (!is_uv_system())
                return;
 
-       for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++)
-               free_irq(IRQ_GRU + i, NULL);
+       gru_teardown_tlb_irqs();
        gru_kservices_exit();
-       for (bid = 0; bid < GRU_MAX_BLADES; bid++)
-               free_pages((unsigned long)gru_base[bid], order);
-
+       gru_free_tables();
        misc_deregister(&gru_miscdev);
        gru_proc_exit();
 }
index 37e7cfc53b9c3be715f79413af5e07fe98b260d8..2f30badc6ffd9251cd2e59835e3061b2816cd09f 100644 (file)
 #ifdef CONFIG_IA64
 #include <asm/processor.h>
 #define GRU_OPERATION_TIMEOUT  (((cycles_t) local_cpu_data->itc_freq)*10)
+#define CLKS2NSEC(c)           ((c) *1000000000 / local_cpu_data->itc_freq)
 #else
 #include <asm/tsc.h>
 #define GRU_OPERATION_TIMEOUT  ((cycles_t) tsc_khz*10*1000)
+#define CLKS2NSEC(c)           ((c) * 1000000 / tsc_khz)
 #endif
 
 /* Extract the status field from a kernel handle */
@@ -39,21 +41,39 @@ struct mcs_op_statistic mcs_op_statistics[mcsop_last];
 
 static void update_mcs_stats(enum mcs_op op, unsigned long clks)
 {
+       unsigned long nsec;
+
+       nsec = CLKS2NSEC(clks);
        atomic_long_inc(&mcs_op_statistics[op].count);
-       atomic_long_add(clks, &mcs_op_statistics[op].total);
-       if (mcs_op_statistics[op].max < clks)
-               mcs_op_statistics[op].max = clks;
+       atomic_long_add(nsec, &mcs_op_statistics[op].total);
+       if (mcs_op_statistics[op].max < nsec)
+               mcs_op_statistics[op].max = nsec;
 }
 
 static void start_instruction(void *h)
 {
        unsigned long *w0 = h;
 
-       wmb();          /* setting CMD bit must be last */
-       *w0 = *w0 | 1;
+       wmb();          /* setting CMD/STATUS bits must be last */
+       *w0 = *w0 | 0x20001;
        gru_flush_cache(h);
 }
 
+static void report_instruction_timeout(void *h)
+{
+       unsigned long goff = GSEGPOFF((unsigned long)h);
+       char *id = "???";
+
+       if (TYPE_IS(CCH, goff))
+               id = "CCH";
+       else if (TYPE_IS(TGH, goff))
+               id = "TGH";
+       else if (TYPE_IS(TFH, goff))
+               id = "TFH";
+
+       panic(KERN_ALERT "GRU %p (%s) is malfunctioning\n", h, id);
+}
+
 static int wait_instruction_complete(void *h, enum mcs_op opc)
 {
        int status;
@@ -64,9 +84,10 @@ static int wait_instruction_complete(void *h, enum mcs_op opc)
                status = GET_MSEG_HANDLE_STATUS(h);
                if (status != CCHSTATUS_ACTIVE)
                        break;
-               if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time))
-                       panic("GRU %p is malfunctioning: start %ld, end %ld\n",
-                             h, start_time, (unsigned long)get_cycles());
+               if (GRU_OPERATION_TIMEOUT < (get_cycles() - start_time)) {
+                       report_instruction_timeout(h);
+                       start_time = get_cycles();
+               }
        }
        if (gru_options & OPT_STATS)
                update_mcs_stats(opc, get_cycles() - start_time);
@@ -75,9 +96,18 @@ static int wait_instruction_complete(void *h, enum mcs_op opc)
 
 int cch_allocate(struct gru_context_configuration_handle *cch)
 {
+       int ret;
+
        cch->opc = CCHOP_ALLOCATE;
        start_instruction(cch);
-       return wait_instruction_complete(cch, cchop_allocate);
+       ret = wait_instruction_complete(cch, cchop_allocate);
+
+       /*
+        * Stop speculation into the GSEG being mapped by the previous ALLOCATE.
+        * The GSEG memory does not exist until the ALLOCATE completes.
+        */
+       sync_core();
+       return ret;
 }
 
 int cch_start(struct gru_context_configuration_handle *cch)
@@ -96,9 +126,18 @@ int cch_interrupt(struct gru_context_configuration_handle *cch)
 
 int cch_deallocate(struct gru_context_configuration_handle *cch)
 {
+       int ret;
+
        cch->opc = CCHOP_DEALLOCATE;
        start_instruction(cch);
-       return wait_instruction_complete(cch, cchop_deallocate);
+       ret = wait_instruction_complete(cch, cchop_deallocate);
+
+       /*
+        * Stop speculation into the GSEG being unmapped by the previous
+        * DEALLOCATE.
+        */
+       sync_core();
+       return ret;
 }
 
 int cch_interrupt_sync(struct gru_context_configuration_handle
@@ -126,17 +165,20 @@ int tgh_invalidate(struct gru_tlb_global_handle *tgh,
        return wait_instruction_complete(tgh, tghop_invalidate);
 }
 
-void tfh_write_only(struct gru_tlb_fault_handle *tfh,
-                                 unsigned long pfn, unsigned long vaddr,
-                                 int asid, int dirty, int pagesize)
+int tfh_write_only(struct gru_tlb_fault_handle *tfh,
+                                 unsigned long paddr, int gaa,
+                                 unsigned long vaddr, int asid, int dirty,
+                                 int pagesize)
 {
        tfh->fillasid = asid;
        tfh->fillvaddr = vaddr;
-       tfh->pfn = pfn;
+       tfh->pfn = paddr >> GRU_PADDR_SHIFT;
+       tfh->gaa = gaa;
        tfh->dirty = dirty;
        tfh->pagesize = pagesize;
        tfh->opc = TFHOP_WRITE_ONLY;
        start_instruction(tfh);
+       return wait_instruction_complete(tfh, tfhop_write_only);
 }
 
 void tfh_write_restart(struct gru_tlb_fault_handle *tfh,
index f44112242d00f739c5da87822862c3b074c3c20f..3f998b924d8f8cdca04b082a0cade431e63988e8 100644 (file)
 /* Convert an arbitrary handle address to the beginning of the GRU segment */
 #define GRUBASE(h)             ((void *)((unsigned long)(h) & ~(GRU_SIZE - 1)))
 
+/* Test a valid handle address to determine the type */
+#define TYPE_IS(hn, h)         ((h) >= GRU_##hn##_BASE && (h) <        \
+               GRU_##hn##_BASE + GRU_NUM_##hn * GRU_HANDLE_STRIDE &&   \
+               (((h) & (GRU_HANDLE_STRIDE - 1)) == 0))
+
+
 /* General addressing macros. */
 static inline void *get_gseg_base_address(void *base, int ctxnum)
 {
@@ -158,6 +164,16 @@ static inline void *gru_chiplet_vaddr(void *vaddr, int pnode, int chiplet)
        return vaddr + GRU_SIZE * (2 * pnode  + chiplet);
 }
 
+static inline struct gru_control_block_extended *gru_tfh_to_cbe(
+                                       struct gru_tlb_fault_handle *tfh)
+{
+       unsigned long cbe;
+
+       cbe = (unsigned long)tfh - GRU_TFH_BASE + GRU_CBE_BASE;
+       return (struct gru_control_block_extended*)cbe;
+}
+
+
 
 
 /*
@@ -236,6 +252,17 @@ enum gru_tgh_state {
        TGHSTATE_RESTART_CTX,
 };
 
+enum gru_tgh_cause {
+       TGHCAUSE_RR_ECC,
+       TGHCAUSE_TLB_ECC,
+       TGHCAUSE_LRU_ECC,
+       TGHCAUSE_PS_ECC,
+       TGHCAUSE_MUL_ERR,
+       TGHCAUSE_DATA_ERR,
+       TGHCAUSE_SW_FORCE
+};
+
+
 /*
  * TFH - TLB Global Handle
  *     Used for TLB dropins into the GRU TLB.
@@ -440,6 +467,12 @@ struct gru_control_block_extended {
        unsigned int cbrexecstatus:8;
 };
 
+/* CBE fields for active BCOPY instructions */
+#define cbe_baddr0     idef1upd
+#define cbe_baddr1     idef3upd
+#define cbe_src_cl     idef6cpy
+#define cbe_nelemcur   idef5upd
+
 enum gru_cbr_state {
        CBRSTATE_INACTIVE,
        CBRSTATE_IDLE,
@@ -487,8 +520,8 @@ int cch_interrupt_sync(struct gru_context_configuration_handle *cch);
 int tgh_invalidate(struct gru_tlb_global_handle *tgh, unsigned long vaddr,
        unsigned long vaddrmask, int asid, int pagesize, int global, int n,
        unsigned short ctxbitmap);
-void tfh_write_only(struct gru_tlb_fault_handle *tfh, unsigned long pfn,
-       unsigned long vaddr, int asid, int dirty, int pagesize);
+int tfh_write_only(struct gru_tlb_fault_handle *tfh, unsigned long paddr,
+       int gaa, unsigned long vaddr, int asid, int dirty, int pagesize);
 void tfh_write_restart(struct gru_tlb_fault_handle *tfh, unsigned long paddr,
        int gaa, unsigned long vaddr, int asid, int dirty, int pagesize);
 void tfh_restart(struct gru_tlb_fault_handle *tfh);
index 55eabfa85585eb60dd889ec09dc441f187623c7b..9b2062d173279438a92b6f1ba548404fe4c429b0 100644 (file)
@@ -44,7 +44,8 @@ static int gru_user_copy_handle(void __user **dp, void *s)
 
 static int gru_dump_context_data(void *grubase,
                        struct gru_context_configuration_handle *cch,
-                       void __user *ubuf, int ctxnum, int dsrcnt)
+                       void __user *ubuf, int ctxnum, int dsrcnt,
+                       int flush_cbrs)
 {
        void *cb, *cbe, *tfh, *gseg;
        int i, scr;
@@ -55,6 +56,8 @@ static int gru_dump_context_data(void *grubase,
        tfh = grubase + GRU_TFH_BASE;
 
        for_each_cbr_in_allocation_map(i, &cch->cbr_allocation_map, scr) {
+               if (flush_cbrs)
+                       gru_flush_cache(cb);
                if (gru_user_copy_handle(&ubuf, cb))
                        goto fail;
                if (gru_user_copy_handle(&ubuf, tfh + i * GRU_HANDLE_STRIDE))
@@ -115,7 +118,7 @@ fail:
 
 static int gru_dump_context(struct gru_state *gru, int ctxnum,
                void __user *ubuf, void __user *ubufend, char data_opt,
-               char lock_cch)
+               char lock_cch, char flush_cbrs)
 {
        struct gru_dump_context_header hdr;
        struct gru_dump_context_header __user *uhdr = ubuf;
@@ -159,8 +162,7 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum,
                        ret = -EFBIG;
                else
                        ret = gru_dump_context_data(grubase, cch, ubuf, ctxnum,
-                                                       dsrcnt);
-
+                                                       dsrcnt, flush_cbrs);
        }
        if (cch_locked)
                unlock_cch_handle(cch);
@@ -215,7 +217,8 @@ int gru_dump_chiplet_request(unsigned long arg)
        for (ctxnum = 0; ctxnum < GRU_NUM_CCH; ctxnum++) {
                if (req.ctxnum == ctxnum || req.ctxnum < 0) {
                        ret = gru_dump_context(gru, ctxnum, ubuf, ubufend,
-                                               req.data_opt, req.lock_cch);
+                                               req.data_opt, req.lock_cch,
+                                               req.flush_cbrs);
                        if (ret < 0)
                                goto fail;
                        ubuf += ret;
index 766e21e15574c75ceba18828a4d492ac6a90a189..34749ee88dfa8966c7c453aaaf8dcec980206223 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/interrupt.h>
 #include <linux/uaccess.h>
 #include <linux/delay.h>
+#include <asm/io_apic.h>
 #include "gru.h"
 #include "grulib.h"
 #include "grutables.h"
@@ -97,9 +98,6 @@
 #define ASYNC_HAN_TO_BID(h)    ((h) - 1)
 #define ASYNC_BID_TO_HAN(b)    ((b) + 1)
 #define ASYNC_HAN_TO_BS(h)     gru_base[ASYNC_HAN_TO_BID(h)]
-#define KCB_TO_GID(cb)         ((cb - gru_start_vaddr) /               \
-                                       (GRU_SIZE * GRU_CHIPLETS_PER_BLADE))
-#define KCB_TO_BS(cb)          gru_base[KCB_TO_GID(cb)]
 
 #define GRU_NUM_KERNEL_CBR     1
 #define GRU_NUM_KERNEL_DSR_BYTES 256
@@ -160,8 +158,10 @@ static void gru_load_kernel_context(struct gru_blade_state *bs, int blade_id)
        up_read(&bs->bs_kgts_sema);
        down_write(&bs->bs_kgts_sema);
 
-       if (!bs->bs_kgts)
-               bs->bs_kgts = gru_alloc_gts(NULL, 0, 0, 0, 0);
+       if (!bs->bs_kgts) {
+               bs->bs_kgts = gru_alloc_gts(NULL, 0, 0, 0, 0, 0);
+               bs->bs_kgts->ts_user_blade_id = blade_id;
+       }
        kgts = bs->bs_kgts;
 
        if (!kgts->ts_gru) {
@@ -172,9 +172,9 @@ static void gru_load_kernel_context(struct gru_blade_state *bs, int blade_id)
                kgts->ts_dsr_au_count = GRU_DS_BYTES_TO_AU(
                        GRU_NUM_KERNEL_DSR_BYTES * ncpus +
                                bs->bs_async_dsr_bytes);
-               while (!gru_assign_gru_context(kgts, blade_id)) {
+               while (!gru_assign_gru_context(kgts)) {
                        msleep(1);
-                       gru_steal_context(kgts, blade_id);
+                       gru_steal_context(kgts);
                }
                gru_load_context(kgts);
                gru = bs->bs_kgts->ts_gru;
@@ -200,13 +200,15 @@ static int gru_free_kernel_contexts(void)
                bs = gru_base[bid];
                if (!bs)
                        continue;
+
+               /* Ignore busy contexts. Don't want to block here.  */
                if (down_write_trylock(&bs->bs_kgts_sema)) {
                        kgts = bs->bs_kgts;
                        if (kgts && kgts->ts_gru)
                                gru_unload_context(kgts, 0);
-                       kfree(kgts);
                        bs->bs_kgts = NULL;
                        up_write(&bs->bs_kgts_sema);
+                       kfree(kgts);
                } else {
                        ret++;
                }
@@ -220,13 +222,21 @@ static int gru_free_kernel_contexts(void)
 static struct gru_blade_state *gru_lock_kernel_context(int blade_id)
 {
        struct gru_blade_state *bs;
+       int bid;
 
        STAT(lock_kernel_context);
-       bs = gru_base[blade_id];
+again:
+       bid = blade_id < 0 ? uv_numa_blade_id() : blade_id;
+       bs = gru_base[bid];
 
+       /* Handle the case where migration occured while waiting for the sema */
        down_read(&bs->bs_kgts_sema);
+       if (blade_id < 0 && bid != uv_numa_blade_id()) {
+               up_read(&bs->bs_kgts_sema);
+               goto again;
+       }
        if (!bs->bs_kgts || !bs->bs_kgts->ts_gru)
-               gru_load_kernel_context(bs, blade_id);
+               gru_load_kernel_context(bs, bid);
        return bs;
 
 }
@@ -255,7 +265,7 @@ static int gru_get_cpu_resources(int dsr_bytes, void **cb, void **dsr)
 
        BUG_ON(dsr_bytes > GRU_NUM_KERNEL_DSR_BYTES);
        preempt_disable();
-       bs = gru_lock_kernel_context(uv_numa_blade_id());
+       bs = gru_lock_kernel_context(-1);
        lcpu = uv_blade_processor_id();
        *cb = bs->kernel_cb + lcpu * GRU_HANDLE_STRIDE;
        *dsr = bs->kernel_dsr + lcpu * GRU_NUM_KERNEL_DSR_BYTES;
@@ -384,13 +394,31 @@ int gru_get_cb_exception_detail(void *cb,
                struct control_block_extended_exc_detail *excdet)
 {
        struct gru_control_block_extended *cbe;
-       struct gru_blade_state *bs;
-       int cbrnum;
-
-       bs = KCB_TO_BS(cb);
-       cbrnum = thread_cbr_number(bs->bs_kgts, get_cb_number(cb));
+       struct gru_thread_state *kgts = NULL;
+       unsigned long off;
+       int cbrnum, bid;
+
+       /*
+        * Locate kgts for cb. This algorithm is SLOW but
+        * this function is rarely called (ie., almost never).
+        * Performance does not matter.
+        */
+       for_each_possible_blade(bid) {
+               if (!gru_base[bid])
+                       break;
+               kgts = gru_base[bid]->bs_kgts;
+               if (!kgts || !kgts->ts_gru)
+                       continue;
+               off = cb - kgts->ts_gru->gs_gru_base_vaddr;
+               if (off < GRU_SIZE)
+                       break;
+               kgts = NULL;
+       }
+       BUG_ON(!kgts);
+       cbrnum = thread_cbr_number(kgts, get_cb_number(cb));
        cbe = get_cbe(GRUBASE(cb), cbrnum);
        gru_flush_cache(cbe);   /* CBE not coherent */
+       sync_core();
        excdet->opc = cbe->opccpy;
        excdet->exopc = cbe->exopccpy;
        excdet->ecause = cbe->ecause;
@@ -409,8 +437,8 @@ char *gru_get_cb_exception_detail_str(int ret, void *cb,
        if (ret > 0 && gen->istatus == CBS_EXCEPTION) {
                gru_get_cb_exception_detail(cb, &excdet);
                snprintf(buf, size,
-                       "GRU exception: cb %p, opc %d, exopc %d, ecause 0x%x,"
-                       "excdet0 0x%lx, excdet1 0x%x",
+                       "GRU:%d exception: cb %p, opc %d, exopc %d, ecause 0x%x,"
+                       "excdet0 0x%lx, excdet1 0x%x", smp_processor_id(),
                        gen, excdet.opc, excdet.exopc, excdet.ecause,
                        excdet.exceptdet0, excdet.exceptdet1);
        } else {
@@ -457,9 +485,10 @@ int gru_check_status_proc(void *cb)
        int ret;
 
        ret = gen->istatus;
-       if (ret != CBS_EXCEPTION)
-               return ret;
-       return gru_retry_exception(cb);
+       if (ret == CBS_EXCEPTION)
+               ret = gru_retry_exception(cb);
+       rmb();
+       return ret;
 
 }
 
@@ -471,7 +500,7 @@ int gru_wait_proc(void *cb)
        ret = gru_wait_idle_or_exception(gen);
        if (ret == CBS_EXCEPTION)
                ret = gru_retry_exception(cb);
-
+       rmb();
        return ret;
 }
 
@@ -538,7 +567,7 @@ int gru_create_message_queue(struct gru_message_queue_desc *mqd,
        mqd->mq = mq;
        mqd->mq_gpa = uv_gpa(mq);
        mqd->qlines = qlines;
-       mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid);
+       mqd->interrupt_pnode = nasid >> 1;
        mqd->interrupt_vector = vector;
        mqd->interrupt_apicid = apicid;
        return 0;
@@ -598,6 +627,8 @@ static int send_noop_message(void *cb, struct gru_message_queue_desc *mqd,
                                ret = MQE_UNEXPECTED_CB_ERR;
                        break;
                case CBSS_PAGE_OVERFLOW:
+                       STAT(mesq_noop_page_overflow);
+                       /* fallthru */
                default:
                        BUG();
                }
@@ -672,18 +703,6 @@ cberr:
        return MQE_UNEXPECTED_CB_ERR;
 }
 
-/*
- * Send a cross-partition interrupt to the SSI that contains the target
- * message queue. Normally, the interrupt is automatically delivered by hardware
- * but some error conditions require explicit delivery.
- */
-static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd)
-{
-       if (mqd->interrupt_vector)
-               uv_hub_send_ipi(mqd->interrupt_pnode, mqd->interrupt_apicid,
-                               mqd->interrupt_vector);
-}
-
 /*
  * Handle a PUT failure. Note: if message was a 2-line message, one of the
  * lines might have successfully have been written. Before sending the
@@ -693,7 +712,8 @@ static void send_message_queue_interrupt(struct gru_message_queue_desc *mqd)
 static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd,
                        void *mesg, int lines)
 {
-       unsigned long m;
+       unsigned long m, *val = mesg, gpa, save;
+       int ret;
 
        m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6);
        if (lines == 2) {
@@ -704,7 +724,26 @@ static int send_message_put_nacked(void *cb, struct gru_message_queue_desc *mqd,
        gru_vstore(cb, m, gru_get_tri(mesg), XTYPE_CL, lines, 1, IMA);
        if (gru_wait(cb) != CBS_IDLE)
                return MQE_UNEXPECTED_CB_ERR;
-       send_message_queue_interrupt(mqd);
+
+       if (!mqd->interrupt_vector)
+               return MQE_OK;
+
+       /*
+        * Send a cross-partition interrupt to the SSI that contains the target
+        * message queue. Normally, the interrupt is automatically delivered by
+        * hardware but some error conditions require explicit delivery.
+        * Use the GRU to deliver the interrupt. Otherwise partition failures
+        * could cause unrecovered errors.
+        */
+       gpa = uv_global_gru_mmr_address(mqd->interrupt_pnode, UVH_IPI_INT);
+       save = *val;
+       *val = uv_hub_ipi_value(mqd->interrupt_apicid, mqd->interrupt_vector,
+                               dest_Fixed);
+       gru_vstore_phys(cb, gpa, gru_get_tri(mesg), IAA_REGISTER, IMA);
+       ret = gru_wait(cb);
+       *val = save;
+       if (ret != CBS_IDLE)
+               return MQE_UNEXPECTED_CB_ERR;
        return MQE_OK;
 }
 
@@ -739,6 +778,9 @@ static int send_message_failure(void *cb, struct gru_message_queue_desc *mqd,
                STAT(mesq_send_put_nacked);
                ret = send_message_put_nacked(cb, mqd, mesg, lines);
                break;
+       case CBSS_PAGE_OVERFLOW:
+               STAT(mesq_page_overflow);
+               /* fallthru */
        default:
                BUG();
        }
@@ -831,7 +873,6 @@ void *gru_get_next_message(struct gru_message_queue_desc *mqd)
        int present = mhdr->present;
 
        /* skip NOOP messages */
-       STAT(mesq_receive);
        while (present == MQS_NOOP) {
                gru_free_message(mqd, mhdr);
                mhdr = mq->next;
@@ -851,12 +892,36 @@ void *gru_get_next_message(struct gru_message_queue_desc *mqd)
        if (mhdr->lines == 2)
                restore_present2(mhdr, mhdr->present2);
 
+       STAT(mesq_receive);
        return mhdr;
 }
 EXPORT_SYMBOL_GPL(gru_get_next_message);
 
 /* ---------------------- GRU DATA COPY FUNCTIONS ---------------------------*/
 
+/*
+ * Load a DW from a global GPA. The GPA can be a memory or MMR address.
+ */
+int gru_read_gpa(unsigned long *value, unsigned long gpa)
+{
+       void *cb;
+       void *dsr;
+       int ret, iaa;
+
+       STAT(read_gpa);
+       if (gru_get_cpu_resources(GRU_NUM_KERNEL_DSR_BYTES, &cb, &dsr))
+               return MQE_BUG_NO_RESOURCES;
+       iaa = gpa >> 62;
+       gru_vload_phys(cb, gpa, gru_get_tri(dsr), iaa, IMA);
+       ret = gru_wait(cb);
+       if (ret == CBS_IDLE)
+               *value = *(unsigned long *)dsr;
+       gru_free_cpu_resources(cb, dsr);
+       return ret;
+}
+EXPORT_SYMBOL_GPL(gru_read_gpa);
+
+
 /*
  * Copy a block of data using the GRU resources
  */
@@ -898,24 +963,24 @@ static int quicktest0(unsigned long arg)
 
        gru_vload(cb, uv_gpa(&word0), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA);
        if (gru_wait(cb) != CBS_IDLE) {
-               printk(KERN_DEBUG "GRU quicktest0: CBR failure 1\n");
+               printk(KERN_DEBUG "GRU:%d quicktest0: CBR failure 1\n", smp_processor_id());
                goto done;
        }
 
        if (*p != MAGIC) {
-               printk(KERN_DEBUG "GRU: quicktest0 bad magic 0x%lx\n", *p);
+               printk(KERN_DEBUG "GRU:%d quicktest0 bad magic 0x%lx\n", smp_processor_id(), *p);
                goto done;
        }
        gru_vstore(cb, uv_gpa(&word1), gru_get_tri(dsr), XTYPE_DW, 1, 1, IMA);
        if (gru_wait(cb) != CBS_IDLE) {
-               printk(KERN_DEBUG "GRU quicktest0: CBR failure 2\n");
+               printk(KERN_DEBUG "GRU:%d quicktest0: CBR failure 2\n", smp_processor_id());
                goto done;
        }
 
        if (word0 != word1 || word1 != MAGIC) {
                printk(KERN_DEBUG
-                      "GRU quicktest0 err: found 0x%lx, expected 0x%lx\n",
-                    word1, MAGIC);
+                      "GRU:%d quicktest0 err: found 0x%lx, expected 0x%lx\n",
+                    smp_processor_id(), word1, MAGIC);
                goto done;
        }
        ret = 0;
@@ -952,8 +1017,11 @@ static int quicktest1(unsigned long arg)
                if (ret)
                        break;
        }
-       if (ret != MQE_QUEUE_FULL || i != 4)
+       if (ret != MQE_QUEUE_FULL || i != 4) {
+               printk(KERN_DEBUG "GRU:%d quicktest1: unexpect status %d, i %d\n",
+                      smp_processor_id(), ret, i);
                goto done;
+       }
 
        for (i = 0; i < 6; i++) {
                m = gru_get_next_message(&mqd);
@@ -961,7 +1029,12 @@ static int quicktest1(unsigned long arg)
                        break;
                gru_free_message(&mqd, m);
        }
-       ret = (i == 4) ? 0 : -EIO;
+       if (i != 4) {
+               printk(KERN_DEBUG "GRU:%d quicktest2: bad message, i %d, m %p, m8 %d\n",
+                       smp_processor_id(), i, m, m ? m[8] : -1);
+               goto done;
+       }
+       ret = 0;
 
 done:
        kfree(p);
@@ -977,6 +1050,7 @@ static int quicktest2(unsigned long arg)
        int ret = 0;
        unsigned long *buf;
        void *cb0, *cb;
+       struct gru_control_block_status *gen;
        int i, k, istatus, bytes;
 
        bytes = numcb * 4 * 8;
@@ -996,20 +1070,30 @@ static int quicktest2(unsigned long arg)
                                XTYPE_DW, 4, 1, IMA_INTERRUPT);
 
        ret = 0;
-       for (k = 0; k < numcb; k++) {
+       k = numcb;
+       do {
                gru_wait_async_cbr(han);
                for (i = 0; i < numcb; i++) {
                        cb = cb0 + i * GRU_HANDLE_STRIDE;
                        istatus = gru_check_status(cb);
-                       if (istatus == CBS_ACTIVE)
-                               continue;
-                       if (istatus == CBS_EXCEPTION)
-                               ret = -EFAULT;
-                       else if (buf[i] || buf[i + 1] || buf[i + 2] ||
-                                       buf[i + 3])
-                               ret = -EIO;
+                       if (istatus != CBS_ACTIVE && istatus != CBS_CALL_OS)
+                               break;
                }
-       }
+               if (i == numcb)
+                       continue;
+               if (istatus != CBS_IDLE) {
+                       printk(KERN_DEBUG "GRU:%d quicktest2: cb %d, exception\n", smp_processor_id(), i);
+                       ret = -EFAULT;
+               } else if (buf[4 * i] || buf[4 * i + 1] || buf[4 * i + 2] ||
+                               buf[4 * i + 3]) {
+                       printk(KERN_DEBUG "GRU:%d quicktest2:cb %d,  buf 0x%lx, 0x%lx, 0x%lx, 0x%lx\n",
+                              smp_processor_id(), i, buf[4 * i], buf[4 * i + 1], buf[4 * i + 2], buf[4 * i + 3]);
+                       ret = -EIO;
+               }
+               k--;
+               gen = cb;
+               gen->istatus = CBS_CALL_OS; /* don't handle this CBR again */
+       } while (k);
        BUG_ON(cmp.done);
 
        gru_unlock_async_resource(han);
@@ -1019,6 +1103,22 @@ done:
        return ret;
 }
 
+#define BUFSIZE 200
+static int quicktest3(unsigned long arg)
+{
+       char buf1[BUFSIZE], buf2[BUFSIZE];
+       int ret = 0;
+
+       memset(buf2, 0, sizeof(buf2));
+       memset(buf1, get_cycles() & 255, sizeof(buf1));
+       gru_copy_gpa(uv_gpa(buf2), uv_gpa(buf1), BUFSIZE);
+       if (memcmp(buf1, buf2, BUFSIZE)) {
+               printk(KERN_DEBUG "GRU:%d quicktest3 error\n", smp_processor_id());
+               ret = -EIO;
+       }
+       return ret;
+}
+
 /*
  * Debugging only. User hook for various kernel tests
  * of driver & gru.
@@ -1037,6 +1137,9 @@ int gru_ktest(unsigned long arg)
        case 2:
                ret = quicktest2(arg);
                break;
+       case 3:
+               ret = quicktest3(arg);
+               break;
        case 99:
                ret = gru_free_kernel_contexts();
                break;
index d60d34bca44d9ccc66a44c481b4043e041a5e832..02aa94d8484ad8e7ec01aee963d563e216f30fa4 100644 (file)
@@ -130,6 +130,20 @@ extern void gru_free_message(struct gru_message_queue_desc *mqd,
 extern void *gru_get_next_message(struct gru_message_queue_desc *mqd);
 
 
+/*
+ * Read a GRU global GPA. Source can be located in a remote partition.
+ *
+ *    Input:
+ *     value           memory address where MMR value is returned
+ *     gpa             source numalink physical address of GPA
+ *
+ *    Output:
+ *     0               OK
+ *     >0              error
+ */
+int gru_read_gpa(unsigned long *value, unsigned long gpa);
+
+
 /*
  * Copy data using the GRU. Source or destination can be located in a remote
  * partition.
index 889bc442a3e81c8d09791f0e7256935f5378ee2b..e77d1b1f9d0500d6e689c6c945562c40d21802bb 100644 (file)
 #define THREAD_POINTER(p, th)          (p + GRU_GSEG_PAGESIZE * (th))
 #define GSEG_START(cb)                 ((void *)((unsigned long)(cb) & ~(GRU_GSEG_PAGESIZE - 1)))
 
-/*
- * Statictics kept on a per-GTS basis.
- */
-struct gts_statistics {
-       unsigned long   fmm_tlbdropin;
-       unsigned long   upm_tlbdropin;
-       unsigned long   context_stolen;
-};
-
 struct gru_get_gseg_statistics_req {
-       unsigned long           gseg;
-       struct gts_statistics   stats;
+       unsigned long                   gseg;
+       struct gru_gseg_statistics      stats;
 };
 
 /*
@@ -86,6 +77,7 @@ struct gru_create_context_req {
        unsigned int            control_blocks;
        unsigned int            maximum_thread_count;
        unsigned int            options;
+       unsigned char           tlb_preload_count;
 };
 
 /*
@@ -98,11 +90,12 @@ struct gru_unload_context_req {
 /*
  * Structure used to set context options
  */
-enum {sco_gseg_owner, sco_cch_req_slice};
+enum {sco_gseg_owner, sco_cch_req_slice, sco_blade_chiplet};
 struct gru_set_context_option_req {
        unsigned long   gseg;
        int             op;
-       unsigned long   val1;
+       int             val0;
+       long            val1;
 };
 
 /*
@@ -124,6 +117,8 @@ struct gru_dump_chiplet_state_req {
        int             ctxnum;
        char            data_opt;
        char            lock_cch;
+       char            flush_cbrs;
+       char            fill[10];
        pid_t           pid;
        void            *buf;
        size_t          buflen;
index 3bc643dad606aa955788fa866bb6c12a7e315ee5..f8538bbd0bfae72c11128d773f00aadc91f0c1ba 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/sched.h>
 #include <linux/device.h>
 #include <linux/list.h>
+#include <linux/err.h>
 #include <asm/uv/uv_hub.h>
 #include "gru.h"
 #include "grutables.h"
@@ -48,12 +49,20 @@ struct device *grudev = &gru_device;
 /*
  * Select a gru fault map to be used by the current cpu. Note that
  * multiple cpus may be using the same map.
- *     ZZZ should "shift" be used?? Depends on HT cpu numbering
  *     ZZZ should be inline but did not work on emulator
  */
 int gru_cpu_fault_map_id(void)
 {
+#ifdef CONFIG_IA64
        return uv_blade_processor_id() % GRU_NUM_TFM;
+#else
+       int cpu = smp_processor_id();
+       int id, core;
+
+       core = uv_cpu_core_number(cpu);
+       id = core + UV_MAX_INT_CORES * uv_cpu_socket_number(cpu);
+       return id;
+#endif
 }
 
 /*--------- ASID Management -------------------------------------------
@@ -286,7 +295,8 @@ static void gru_unload_mm_tracker(struct gru_state *gru,
 void gts_drop(struct gru_thread_state *gts)
 {
        if (gts && atomic_dec_return(&gts->ts_refcnt) == 0) {
-               gru_drop_mmu_notifier(gts->ts_gms);
+               if (gts->ts_gms)
+                       gru_drop_mmu_notifier(gts->ts_gms);
                kfree(gts);
                STAT(gts_free);
        }
@@ -310,16 +320,18 @@ static struct gru_thread_state *gru_find_current_gts_nolock(struct gru_vma_data
  * Allocate a thread state structure.
  */
 struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma,
-               int cbr_au_count, int dsr_au_count, int options, int tsid)
+               int cbr_au_count, int dsr_au_count,
+               unsigned char tlb_preload_count, int options, int tsid)
 {
        struct gru_thread_state *gts;
+       struct gru_mm_struct *gms;
        int bytes;
 
        bytes = DSR_BYTES(dsr_au_count) + CBR_BYTES(cbr_au_count);
        bytes += sizeof(struct gru_thread_state);
        gts = kmalloc(bytes, GFP_KERNEL);
        if (!gts)
-               return NULL;
+               return ERR_PTR(-ENOMEM);
 
        STAT(gts_alloc);
        memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */
@@ -327,7 +339,10 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma,
        mutex_init(&gts->ts_ctxlock);
        gts->ts_cbr_au_count = cbr_au_count;
        gts->ts_dsr_au_count = dsr_au_count;
+       gts->ts_tlb_preload_count = tlb_preload_count;
        gts->ts_user_options = options;
+       gts->ts_user_blade_id = -1;
+       gts->ts_user_chiplet_id = -1;
        gts->ts_tsid = tsid;
        gts->ts_ctxnum = NULLCTX;
        gts->ts_tlb_int_select = -1;
@@ -336,9 +351,10 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma,
        if (vma) {
                gts->ts_mm = current->mm;
                gts->ts_vma = vma;
-               gts->ts_gms = gru_register_mmu_notifier();
-               if (!gts->ts_gms)
+               gms = gru_register_mmu_notifier();
+               if (IS_ERR(gms))
                        goto err;
+               gts->ts_gms = gms;
        }
 
        gru_dbg(grudev, "alloc gts %p\n", gts);
@@ -346,7 +362,7 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma,
 
 err:
        gts_drop(gts);
-       return NULL;
+       return ERR_CAST(gms);
 }
 
 /*
@@ -360,6 +376,7 @@ struct gru_vma_data *gru_alloc_vma_data(struct vm_area_struct *vma, int tsid)
        if (!vdata)
                return NULL;
 
+       STAT(vdata_alloc);
        INIT_LIST_HEAD(&vdata->vd_head);
        spin_lock_init(&vdata->vd_lock);
        gru_dbg(grudev, "alloc vdata %p\n", vdata);
@@ -392,10 +409,12 @@ struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma,
        struct gru_vma_data *vdata = vma->vm_private_data;
        struct gru_thread_state *gts, *ngts;
 
-       gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, vdata->vd_dsr_au_count,
+       gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count,
+                           vdata->vd_dsr_au_count,
+                           vdata->vd_tlb_preload_count,
                            vdata->vd_user_options, tsid);
-       if (!gts)
-               return NULL;
+       if (IS_ERR(gts))
+               return gts;
 
        spin_lock(&vdata->vd_lock);
        ngts = gru_find_current_gts_nolock(vdata, tsid);
@@ -493,6 +512,9 @@ static void gru_load_context_data(void *save, void *grubase, int ctxnum,
                        memset(cbe + i * GRU_HANDLE_STRIDE, 0,
                                                GRU_CACHE_LINE_BYTES);
                }
+               /* Flush CBE to hide race in context restart */
+               mb();
+               gru_flush_cache(cbe + i * GRU_HANDLE_STRIDE);
                cb += GRU_HANDLE_STRIDE;
        }
 
@@ -513,6 +535,12 @@ static void gru_unload_context_data(void *save, void *grubase, int ctxnum,
        cb = gseg + GRU_CB_BASE;
        cbe = grubase + GRU_CBE_BASE;
        length = hweight64(dsrmap) * GRU_DSR_AU_BYTES;
+
+       /* CBEs may not be coherent. Flush them from cache */
+       for_each_cbr_in_allocation_map(i, &cbrmap, scr)
+               gru_flush_cache(cbe + i * GRU_HANDLE_STRIDE);
+       mb();           /* Let the CL flush complete */
+
        gru_prefetch_context(gseg, cb, cbe, cbrmap, length);
 
        for_each_cbr_in_allocation_map(i, &cbrmap, scr) {
@@ -533,7 +561,8 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate)
                zap_vma_ptes(gts->ts_vma, UGRUADDR(gts), GRU_GSEG_PAGESIZE);
        cch = get_cch(gru->gs_gru_base_vaddr, ctxnum);
 
-       gru_dbg(grudev, "gts %p\n", gts);
+       gru_dbg(grudev, "gts %p, cbrmap 0x%lx, dsrmap 0x%lx\n",
+               gts, gts->ts_cbr_map, gts->ts_dsr_map);
        lock_cch_handle(cch);
        if (cch_interrupt_sync(cch))
                BUG();
@@ -549,7 +578,6 @@ void gru_unload_context(struct gru_thread_state *gts, int savestate)
 
        if (cch_deallocate(cch))
                BUG();
-       gts->ts_force_unload = 0;       /* ts_force_unload locked by CCH lock */
        unlock_cch_handle(cch);
 
        gru_free_gru_context(gts);
@@ -565,9 +593,7 @@ void gru_load_context(struct gru_thread_state *gts)
        struct gru_context_configuration_handle *cch;
        int i, err, asid, ctxnum = gts->ts_ctxnum;
 
-       gru_dbg(grudev, "gts %p\n", gts);
        cch = get_cch(gru->gs_gru_base_vaddr, ctxnum);
-
        lock_cch_handle(cch);
        cch->tfm_fault_bit_enable =
            (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL
@@ -591,6 +617,7 @@ void gru_load_context(struct gru_thread_state *gts)
                cch->unmap_enable = 1;
                cch->tfm_done_bit_enable = 1;
                cch->cb_int_enable = 1;
+               cch->tlb_int_select = 0;        /* For now, ints go to cpu 0 */
        } else {
                cch->unmap_enable = 0;
                cch->tfm_done_bit_enable = 0;
@@ -616,17 +643,18 @@ void gru_load_context(struct gru_thread_state *gts)
        if (cch_start(cch))
                BUG();
        unlock_cch_handle(cch);
+
+       gru_dbg(grudev, "gid %d, gts %p, cbrmap 0x%lx, dsrmap 0x%lx, tie %d, tis %d\n",
+               gts->ts_gru->gs_gid, gts, gts->ts_cbr_map, gts->ts_dsr_map,
+               (gts->ts_user_options == GRU_OPT_MISS_FMM_INTR), gts->ts_tlb_int_select);
 }
 
 /*
  * Update fields in an active CCH:
  *     - retarget interrupts on local blade
  *     - update sizeavail mask
- *     - force a delayed context unload by clearing the CCH asids. This
- *       forces TLB misses for new GRU instructions. The context is unloaded
- *       when the next TLB miss occurs.
  */
-int gru_update_cch(struct gru_thread_state *gts, int force_unload)
+int gru_update_cch(struct gru_thread_state *gts)
 {
        struct gru_context_configuration_handle *cch;
        struct gru_state *gru = gts->ts_gru;
@@ -640,21 +668,13 @@ int gru_update_cch(struct gru_thread_state *gts, int force_unload)
                        goto exit;
                if (cch_interrupt(cch))
                        BUG();
-               if (!force_unload) {
-                       for (i = 0; i < 8; i++)
-                               cch->sizeavail[i] = gts->ts_sizeavail;
-                       gts->ts_tlb_int_select = gru_cpu_fault_map_id();
-                       cch->tlb_int_select = gru_cpu_fault_map_id();
-                       cch->tfm_fault_bit_enable =
-                         (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL
-                           || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR);
-               } else {
-                       for (i = 0; i < 8; i++)
-                               cch->asid[i] = 0;
-                       cch->tfm_fault_bit_enable = 0;
-                       cch->tlb_int_enable = 0;
-                       gts->ts_force_unload = 1;
-               }
+               for (i = 0; i < 8; i++)
+                       cch->sizeavail[i] = gts->ts_sizeavail;
+               gts->ts_tlb_int_select = gru_cpu_fault_map_id();
+               cch->tlb_int_select = gru_cpu_fault_map_id();
+               cch->tfm_fault_bit_enable =
+                 (gts->ts_user_options == GRU_OPT_MISS_FMM_POLL
+                   || gts->ts_user_options == GRU_OPT_MISS_FMM_INTR);
                if (cch_start(cch))
                        BUG();
                ret = 1;
@@ -679,7 +699,54 @@ static int gru_retarget_intr(struct gru_thread_state *gts)
 
        gru_dbg(grudev, "retarget from %d to %d\n", gts->ts_tlb_int_select,
                gru_cpu_fault_map_id());
-       return gru_update_cch(gts, 0);
+       return gru_update_cch(gts);
+}
+
+/*
+ * Check if a GRU context is allowed to use a specific chiplet. By default
+ * a context is assigned to any blade-local chiplet. However, users can
+ * override this.
+ *     Returns 1 if assignment allowed, 0 otherwise
+ */
+static int gru_check_chiplet_assignment(struct gru_state *gru,
+                                       struct gru_thread_state *gts)
+{
+       int blade_id;
+       int chiplet_id;
+
+       blade_id = gts->ts_user_blade_id;
+       if (blade_id < 0)
+               blade_id = uv_numa_blade_id();
+
+       chiplet_id = gts->ts_user_chiplet_id;
+       return gru->gs_blade_id == blade_id &&
+               (chiplet_id < 0 || chiplet_id == gru->gs_chiplet_id);
+}
+
+/*
+ * Unload the gru context if it is not assigned to the correct blade or
+ * chiplet. Misassignment can occur if the process migrates to a different
+ * blade or if the user changes the selected blade/chiplet.
+ */
+void gru_check_context_placement(struct gru_thread_state *gts)
+{
+       struct gru_state *gru;
+
+       /*
+        * If the current task is the context owner, verify that the
+        * context is correctly placed. This test is skipped for non-owner
+        * references. Pthread apps use non-owner references to the CBRs.
+        */
+       gru = gts->ts_gru;
+       if (!gru || gts->ts_tgid_owner != current->tgid)
+               return;
+
+       if (!gru_check_chiplet_assignment(gru, gts)) {
+               STAT(check_context_unload);
+               gru_unload_context(gts, 1);
+       } else if (gru_retarget_intr(gts)) {
+               STAT(check_context_retarget_intr);
+       }
 }
 
 
@@ -712,13 +779,17 @@ static void gts_stolen(struct gru_thread_state *gts,
        }
 }
 
-void gru_steal_context(struct gru_thread_state *gts, int blade_id)
+void gru_steal_context(struct gru_thread_state *gts)
 {
        struct gru_blade_state *blade;
        struct gru_state *gru, *gru0;
        struct gru_thread_state *ngts = NULL;
        int ctxnum, ctxnum0, flag = 0, cbr, dsr;
+       int blade_id;
 
+       blade_id = gts->ts_user_blade_id;
+       if (blade_id < 0)
+               blade_id = uv_numa_blade_id();
        cbr = gts->ts_cbr_au_count;
        dsr = gts->ts_dsr_au_count;
 
@@ -729,35 +800,39 @@ void gru_steal_context(struct gru_thread_state *gts, int blade_id)
        gru = blade->bs_lru_gru;
        if (ctxnum == 0)
                gru = next_gru(blade, gru);
+       blade->bs_lru_gru = gru;
+       blade->bs_lru_ctxnum = ctxnum;
        ctxnum0 = ctxnum;
        gru0 = gru;
        while (1) {
-               if (check_gru_resources(gru, cbr, dsr, GRU_NUM_CCH))
-                       break;
-               spin_lock(&gru->gs_lock);
-               for (; ctxnum < GRU_NUM_CCH; ctxnum++) {
-                       if (flag && gru == gru0 && ctxnum == ctxnum0)
+               if (gru_check_chiplet_assignment(gru, gts)) {
+                       if (check_gru_resources(gru, cbr, dsr, GRU_NUM_CCH))
                                break;
-                       ngts = gru->gs_gts[ctxnum];
-                       /*
-                        * We are grabbing locks out of order, so trylock is
-                        * needed. GTSs are usually not locked, so the odds of
-                        * success are high. If trylock fails, try to steal a
-                        * different GSEG.
-                        */
-                       if (ngts && is_gts_stealable(ngts, blade))
+                       spin_lock(&gru->gs_lock);
+                       for (; ctxnum < GRU_NUM_CCH; ctxnum++) {
+                               if (flag && gru == gru0 && ctxnum == ctxnum0)
+                                       break;
+                               ngts = gru->gs_gts[ctxnum];
+                               /*
+                               * We are grabbing locks out of order, so trylock is
+                               * needed. GTSs are usually not locked, so the odds of
+                               * success are high. If trylock fails, try to steal a
+                               * different GSEG.
+                               */
+                               if (ngts && is_gts_stealable(ngts, blade))
+                                       break;
+                               ngts = NULL;
+                       }
+                       spin_unlock(&gru->gs_lock);
+                       if (ngts || (flag && gru == gru0 && ctxnum == ctxnum0))
                                break;
-                       ngts = NULL;
-                       flag = 1;
                }
-               spin_unlock(&gru->gs_lock);
-               if (ngts || (flag && gru == gru0 && ctxnum == ctxnum0))
+               if (flag && gru == gru0)
                        break;
+               flag = 1;
                ctxnum = 0;
                gru = next_gru(blade, gru);
        }
-       blade->bs_lru_gru = gru;
-       blade->bs_lru_ctxnum = ctxnum;
        spin_unlock(&blade->bs_lock);
 
        if (ngts) {
@@ -775,20 +850,35 @@ void gru_steal_context(struct gru_thread_state *gts, int blade_id)
                hweight64(gru->gs_dsr_map));
 }
 
+/*
+ * Assign a gru context.
+ */
+static int gru_assign_context_number(struct gru_state *gru)
+{
+       int ctxnum;
+
+       ctxnum = find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH);
+       __set_bit(ctxnum, &gru->gs_context_map);
+       return ctxnum;
+}
+
 /*
  * Scan the GRUs on the local blade & assign a GRU context.
  */
-struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts,
-                                               int blade)
+struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts)
 {
        struct gru_state *gru, *grux;
        int i, max_active_contexts;
+       int blade_id = gts->ts_user_blade_id;
 
-
+       if (blade_id < 0)
+               blade_id = uv_numa_blade_id();
 again:
        gru = NULL;
        max_active_contexts = GRU_NUM_CCH;
-       for_each_gru_on_blade(grux, blade, i) {
+       for_each_gru_on_blade(grux, blade_id, i) {
+               if (!gru_check_chiplet_assignment(grux, gts))
+                       continue;
                if (check_gru_resources(grux, gts->ts_cbr_au_count,
                                        gts->ts_dsr_au_count,
                                        max_active_contexts)) {
@@ -809,12 +899,9 @@ again:
                reserve_gru_resources(gru, gts);
                gts->ts_gru = gru;
                gts->ts_blade = gru->gs_blade_id;
-               gts->ts_ctxnum =
-                   find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH);
-               BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH);
+               gts->ts_ctxnum = gru_assign_context_number(gru);
                atomic_inc(&gts->ts_refcnt);
                gru->gs_gts[gts->ts_ctxnum] = gts;
-               __set_bit(gts->ts_ctxnum, &gru->gs_context_map);
                spin_unlock(&gru->gs_lock);
 
                STAT(assign_context);
@@ -842,7 +929,6 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct gru_thread_state *gts;
        unsigned long paddr, vaddr;
-       int blade_id;
 
        vaddr = (unsigned long)vmf->virtual_address;
        gru_dbg(grudev, "vma %p, vaddr 0x%lx (0x%lx)\n",
@@ -857,28 +943,18 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 again:
        mutex_lock(&gts->ts_ctxlock);
        preempt_disable();
-       blade_id = uv_numa_blade_id();
 
-       if (gts->ts_gru) {
-               if (gts->ts_gru->gs_blade_id != blade_id) {
-                       STAT(migrated_nopfn_unload);
-                       gru_unload_context(gts, 1);
-               } else {
-                       if (gru_retarget_intr(gts))
-                               STAT(migrated_nopfn_retarget);
-               }
-       }
+       gru_check_context_placement(gts);
 
        if (!gts->ts_gru) {
                STAT(load_user_context);
-               if (!gru_assign_gru_context(gts, blade_id)) {
+               if (!gru_assign_gru_context(gts)) {
                        preempt_enable();
                        mutex_unlock(&gts->ts_ctxlock);
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule_timeout(GRU_ASSIGN_DELAY);  /* true hack ZZZ */
-                       blade_id = uv_numa_blade_id();
                        if (gts->ts_steal_jiffies + GRU_STEAL_DELAY < jiffies)
-                               gru_steal_context(gts, blade_id);
+                               gru_steal_context(gts);
                        goto again;
                }
                gru_load_context(gts);
index 3f2375c5ba5bd3a98ef37f6e628474d507188197..7768b87d995be6888b0b540f3cee7344546d25ea 100644 (file)
@@ -36,8 +36,7 @@ static void printstat_val(struct seq_file *s, atomic_long_t *v, char *id)
 {
        unsigned long val = atomic_long_read(v);
 
-       if (val)
-               seq_printf(s, "%16lu %s\n", val, id);
+       seq_printf(s, "%16lu %s\n", val, id);
 }
 
 static int statistics_show(struct seq_file *s, void *p)
@@ -46,7 +45,8 @@ static int statistics_show(struct seq_file *s, void *p)
        printstat(s, vdata_free);
        printstat(s, gts_alloc);
        printstat(s, gts_free);
-       printstat(s, vdata_double_alloc);
+       printstat(s, gms_alloc);
+       printstat(s, gms_free);
        printstat(s, gts_double_allocate);
        printstat(s, assign_context);
        printstat(s, assign_context_failed);
@@ -59,28 +59,25 @@ static int statistics_show(struct seq_file *s, void *p)
        printstat(s, steal_kernel_context);
        printstat(s, steal_context_failed);
        printstat(s, nopfn);
-       printstat(s, break_cow);
        printstat(s, asid_new);
        printstat(s, asid_next);
        printstat(s, asid_wrap);
        printstat(s, asid_reuse);
        printstat(s, intr);
+       printstat(s, intr_cbr);
+       printstat(s, intr_tfh);
+       printstat(s, intr_spurious);
        printstat(s, intr_mm_lock_failed);
        printstat(s, call_os);
-       printstat(s, call_os_offnode_reference);
-       printstat(s, call_os_check_for_bug);
        printstat(s, call_os_wait_queue);
        printstat(s, user_flush_tlb);
        printstat(s, user_unload_context);
        printstat(s, user_exception);
        printstat(s, set_context_option);
-       printstat(s, migrate_check);
-       printstat(s, migrated_retarget);
-       printstat(s, migrated_unload);
-       printstat(s, migrated_unload_delay);
-       printstat(s, migrated_nopfn_retarget);
-       printstat(s, migrated_nopfn_unload);
+       printstat(s, check_context_retarget_intr);
+       printstat(s, check_context_unload);
        printstat(s, tlb_dropin);
+       printstat(s, tlb_preload_page);
        printstat(s, tlb_dropin_fail_no_asid);
        printstat(s, tlb_dropin_fail_upm);
        printstat(s, tlb_dropin_fail_invalid);
@@ -88,16 +85,15 @@ static int statistics_show(struct seq_file *s, void *p)
        printstat(s, tlb_dropin_fail_idle);
        printstat(s, tlb_dropin_fail_fmm);
        printstat(s, tlb_dropin_fail_no_exception);
-       printstat(s, tlb_dropin_fail_no_exception_war);
        printstat(s, tfh_stale_on_fault);
        printstat(s, mmu_invalidate_range);
        printstat(s, mmu_invalidate_page);
-       printstat(s, mmu_clear_flush_young);
        printstat(s, flush_tlb);
        printstat(s, flush_tlb_gru);
        printstat(s, flush_tlb_gru_tgh);
        printstat(s, flush_tlb_gru_zero_asid);
        printstat(s, copy_gpa);
+       printstat(s, read_gpa);
        printstat(s, mesq_receive);
        printstat(s, mesq_receive_none);
        printstat(s, mesq_send);
@@ -108,7 +104,6 @@ static int statistics_show(struct seq_file *s, void *p)
        printstat(s, mesq_send_qlimit_reached);
        printstat(s, mesq_send_amo_nacked);
        printstat(s, mesq_send_put_nacked);
-       printstat(s, mesq_qf_not_full);
        printstat(s, mesq_qf_locked);
        printstat(s, mesq_qf_noop_not_full);
        printstat(s, mesq_qf_switch_head_failed);
@@ -118,6 +113,7 @@ static int statistics_show(struct seq_file *s, void *p)
        printstat(s, mesq_noop_qlimit_reached);
        printstat(s, mesq_noop_amo_nacked);
        printstat(s, mesq_noop_put_nacked);
+       printstat(s, mesq_noop_page_overflow);
        return 0;
 }
 
@@ -133,8 +129,10 @@ static int mcs_statistics_show(struct seq_file *s, void *p)
        int op;
        unsigned long total, count, max;
        static char *id[] = {"cch_allocate", "cch_start", "cch_interrupt",
-               "cch_interrupt_sync", "cch_deallocate", "tgh_invalidate"};
+               "cch_interrupt_sync", "cch_deallocate", "tfh_write_only",
+               "tfh_write_restart", "tgh_invalidate"};
 
+       seq_printf(s, "%-20s%12s%12s%12s\n", "#id", "count", "aver-clks", "max-clks");
        for (op = 0; op < mcsop_last; op++) {
                count = atomic_long_read(&mcs_op_statistics[op].count);
                total = atomic_long_read(&mcs_op_statistics[op].total);
@@ -154,6 +152,7 @@ static ssize_t mcs_statistics_write(struct file *file,
 
 static int options_show(struct seq_file *s, void *p)
 {
+       seq_printf(s, "#bitmask: 1=trace, 2=statistics\n");
        seq_printf(s, "0x%lx\n", gru_options);
        return 0;
 }
@@ -183,16 +182,17 @@ static int cch_seq_show(struct seq_file *file, void *data)
        const char *mode[] = { "??", "UPM", "INTR", "OS_POLL" };
 
        if (gid == 0)
-               seq_printf(file, "#%5s%5s%6s%9s%6s%8s%8s\n", "gid", "bid",
-                          "ctx#", "pid", "cbrs", "dsbytes", "mode");
+               seq_printf(file, "#%5s%5s%6s%7s%9s%6s%8s%8s\n", "gid", "bid",
+                          "ctx#", "asid", "pid", "cbrs", "dsbytes", "mode");
        if (gru)
                for (i = 0; i < GRU_NUM_CCH; i++) {
                        ts = gru->gs_gts[i];
                        if (!ts)
                                continue;
-                       seq_printf(file, " %5d%5d%6d%9d%6d%8d%8s\n",
+                       seq_printf(file, " %5d%5d%6d%7d%9d%6d%8d%8s\n",
                                   gru->gs_gid, gru->gs_blade_id, i,
-                                  ts->ts_tgid_owner,
+                                  is_kernel_context(ts) ? 0 : ts->ts_gms->ms_asids[gid].mt_asid,
+                                  is_kernel_context(ts) ? 0 : ts->ts_tgid_owner,
                                   ts->ts_cbr_au_count * GRU_CBR_AU_SIZE,
                                   ts->ts_cbr_au_count * GRU_DSR_AU_BYTES,
                                   mode[ts->ts_user_options &
@@ -355,7 +355,7 @@ static void delete_proc_files(void)
                for (p = proc_files; p->name; p++)
                        if (p->entry)
                                remove_proc_entry(p->name, proc_gru);
-               remove_proc_entry("gru", NULL);
+               remove_proc_entry("gru", proc_gru->parent);
        }
 }
 
index 46990bcfa5369a541719cfcde7d0532aedaaca8c..02a77b8b8eef36c59117742c8970083b9d382ea9 100644 (file)
@@ -161,7 +161,7 @@ extern unsigned int gru_max_gids;
 #define GRU_MAX_GRUS          &