From 30bab60548833312cf65e4c2b4a164bdd5cc5d78 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 5 Dec 2009 01:19:47 -0300 Subject: [PATCH] --- yaml --- r: 176764 b: refs/heads/master c: d30a3fe89635324397c9cf5802f18f11a49ace17 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/Documentation/DocBook/Makefile | 17 +- trunk/Documentation/DocBook/procfs-guide.tmpl | 626 +++++++++++++ trunk/Documentation/DocBook/procfs_example.c | 201 +++++ trunk/Documentation/SubmitChecklist | 5 +- trunk/Documentation/fb/viafb.txt | 12 +- trunk/Documentation/filesystems/seq_file.txt | 4 +- trunk/Documentation/gpio.txt | 15 - trunk/Documentation/kernel-parameters.txt | 5 - trunk/arch/alpha/include/asm/elf.h | 1 + trunk/arch/arm/include/asm/elf.h | 1 + trunk/arch/arm/mach-davinci/board-da850-evm.c | 24 +- trunk/arch/avr32/include/asm/elf.h | 1 + .../arch/blackfin/include/asm/bfin-lq035q1.h | 28 - trunk/arch/blackfin/include/asm/elf.h | 1 + trunk/arch/cris/include/asm/elf.h | 2 + trunk/arch/frv/include/asm/elf.h | 1 + trunk/arch/h8300/include/asm/elf.h | 1 + trunk/arch/ia64/ia32/elfcore32.h | 2 + trunk/arch/ia64/include/asm/dma-mapping.h | 2 +- trunk/arch/ia64/include/asm/elf.h | 1 + trunk/arch/ia64/sn/pci/tioca_provider.c | 19 +- trunk/arch/m32r/include/asm/elf.h | 1 + trunk/arch/m68k/include/asm/elf.h | 1 + trunk/arch/microblaze/include/asm/elf.h | 1 + trunk/arch/mips/include/asm/elf.h | 1 + trunk/arch/mn10300/include/asm/elf.h | 1 + trunk/arch/parisc/include/asm/elf.h | 1 + trunk/arch/powerpc/include/asm/dma-mapping.h | 2 +- trunk/arch/powerpc/include/asm/elf.h | 1 + trunk/arch/powerpc/include/asm/ptrace.h | 2 - trunk/arch/powerpc/kernel/iommu.c | 4 +- trunk/arch/powerpc/kernel/traps.c | 9 - trunk/arch/s390/include/asm/elf.h | 1 + trunk/arch/score/include/asm/elf.h | 1 + trunk/arch/sh/include/asm/elf.h | 1 + trunk/arch/sparc/include/asm/elf_32.h | 2 + trunk/arch/sparc/include/asm/elf_64.h | 1 + trunk/arch/sparc/kernel/iommu.c | 3 +- trunk/arch/sparc/kernel/ldc.c | 16 +- trunk/arch/sparc/mm/sun4c.c | 17 +- trunk/arch/um/sys-i386/asm/elf.h | 1 + trunk/arch/um/sys-ppc/asm/elf.h | 2 + trunk/arch/um/sys-x86_64/asm/elf.h | 1 + trunk/arch/x86/include/asm/dma-mapping.h | 2 +- trunk/arch/x86/include/asm/elf.h | 1 + trunk/arch/x86/include/asm/ptrace.h | 2 - trunk/arch/x86/include/asm/uv/bios.h | 11 +- trunk/arch/x86/include/asm/uv/uv_hub.h | 44 +- trunk/arch/x86/kernel/amd_iommu.c | 4 +- trunk/arch/x86/kernel/bios_uv.c | 8 +- trunk/arch/x86/kernel/pci-calgary_64.c | 6 +- trunk/arch/x86/kernel/pci-gart_64.c | 6 +- trunk/arch/x86/kernel/ptrace.c | 51 +- trunk/arch/xtensa/include/asm/elf.h | 1 + trunk/drivers/char/efirtc.c | 1 - trunk/drivers/char/ipmi/ipmi_kcs_sm.c | 2 +- trunk/drivers/char/sysrq.c | 2 +- trunk/drivers/char/vt.c | 7 +- trunk/drivers/edac/i5100_edac.c | 252 ++---- trunk/drivers/gpio/Kconfig | 6 - trunk/drivers/gpio/Makefile | 1 - trunk/drivers/gpio/gpiolib.c | 161 +--- trunk/drivers/gpio/langwell_gpio.c | 2 +- trunk/drivers/gpio/timbgpio.c | 342 -------- trunk/drivers/misc/sgi-gru/gru.h | 11 - trunk/drivers/misc/sgi-gru/gru_instructions.h | 144 ++- trunk/drivers/misc/sgi-gru/grufault.c | 311 ++----- trunk/drivers/misc/sgi-gru/grufile.c | 290 ++---- trunk/drivers/misc/sgi-gru/gruhandles.c | 70 +- trunk/drivers/misc/sgi-gru/gruhandles.h | 37 +- trunk/drivers/misc/sgi-gru/grukdump.c | 13 +- trunk/drivers/misc/sgi-gru/grukservices.c | 211 ++--- trunk/drivers/misc/sgi-gru/grukservices.h | 14 - trunk/drivers/misc/sgi-gru/grulib.h | 21 +- trunk/drivers/misc/sgi-gru/grumain.c | 228 ++--- trunk/drivers/misc/sgi-gru/gruprocfs.c | 42 +- trunk/drivers/misc/sgi-gru/grutables.h | 75 +- trunk/drivers/misc/sgi-gru/grutlbpurge.c | 14 +- trunk/drivers/misc/sgi-xp/xp.h | 1 - trunk/drivers/misc/sgi-xp/xp_main.c | 3 - trunk/drivers/misc/sgi-xp/xp_sn2.c | 10 - trunk/drivers/misc/sgi-xp/xp_uv.c | 33 - trunk/drivers/misc/sgi-xp/xpc_partition.c | 13 +- trunk/drivers/misc/sgi-xp/xpc_uv.c | 46 +- trunk/drivers/net/mlx4/alloc.c | 37 +- trunk/drivers/parport/parport_pc.c | 2 +- trunk/drivers/pnp/pnpbios/proc.c | 204 ++--- trunk/drivers/rtc/Kconfig | 28 +- trunk/drivers/rtc/Makefile | 3 - trunk/drivers/rtc/rtc-at32ap700x.c | 4 +- trunk/drivers/rtc/rtc-bq32k.c | 204 ----- trunk/drivers/rtc/rtc-bq4802.c | 3 +- trunk/drivers/rtc/rtc-cmos.c | 78 +- trunk/drivers/rtc/rtc-ds1302.c | 1 + trunk/drivers/rtc/rtc-ds1305.c | 14 +- trunk/drivers/rtc/rtc-ds1307.c | 2 +- trunk/drivers/rtc/rtc-ds1511.c | 148 ++-- trunk/drivers/rtc/rtc-ds1553.c | 149 ++-- trunk/drivers/rtc/rtc-ds1742.c | 59 +- trunk/drivers/rtc/rtc-m48t35.c | 16 +- trunk/drivers/rtc/rtc-m48t59.c | 11 +- trunk/drivers/rtc/rtc-mc13783.c | 262 ------ trunk/drivers/rtc/rtc-mv.c | 157 +--- trunk/drivers/rtc/rtc-nuc900.c | 342 -------- trunk/drivers/rtc/rtc-omap.c | 47 +- trunk/drivers/rtc/rtc-pcf50633.c | 5 - trunk/drivers/rtc/rtc-pcf8563.c | 4 +- trunk/drivers/rtc/rtc-pcf8583.c | 3 +- trunk/drivers/rtc/rtc-pl031.c | 23 +- trunk/drivers/rtc/rtc-stk17ta8.c | 124 +-- trunk/drivers/rtc/rtc-tx4939.c | 51 +- trunk/drivers/rtc/rtc-v3020.c | 8 +- trunk/drivers/rtc/rtc-vr41xx.c | 4 +- trunk/drivers/rtc/rtc-wm8350.c | 14 +- trunk/drivers/rtc/rtc-x1205.c | 53 +- trunk/drivers/usb/host/isp1362-hcd.c | 26 +- trunk/drivers/video/Kconfig | 15 - trunk/drivers/video/Makefile | 1 - trunk/drivers/video/atafb.c | 3 - trunk/drivers/video/bfin-lq035q1-fb.c | 826 ------------------ trunk/drivers/video/bfin-t350mcqb-fb.c | 32 +- trunk/drivers/video/clps711xfb.c | 50 +- trunk/drivers/video/da8xx-fb.c | 175 +--- trunk/drivers/video/ep93xx-fb.c | 2 - trunk/drivers/video/geode/lxfb.h | 10 - trunk/drivers/video/i810/i810_dvt.c | 53 +- trunk/drivers/video/intelfb/intelfbdrv.c | 3 - trunk/drivers/video/intelfb/intelfbhw.c | 47 +- trunk/drivers/video/intelfb/intelfbhw.h | 1 - trunk/drivers/video/matrox/g450_pll.c | 3 +- trunk/drivers/video/maxinefb.c | 3 - trunk/drivers/video/mb862xx/Makefile | 2 +- trunk/drivers/video/mb862xx/mb862xxfb.c | 14 - trunk/drivers/video/mb862xx/mb862xxfb.h | 2 - trunk/drivers/video/mb862xx/mb862xxfb_accel.c | 331 ------- trunk/drivers/video/mb862xx/mb862xxfb_accel.h | 203 ----- trunk/drivers/video/modedb.c | 24 +- trunk/drivers/video/pmag-ba-fb.c | 3 +- trunk/drivers/video/pmagb-b-fb.c | 3 +- trunk/drivers/video/pxafb.c | 5 +- trunk/drivers/video/sis/sis_main.c | 2 +- trunk/drivers/video/sm501fb.c | 249 +----- trunk/drivers/video/via/lcd.c | 40 +- trunk/drivers/video/via/viafbdev.c | 2 +- trunk/fs/aio.c | 40 +- trunk/fs/autofs4/autofs_i.h | 38 +- trunk/fs/autofs4/expire.c | 8 +- trunk/fs/autofs4/inode.c | 2 - trunk/fs/autofs4/root.c | 616 +++++-------- trunk/fs/binfmt_elf.c | 11 +- trunk/fs/binfmt_elf_fdpic.c | 8 +- trunk/fs/direct-io.c | 165 ++-- trunk/fs/ext2/dir.c | 2 +- trunk/fs/ext2/ext2.h | 1 - trunk/fs/ext2/file.c | 21 +- trunk/fs/ext2/super.c | 22 - trunk/fs/fat/misc.c | 57 +- trunk/fs/fscache/object-list.c | 2 +- trunk/fs/hpfs/super.c | 17 +- trunk/fs/ocfs2/aops.c | 34 +- trunk/fs/proc/base.c | 4 +- trunk/fs/proc/generic.c | 21 +- trunk/fs/proc/inode.c | 31 +- trunk/fs/proc/internal.h | 10 +- trunk/fs/qnx4/bitmap.c | 24 +- trunk/fs/qnx4/inode.c | 22 +- trunk/fs/reiserfs/Makefile | 6 +- trunk/fs/reiserfs/procfs.c | 65 ++ trunk/fs/reiserfs/super.c | 4 + trunk/fs/ufs/dir.c | 10 +- trunk/fs/ufs/namei.c | 8 +- trunk/fs/ufs/super.c | 52 -- trunk/fs/ufs/ufs.h | 4 +- trunk/fs/xfs/linux-2.6/xfs_aops.c | 20 +- trunk/include/asm-generic/gpio.h | 6 - trunk/include/linux/aio.h | 4 + trunk/include/linux/bitmap.h | 11 - trunk/include/linux/fs.h | 22 +- trunk/include/linux/gpio.h | 6 - trunk/include/linux/iommu-helper.h | 3 + trunk/include/linux/ioport.h | 4 +- trunk/include/linux/ipc_namespace.h | 2 +- trunk/include/linux/kexec.h | 2 - trunk/include/linux/ksm.h | 14 +- trunk/include/linux/memcontrol.h | 17 +- trunk/include/linux/oom.h | 4 +- trunk/include/linux/page_cgroup.h | 7 +- trunk/include/linux/ptrace.h | 23 +- trunk/include/linux/reiserfs_fs.h | 35 +- trunk/include/linux/sched.h | 14 +- trunk/include/linux/sem.h | 5 +- trunk/include/linux/sm501-regs.h | 2 - trunk/include/linux/timb_gpio.h | 37 - trunk/include/linux/tracehook.h | 7 - trunk/include/media/ir-common.h | 11 +- trunk/include/video/da8xx-fb.h | 1 - trunk/ipc/msg.c | 1 - trunk/ipc/sem.c | 214 ++--- trunk/ipc/shm.c | 1 - trunk/kernel/fork.c | 9 +- trunk/kernel/kexec.c | 59 -- trunk/kernel/ksysfs.c | 21 - trunk/kernel/pid.c | 12 +- trunk/kernel/relay.c | 2 +- trunk/kernel/signal.c | 38 +- trunk/kernel/time/timecompare.c | 2 +- trunk/kernel/trace/trace.c | 4 +- trunk/lib/bitmap.c | 81 -- trunk/lib/genalloc.c | 33 +- trunk/lib/iommu-helper.c | 59 +- trunk/lib/swiotlb.c | 4 +- trunk/mm/memcontrol.c | 419 +++------ trunk/mm/memory.c | 2 - trunk/mm/oom_kill.c | 75 +- trunk/mm/page_alloc.c | 22 +- trunk/mm/rmap.c | 4 +- trunk/mm/truncate.c | 6 - trunk/net/core/skbuff.c | 2 +- 219 files changed, 3296 insertions(+), 7066 deletions(-) create mode 100644 trunk/Documentation/DocBook/procfs-guide.tmpl create mode 100644 trunk/Documentation/DocBook/procfs_example.c delete mode 100644 trunk/arch/blackfin/include/asm/bfin-lq035q1.h delete mode 100644 trunk/drivers/gpio/timbgpio.c delete mode 100644 trunk/drivers/rtc/rtc-bq32k.c delete mode 100644 trunk/drivers/rtc/rtc-mc13783.c delete mode 100644 trunk/drivers/rtc/rtc-nuc900.c delete mode 100644 trunk/drivers/video/bfin-lq035q1-fb.c delete mode 100644 trunk/drivers/video/mb862xx/mb862xxfb_accel.c delete mode 100644 trunk/drivers/video/mb862xx/mb862xxfb_accel.h delete mode 100644 trunk/include/linux/timb_gpio.h diff --git a/[refs] b/[refs] index 574ac6cfacba..3a0ea7df4443 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 9cfc86249f32d984339c6d1f8a1fd1326989b3b8 +refs/heads/master: d30a3fe89635324397c9cf5802f18f11a49ace17 diff --git a/trunk/Documentation/DocBook/Makefile b/trunk/Documentation/DocBook/Makefile index ee34ceb9ad5f..ab8300f67182 100644 --- a/trunk/Documentation/DocBook/Makefile +++ b/trunk/Documentation/DocBook/Makefile @@ -8,7 +8,7 @@ DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ - writing_usb_driver.xml networking.xml \ + procfs-guide.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 \ @@ -65,7 +65,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: @@ -101,6 +101,17 @@ 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) @@ -227,7 +238,7 @@ clean-files := $(DOCBOOKS) \ $(patsubst %.xml, %.pdf, $(DOCBOOKS)) \ $(patsubst %.xml, %.html, $(DOCBOOKS)) \ $(patsubst %.xml, %.9, $(DOCBOOKS)) \ - $(index) + $(C-procfs-example) $(index) clean-dirs := $(patsubst %.xml,%,$(DOCBOOKS)) man diff --git a/trunk/Documentation/DocBook/procfs-guide.tmpl b/trunk/Documentation/DocBook/procfs-guide.tmpl new file mode 100644 index 000000000000..9eba4b7af73d --- /dev/null +++ b/trunk/Documentation/DocBook/procfs-guide.tmpl @@ -0,0 +1,626 @@ + + +]> + + + + Linux Kernel Procfs Guide + + + + Erik + (J.A.K.) + Mouw + +
+ mouw@nl.linux.org +
+
+
+ + + This software and documentation were written 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. + + +
+ + + + 1.0 + May 30, 2001 + Initial revision posted to linux-kernel + + + 1.1 + June 3, 2001 + Revised after comments from linux-kernel + + + + + 2001 + Erik Mouw + + + + + + 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. + + + + 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. + + + + 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 + + + + For more details see the file COPYING in the source + distribution of Linux. + + +
+ + + + + + + + + + + + Preface + + + 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 http://www.kernelnewbies.org/), + 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. + + + + I'd like to thank Jeff Garzik + jgarzik@pobox.com and Alexander Viro + viro@parcelfarce.linux.theplanet.co.uk for their input, + Tim Waugh twaugh@redhat.com for his Selfdocbook, + and Marc Joosen marcj@historia.et.tudelft.nl for + proofreading. + + + + Erik + + + + + + + + Introduction + + + The /proc 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 /proc/[0-9]+/), but also for debug + purposes (like /proc/ksyms). + + + + 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. + + + + Note that the files in /proc/sys are sysctl files: they + don't belong to procfs and are governed by a completely + different API described in the Kernel API book. + + + + + + + + Managing procfs entries + + + This chapter describes the functions that various kernel + components use to populate the procfs with files, symlinks, + device nodes, and directories. + + + + 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: + + + +#include <linux/proc_fs.h> + + + + + + + Creating a regular file + + + + struct proc_dir_entry* create_proc_entry + const char* name + mode_t mode + struct proc_dir_entry* parent + + + + + This function creates a regular file with the name + name, file mode + mode in the directory + parent. To create a file in the root of + the procfs, use NULL as + parent parameter. When successful, the + function will return a pointer to the freshly created + struct proc_dir_entry; otherwise it + will return NULL. describes how to do something useful with + regular files. + + + + Note that it is specifically supported that you can pass a + path that spans multiple directories. For example + create_proc_entry("drivers/via0/info") + will create the via0 + directory if necessary, with standard + 0755 permissions. + + + + If you only want to be able to read the file, the function + create_proc_read_entry described in may be used to create and initialise + the procfs entry in one single call. + + + + + + + + Creating a symlink + + + + struct proc_dir_entry* + proc_symlink const + char* name + struct proc_dir_entry* + parent const + char* dest + + + + + This creates a symlink in the procfs directory + parent that points from + name to + dest. This translates in userland to + ln -s dest + name. + + + + + Creating a directory + + + + struct proc_dir_entry* proc_mkdir + const char* name + struct proc_dir_entry* parent + + + + + Create a directory name in the procfs + directory parent. + + + + + + + + Removing an entry + + + + void remove_proc_entry + const char* name + struct proc_dir_entry* parent + + + + + Removes the entry name in the directory + parent from the procfs. Entries are + removed by their name, not by the + struct proc_dir_entry returned by the + various create functions. Note that this function doesn't + recursively remove entries. + + + + Be sure to free the data entry from + the struct proc_dir_entry before + remove_proc_entry is called (that is: if + there was some data allocated, of + course). See for more information + on using the data entry. + + + + + + + + + Communicating with userland + + + Instead of reading (or writing) information directly from + kernel memory, procfs works with call back + functions 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 read_proc and/or + write_proc fields in the + struct proc_dir_entry* that the + function create_proc_entry returned: + + + +struct proc_dir_entry* entry; + +entry->read_proc = read_proc_foo; +entry->write_proc = write_proc_foo; + + + + If you only want to use a the + read_proc, the function + create_proc_read_entry described in may be used to create and initialise the + procfs entry in one single call. + + + + + + Reading data + + + 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: + + + + + int read_func + char* buffer + char** start + off_t off + int count + int* peof + void* data + + + + + The read function should write its information into the + buffer, which will be exactly + PAGE_SIZE bytes long. + + + + The parameter + peof should be used to signal that the + end of the file has been reached by writing + 1 to the memory location + peof points to. + + + + The data + parameter can be used to create a single call back function for + several files, see . + + + + The rest of the parameters and the return value are described + by a comment in fs/proc/generic.c as follows: + + +
+ + You have three ways to return data: + + + + + Leave *start = NULL. (This is the default.) + Put the data of the requested offset at that + offset within the buffer. Return the number (n) + of bytes there are from the beginning of the + buffer up to the last byte of data. If the + number of supplied bytes (= n - offset) 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. + + + + + Set *start 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 *start. 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) + + + + + Set *start to an address within the buffer. + Put the data of the requested offset at *start. + 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. + + + +
+ + + shows how to use a read call back + function. + +
+ + + + + + Writing data + + + 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: + + + + + int write_func + struct file* file + const char* buffer + unsigned long count + void* data + + + + + The write function should read count + bytes at maximum from the buffer. Note + that the buffer doesn't live in the + kernel's memory space, so it should first be copied to kernel + space with copy_from_user. The + file parameter is usually + ignored. shows how to use the + data parameter. + + + + Again, shows how to use this call back + function. + + + + + + + + A single call back for many files + + + 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 + data field in struct + proc_dir_entry. First of all, the + data field has to be initialised: + + + +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; + + + + The data field is a void + *, so it can be initialised with anything. + + + + Now that the data field is set, the + read_proc and + write_proc can use it to distinguish + between files because they get it passed into their + data parameter: + + + +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; +} + + + + Be sure to free the data data field + when removing the procfs entry. + + +
+ + + + + + Tips and tricks + + + + + + Convenience functions + + + + struct proc_dir_entry* create_proc_read_entry + const char* name + mode_t mode + struct proc_dir_entry* parent + read_proc_t* read_proc + void* data + + + + + This function creates a regular file in exactly the same way + as create_proc_entry from does, but also allows to set the read + function read_proc in one call. This + function can set the data as well, like + explained in . + + + + + + + Modules + + + If procfs is being used from within a module, be sure to set + the owner field in the + struct proc_dir_entry to + THIS_MODULE. + + + +struct proc_dir_entry* entry; + +entry->owner = THIS_MODULE; + + + + + + + + Mode and ownership + + + 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: + + + +struct proc_dir_entry* entry; + +entry->mode = S_IWUSR |S_IRUSR | S_IRGRP | S_IROTH; +entry->uid = 0; +entry->gid = 100; + + + + + + + + + + Example + + + +&procfsexample; + + +
diff --git a/trunk/Documentation/DocBook/procfs_example.c b/trunk/Documentation/DocBook/procfs_example.c new file mode 100644 index 000000000000..a5b11793b1e0 --- /dev/null +++ b/trunk/Documentation/DocBook/procfs_example.c @@ -0,0 +1,201 @@ +/* + * 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 +#include +#include +#include +#include +#include + + +#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"); diff --git a/trunk/Documentation/SubmitChecklist b/trunk/Documentation/SubmitChecklist index 1053a56be3b1..78a9168ff377 100644 --- a/trunk/Documentation/SubmitChecklist +++ b/trunk/Documentation/SubmitChecklist @@ -15,7 +15,7 @@ kernel patches. 2: Passes allnoconfig, allmodconfig 3: Builds on multiple CPU architectures by using local cross-compile tools - or some other build farm. + or something like PLM at OSDL. 4: ppc64 is a good architecture for cross-compilation checking because it tends to use `unsigned long' for 64-bit quantities. @@ -88,6 +88,3 @@ 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. diff --git a/trunk/Documentation/fb/viafb.txt b/trunk/Documentation/fb/viafb.txt index f3e046a6a987..67dbf442b0b6 100644 --- a/trunk/Documentation/fb/viafb.txt +++ b/trunk/Documentation/fb/viafb.txt @@ -7,7 +7,7 @@ VIA UniChrome Family(CLE266, PM800 / CN400 / CN300, P4M800CE / P4M800Pro / CN700 / VN800, CX700 / VX700, K8M890, P4M890, - CN896 / P4M900, VX800, VX855) + CN896 / P4M900, VX800) [Driver features] ------------------------ @@ -154,6 +154,13 @@ 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". @@ -174,6 +181,9 @@ 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] diff --git a/trunk/Documentation/filesystems/seq_file.txt b/trunk/Documentation/filesystems/seq_file.txt index a1e2e0dda907..0d15ebccf5b0 100644 --- a/trunk/Documentation/filesystems/seq_file.txt +++ b/trunk/Documentation/filesystems/seq_file.txt @@ -248,7 +248,9 @@ code, that is done in the initialization code in the usual way: { struct proc_dir_entry *entry; - proc_create("sequence", 0, NULL, &ct_file_ops); + entry = create_proc_entry("sequence", 0, NULL); + if (entry) + entry->proc_fops = &ct_file_ops; return 0; } diff --git a/trunk/Documentation/gpio.txt b/trunk/Documentation/gpio.txt index 1866c27eec69..e4e7daed2ba8 100644 --- a/trunk/Documentation/gpio.txt +++ b/trunk/Documentation/gpio.txt @@ -531,13 +531,6 @@ 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: @@ -573,8 +566,6 @@ 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 @@ -589,9 +580,3 @@ 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. diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index c309515ae959..ab95d3ada5c7 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -2729,11 +2729,6 @@ 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: - vt.cur_default= [VT] Default cursor shape. - Format: 0xCCBBAA, where AA, BB, and CC are the same as - the parameters of the [?A;B;Cc escape sequence; - see VGA-softcursor.txt. Default: 2 = underline. - vt.default_blu= [VT] Format: ,,,..., Change the default blue palette of the console. diff --git a/trunk/arch/alpha/include/asm/elf.h b/trunk/arch/alpha/include/asm/elf.h index 9baae8afe8a3..5c75c1b2352a 100644 --- a/trunk/arch/alpha/include/asm/elf.h +++ b/trunk/arch/alpha/include/asm/elf.h @@ -81,6 +81,7 @@ 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 diff --git a/trunk/arch/arm/include/asm/elf.h b/trunk/arch/arm/include/asm/elf.h index a399bb5730f1..6aac3f5bb2f3 100644 --- a/trunk/arch/arm/include/asm/elf.h +++ b/trunk/arch/arm/include/asm/elf.h @@ -101,6 +101,7 @@ 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 diff --git a/trunk/arch/arm/mach-davinci/board-da850-evm.c b/trunk/arch/arm/mach-davinci/board-da850-evm.c index 07de8db14581..62b98bffc158 100644 --- a/trunk/arch/arm/mach-davinci/board-da850-evm.c +++ b/trunk/arch/arm/mach-davinci/board-da850-evm.c @@ -339,15 +339,6 @@ 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; @@ -365,11 +356,17 @@ static int da850_lcd_hw_init(void) gpio_direction_output(DA850_LCD_BL_PIN, 0); gpio_direction_output(DA850_LCD_PWR_PIN, 0); - /* Switch off panel power and backlight */ - da850_panel_power_ctrl(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 on panel power and backlight */ - da850_panel_power_ctrl(1); + /* enable lcd backlight */ + gpio_set_value(DA850_LCD_BL_PIN, 1); return 0; } @@ -677,7 +674,6 @@ 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", diff --git a/trunk/arch/avr32/include/asm/elf.h b/trunk/arch/avr32/include/asm/elf.h index 3b3159b710d4..d5d1d41c600a 100644 --- a/trunk/arch/avr32/include/asm/elf.h +++ b/trunk/arch/avr32/include/asm/elf.h @@ -77,6 +77,7 @@ 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/trunk/arch/blackfin/include/asm/bfin-lq035q1.h b/trunk/arch/blackfin/include/asm/bfin-lq035q1.h deleted file mode 100644 index 57bc21ac2296..000000000000 --- a/trunk/arch/blackfin/include/asm/bfin-lq035q1.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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 */ diff --git a/trunk/arch/blackfin/include/asm/elf.h b/trunk/arch/blackfin/include/asm/elf.h index 5b50f0ecacf8..8e0764c81eaf 100644 --- a/trunk/arch/blackfin/include/asm/elf.h +++ b/trunk/arch/blackfin/include/asm/elf.h @@ -55,6 +55,7 @@ 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 diff --git a/trunk/arch/cris/include/asm/elf.h b/trunk/arch/cris/include/asm/elf.h index 8a3d8e2b33c1..0f51b10b9f4f 100644 --- a/trunk/arch/cris/include/asm/elf.h +++ b/trunk/arch/cris/include/asm/elf.h @@ -64,6 +64,8 @@ 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 diff --git a/trunk/arch/frv/include/asm/elf.h b/trunk/arch/frv/include/asm/elf.h index c3819804a74b..7bbf6e47f8c8 100644 --- a/trunk/arch/frv/include/asm/elf.h +++ b/trunk/arch/frv/include/asm/elf.h @@ -115,6 +115,7 @@ 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 diff --git a/trunk/arch/h8300/include/asm/elf.h b/trunk/arch/h8300/include/asm/elf.h index c24fa250d653..94e2284c8816 100644 --- a/trunk/arch/h8300/include/asm/elf.h +++ b/trunk/arch/h8300/include/asm/elf.h @@ -34,6 +34,7 @@ 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 diff --git a/trunk/arch/ia64/ia32/elfcore32.h b/trunk/arch/ia64/ia32/elfcore32.h index 657725742617..9a3abf58cea3 100644 --- a/trunk/arch/ia64/ia32/elfcore32.h +++ b/trunk/arch/ia64/ia32/elfcore32.h @@ -11,6 +11,8 @@ #include #include +#define USE_ELF_CORE_DUMP 1 + /* Override elfcore.h */ #define _LINUX_ELFCORE_H 1 typedef unsigned int elf_greg_t; diff --git a/trunk/arch/ia64/include/asm/dma-mapping.h b/trunk/arch/ia64/include/asm/dma-mapping.h index 7d09a09cdaad..8d3c79cd81e7 100644 --- a/trunk/arch/ia64/include/asm/dma-mapping.h +++ b/trunk/arch/ia64/include/asm/dma-mapping.h @@ -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 - 1 <= *dev->dma_mask; + return addr + size <= *dev->dma_mask; } static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) diff --git a/trunk/arch/ia64/include/asm/elf.h b/trunk/arch/ia64/include/asm/elf.h index e14108b19c09..86eddee029cb 100644 --- a/trunk/arch/ia64/include/asm/elf.h +++ b/trunk/arch/ia64/include/asm/elf.h @@ -25,6 +25,7 @@ #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 diff --git a/trunk/arch/ia64/sn/pci/tioca_provider.c b/trunk/arch/ia64/sn/pci/tioca_provider.c index efb454534e52..35b2a27d2e77 100644 --- a/trunk/arch/ia64/sn/pci/tioca_provider.c +++ b/trunk/arch/ia64/sn/pci/tioca_provider.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -370,7 +369,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 ps, ps_shift, entry, entries, mapsize; + int i, ps, ps_shift, entry, entries, mapsize, last_entry; u64 xio_addr, end_xio_addr; struct tioca_common *tioca_common; struct tioca_kernel *tioca_kern; @@ -411,13 +410,23 @@ 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 = bitmap_find_next_zero_area(map, mapsize, 0, entries, 0); - if (entry >= mapsize) { + 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) { kfree(ca_dmamap); goto map_return; } - bitmap_set(map, entry, entries); + for (i = 0; i < entries; i++) + set_bit(entry + i, map); bus_addr = tioca_kern->ca_pciap_base + (entry * ps); diff --git a/trunk/arch/m32r/include/asm/elf.h b/trunk/arch/m32r/include/asm/elf.h index 2f85412ef730..0cc34c94bf2b 100644 --- a/trunk/arch/m32r/include/asm/elf.h +++ b/trunk/arch/m32r/include/asm/elf.h @@ -102,6 +102,7 @@ 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 /* diff --git a/trunk/arch/m68k/include/asm/elf.h b/trunk/arch/m68k/include/asm/elf.h index 01c193d91412..0b0f49eb876b 100644 --- a/trunk/arch/m68k/include/asm/elf.h +++ b/trunk/arch/m68k/include/asm/elf.h @@ -59,6 +59,7 @@ 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 diff --git a/trunk/arch/microblaze/include/asm/elf.h b/trunk/arch/microblaze/include/asm/elf.h index 7d4acf2b278e..f92fc0dda006 100644 --- a/trunk/arch/microblaze/include/asm/elf.h +++ b/trunk/arch/microblaze/include/asm/elf.h @@ -77,6 +77,7 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; #define ELF_DATA ELFDATA2MSB #endif +#define USE_ELF_CORE_DUMP #define ELF_EXEC_PAGESIZE 4096 diff --git a/trunk/arch/mips/include/asm/elf.h b/trunk/arch/mips/include/asm/elf.h index 7a6a35dbe529..7990694cda22 100644 --- a/trunk/arch/mips/include/asm/elf.h +++ b/trunk/arch/mips/include/asm/elf.h @@ -326,6 +326,7 @@ 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 diff --git a/trunk/arch/mn10300/include/asm/elf.h b/trunk/arch/mn10300/include/asm/elf.h index e5fa97cd9a14..75a70aa9fd6f 100644 --- a/trunk/arch/mn10300/include/asm/elf.h +++ b/trunk/arch/mn10300/include/asm/elf.h @@ -77,6 +77,7 @@ 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 diff --git a/trunk/arch/parisc/include/asm/elf.h b/trunk/arch/parisc/include/asm/elf.h index 19f6cb1a4a1c..9c802eb4be84 100644 --- a/trunk/arch/parisc/include/asm/elf.h +++ b/trunk/arch/parisc/include/asm/elf.h @@ -328,6 +328,7 @@ 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 diff --git a/trunk/arch/powerpc/include/asm/dma-mapping.h b/trunk/arch/powerpc/include/asm/dma-mapping.h index 80a973bb9e71..e281daebddca 100644 --- a/trunk/arch/powerpc/include/asm/dma-mapping.h +++ b/trunk/arch/powerpc/include/asm/dma-mapping.h @@ -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 - 1 <= *dev->dma_mask; + return addr + size <= *dev->dma_mask; } static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) diff --git a/trunk/arch/powerpc/include/asm/elf.h b/trunk/arch/powerpc/include/asm/elf.h index 17828ad411eb..014a624f4c8e 100644 --- a/trunk/arch/powerpc/include/asm/elf.h +++ b/trunk/arch/powerpc/include/asm/elf.h @@ -170,6 +170,7 @@ 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 diff --git a/trunk/arch/powerpc/include/asm/ptrace.h b/trunk/arch/powerpc/include/asm/ptrace.h index cbd759e3cd78..8c341490cfc5 100644 --- a/trunk/arch/powerpc/include/asm/ptrace.h +++ b/trunk/arch/powerpc/include/asm/ptrace.h @@ -140,8 +140,6 @@ 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__ */ diff --git a/trunk/arch/powerpc/kernel/iommu.c b/trunk/arch/powerpc/kernel/iommu.c index 5547ae6e6b0b..fd51578e29dd 100644 --- a/trunk/arch/powerpc/kernel/iommu.c +++ b/trunk/arch/powerpc/kernel/iommu.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include @@ -251,7 +251,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, } ppc_md.tce_free(tbl, entry, npages); - bitmap_clear(tbl->it_map, free_entry, npages); + iommu_area_free(tbl->it_map, free_entry, npages); } static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr, diff --git a/trunk/arch/powerpc/kernel/traps.c b/trunk/arch/powerpc/kernel/traps.c index d069ff8a7e03..804f0f30f227 100644 --- a/trunk/arch/powerpc/kernel/traps.c +++ b/trunk/arch/powerpc/kernel/traps.c @@ -174,15 +174,6 @@ 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; diff --git a/trunk/arch/s390/include/asm/elf.h b/trunk/arch/s390/include/asm/elf.h index 354d42616c7e..e885442c1dfe 100644 --- a/trunk/arch/s390/include/asm/elf.h +++ b/trunk/arch/s390/include/asm/elf.h @@ -155,6 +155,7 @@ 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 diff --git a/trunk/arch/score/include/asm/elf.h b/trunk/arch/score/include/asm/elf.h index f478ce94181f..43526d9fda93 100644 --- a/trunk/arch/score/include/asm/elf.h +++ b/trunk/arch/score/include/asm/elf.h @@ -61,6 +61,7 @@ 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 diff --git a/trunk/arch/sh/include/asm/elf.h b/trunk/arch/sh/include/asm/elf.h index ac04255022b6..ccb1d93bb043 100644 --- a/trunk/arch/sh/include/asm/elf.h +++ b/trunk/arch/sh/include/asm/elf.h @@ -114,6 +114,7 @@ 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 diff --git a/trunk/arch/sparc/include/asm/elf_32.h b/trunk/arch/sparc/include/asm/elf_32.h index 4269ca6ad18a..381a1b5256d6 100644 --- a/trunk/arch/sparc/include/asm/elf_32.h +++ b/trunk/arch/sparc/include/asm/elf_32.h @@ -104,6 +104,8 @@ typedef struct { #define ELF_CLASS ELFCLASS32 #define ELF_DATA ELFDATA2MSB +#define USE_ELF_CORE_DUMP + #define ELF_EXEC_PAGESIZE 4096 diff --git a/trunk/arch/sparc/include/asm/elf_64.h b/trunk/arch/sparc/include/asm/elf_64.h index ff66bb88537b..d42e393078c4 100644 --- a/trunk/arch/sparc/include/asm/elf_64.h +++ b/trunk/arch/sparc/include/asm/elf_64.h @@ -152,6 +152,7 @@ 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 diff --git a/trunk/arch/sparc/kernel/iommu.c b/trunk/arch/sparc/kernel/iommu.c index 5fad94950e76..7690cc219ecc 100644 --- a/trunk/arch/sparc/kernel/iommu.c +++ b/trunk/arch/sparc/kernel/iommu.c @@ -11,7 +11,6 @@ #include #include #include -#include #ifdef CONFIG_PCI #include @@ -170,7 +169,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; - bitmap_clear(arena->map, entry, npages); + iommu_area_free(arena->map, entry, npages); } int iommu_table_init(struct iommu *iommu, int tsbsize, diff --git a/trunk/arch/sparc/kernel/ldc.c b/trunk/arch/sparc/kernel/ldc.c index df39a0f0d27a..e0ba898e30cf 100644 --- a/trunk/arch/sparc/kernel/ldc.c +++ b/trunk/arch/sparc/kernel/ldc.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -1876,7 +1875,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, start, end, limit; + unsigned long n, i, start, end, limit; int pass; limit = arena->limit; @@ -1884,7 +1883,7 @@ static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages) pass = 0; again: - n = bitmap_find_next_zero_area(arena->map, limit, start, npages, 0); + n = find_next_zero_bit(arena->map, limit, start); end = n + npages; if (unlikely(end >= limit)) { if (likely(pass < 1)) { @@ -1897,7 +1896,16 @@ static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages) return -1; } } - bitmap_set(arena->map, n, npages); + + 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); arena->hint = end; diff --git a/trunk/arch/sparc/mm/sun4c.c b/trunk/arch/sparc/mm/sun4c.c index a89baf0d875a..2ffacd67c424 100644 --- a/trunk/arch/sparc/mm/sun4c.c +++ b/trunk/arch/sparc/mm/sun4c.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -1022,12 +1021,20 @@ 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); - base = bitmap_find_next_zero_area(sun4c_iobuffer_map, iobuffer_map_size, - 0, npages, 0); - if (base >= iobuffer_map_size) - goto abend; + 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++; + } + } +found: high = ((base + npages) << PAGE_SHIFT) + sun4c_iobuffer_start; high = SUN4C_REAL_PGDIR_ALIGN(high); while (high > sun4c_iobuffer_high) { diff --git a/trunk/arch/um/sys-i386/asm/elf.h b/trunk/arch/um/sys-i386/asm/elf.h index 770885472ed4..d0da9d7c5371 100644 --- a/trunk/arch/um/sys-i386/asm/elf.h +++ b/trunk/arch/um/sys-i386/asm/elf.h @@ -48,6 +48,7 @@ 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) diff --git a/trunk/arch/um/sys-ppc/asm/elf.h b/trunk/arch/um/sys-ppc/asm/elf.h index 8aacaf56508d..af9463cd8ce5 100644 --- a/trunk/arch/um/sys-ppc/asm/elf.h +++ b/trunk/arch/um/sys-ppc/asm/elf.h @@ -17,6 +17,8 @@ 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 diff --git a/trunk/arch/um/sys-x86_64/asm/elf.h b/trunk/arch/um/sys-x86_64/asm/elf.h index 49655c83efd2..04b9e87c8dad 100644 --- a/trunk/arch/um/sys-x86_64/asm/elf.h +++ b/trunk/arch/um/sys-x86_64/asm/elf.h @@ -104,6 +104,7 @@ 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) diff --git a/trunk/arch/x86/include/asm/dma-mapping.h b/trunk/arch/x86/include/asm/dma-mapping.h index ac91eed21061..0f6c02f3b7d4 100644 --- a/trunk/arch/x86/include/asm/dma-mapping.h +++ b/trunk/arch/x86/include/asm/dma-mapping.h @@ -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 - 1 <= *dev->dma_mask; + return addr + size <= *dev->dma_mask; } static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) diff --git a/trunk/arch/x86/include/asm/elf.h b/trunk/arch/x86/include/asm/elf.h index b4501ee223ad..8a024babe5e6 100644 --- a/trunk/arch/x86/include/asm/elf.h +++ b/trunk/arch/x86/include/asm/elf.h @@ -239,6 +239,7 @@ 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 diff --git a/trunk/arch/x86/include/asm/ptrace.h b/trunk/arch/x86/include/asm/ptrace.h index 9d369f680321..3d11fd0f44c5 100644 --- a/trunk/arch/x86/include/asm/ptrace.h +++ b/trunk/arch/x86/include/asm/ptrace.h @@ -292,8 +292,6 @@ 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); diff --git a/trunk/arch/x86/include/asm/uv/bios.h b/trunk/arch/x86/include/asm/uv/bios.h index 2751f3075d8b..7ed17ff502b9 100644 --- a/trunk/arch/x86/include/asm/uv/bios.h +++ b/trunk/arch/x86/include/asm/uv/bios.h @@ -76,6 +76,15 @@ 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, @@ -91,7 +100,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(unsigned long, unsigned int, +extern int uv_bios_mq_watchlist_alloc(int, 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); diff --git a/trunk/arch/x86/include/asm/uv/uv_hub.h b/trunk/arch/x86/include/asm/uv/uv_hub.h index 811bfabc80b7..d1414af98559 100644 --- a/trunk/arch/x86/include/asm/uv/uv_hub.h +++ b/trunk/arch/x86/include/asm/uv/uv_hub.h @@ -172,8 +172,6 @@ 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 @@ -234,26 +232,6 @@ 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) { @@ -329,15 +307,6 @@ 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. @@ -465,14 +434,6 @@ 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; @@ -481,7 +442,10 @@ static inline void uv_hub_send_ipi(int pnode, int apicid, int vector) if (vector == NMI_VECTOR) dmode = dest_NMI; - val = uv_hub_ipi_value(apicid, vector, dmode); + 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); uv_write_global_mmr64(pnode, UVH_IPI_INT, val); } diff --git a/trunk/arch/x86/kernel/amd_iommu.c b/trunk/arch/x86/kernel/amd_iommu.c index 23824fef789c..b990b5cc9541 100644 --- a/trunk/arch/x86/kernel/amd_iommu.c +++ b/trunk/arch/x86/kernel/amd_iommu.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include @@ -1162,7 +1162,7 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom, address = (address % APERTURE_RANGE_SIZE) >> PAGE_SHIFT; - bitmap_clear(range->bitmap, address, pages); + iommu_area_free(range->bitmap, address, pages); } diff --git a/trunk/arch/x86/kernel/bios_uv.c b/trunk/arch/x86/kernel/bios_uv.c index b0206a211b09..63a88e1f987d 100644 --- a/trunk/arch/x86/kernel/bios_uv.c +++ b/trunk/arch/x86/kernel/bios_uv.c @@ -101,17 +101,21 @@ s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher, } int -uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size, +uv_bios_mq_watchlist_alloc(int blade, 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, - mq_size, (u64)intr_mmr_offset, + size_blade.val, (u64)intr_mmr_offset, (u64)&watchlist, 0); if (ret < BIOS_STATUS_SUCCESS) return ret; diff --git a/trunk/arch/x86/kernel/pci-calgary_64.c b/trunk/arch/x86/kernel/pci-calgary_64.c index 2bbde6078143..c563e4c8ff39 100644 --- a/trunk/arch/x86/kernel/pci-calgary_64.c +++ b/trunk/arch/x86/kernel/pci-calgary_64.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include @@ -212,7 +212,7 @@ static void iommu_range_reserve(struct iommu_table *tbl, spin_lock_irqsave(&tbl->it_lock, flags); - bitmap_set(tbl->it_map, index, npages); + iommu_area_reserve(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); - bitmap_clear(tbl->it_map, entry, npages); + iommu_area_free(tbl->it_map, entry, npages); spin_unlock_irqrestore(&tbl->it_lock, flags); } diff --git a/trunk/arch/x86/kernel/pci-gart_64.c b/trunk/arch/x86/kernel/pci-gart_64.c index 34de53b46f87..56c0e730d3fe 100644 --- a/trunk/arch/x86/kernel/pci-gart_64.c +++ b/trunk/arch/x86/kernel/pci-gart_64.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include @@ -126,7 +126,7 @@ static void free_iommu(unsigned long offset, int size) unsigned long flags; spin_lock_irqsave(&iommu_bitmap_lock, flags); - bitmap_clear(iommu_gart_bitmap, offset, size); + iommu_area_free(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. */ - bitmap_set(iommu_gart_bitmap, 0, EMERGENCY_PAGES); + iommu_area_reserve(iommu_gart_bitmap, 0, EMERGENCY_PAGES); pr_info("PCI-DMA: Reserving %luMB of IOMMU area in the AGP aperture\n", iommu_size >> 20); diff --git a/trunk/arch/x86/kernel/ptrace.c b/trunk/arch/x86/kernel/ptrace.c index 2779321046bd..7079ddaf0731 100644 --- a/trunk/arch/x86/kernel/ptrace.c +++ b/trunk/arch/x86/kernel/ptrace.c @@ -1676,33 +1676,21 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) #endif } -static void fill_sigtrap_info(struct task_struct *tsk, - struct pt_regs *regs, - int error_code, int si_code, - struct siginfo *info) +void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, + int error_code, int si_code) { + 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; - info->si_addr = user_mode_vm(regs) ? (void __user *)regs->ip : NULL; -} + memset(&info, 0, sizeof(info)); + info.si_signo = SIGTRAP; + info.si_code = si_code; -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); -} + /* User-mode ip? */ + info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL; -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); } @@ -1767,22 +1755,29 @@ 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(). + * 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. */ - 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); + if (test_thread_flag(TIF_SINGLESTEP) && + tracehook_consider_fatal_signal(current, SIGTRAP)) + send_sigtrap(current, regs, 0, TRAP_BRKPT); } diff --git a/trunk/arch/xtensa/include/asm/elf.h b/trunk/arch/xtensa/include/asm/elf.h index 5eb6d695e987..c3f53e755ca5 100644 --- a/trunk/arch/xtensa/include/asm/elf.h +++ b/trunk/arch/xtensa/include/asm/elf.h @@ -123,6 +123,7 @@ 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 /* diff --git a/trunk/drivers/char/efirtc.c b/trunk/drivers/char/efirtc.c index 53c524e7b829..26a47dc88f61 100644 --- a/trunk/drivers/char/efirtc.c +++ b/trunk/drivers/char/efirtc.c @@ -285,7 +285,6 @@ 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= { diff --git a/trunk/drivers/char/ipmi/ipmi_kcs_sm.c b/trunk/drivers/char/ipmi/ipmi_kcs_sm.c index cf82fedae099..80704875794c 100644 --- a/trunk/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/trunk/drivers/char/ipmi/ipmi_kcs_sm.c @@ -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_STATE) { + if (state != KCS_IDLE) { start_error_recovery(kcs, "State machine not idle at start"); break; diff --git a/trunk/drivers/char/sysrq.c b/trunk/drivers/char/sysrq.c index 1ae2de7d8b4f..44203ff599da 100644 --- a/trunk/drivers/char/sysrq.c +++ b/trunk/drivers/char/sysrq.c @@ -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, NULL); + out_of_memory(node_zonelist(0, GFP_KERNEL), GFP_KERNEL, 0); } static DECLARE_WORK(moom_work, moom_callback); diff --git a/trunk/drivers/char/vt.c b/trunk/drivers/char/vt.c index 50faa1fb0f06..e43fbc66aef0 100644 --- a/trunk/drivers/char/vt.c +++ b/trunk/drivers/char/vt.c @@ -164,9 +164,6 @@ 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. @@ -1639,7 +1636,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); @@ -1841,7 +1838,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; diff --git a/trunk/drivers/edac/i5100_edac.c b/trunk/drivers/edac/i5100_edac.c index 7785d8ffa404..22db05a67bfb 100644 --- a/trunk/drivers/edac/i5100_edac.c +++ b/trunk/drivers/edac/i5100_edac.c @@ -9,11 +9,6 @@ * 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 #include @@ -30,8 +25,6 @@ /* 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 */ @@ -79,21 +72,11 @@ /* 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; @@ -282,43 +265,42 @@ static inline u32 i5100_recmemb_ras(u32 a) } /* some generic limits */ -#define I5100_MAX_RANKS_PER_CHAN 6 -#define I5100_CHANNELS 2 +#define I5100_MAX_RANKS_PER_CTLR 6 +#define I5100_MAX_CTLRS 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_CHAN 4 +#define I5100_MAX_DIMM_SLOTS_PER_CTLR 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_CHANNELS][I5100_MAX_DIMM_SLOTS_PER_CHAN]; + int dimm_numrank[I5100_MAX_CTLRS][I5100_MAX_DIMM_SLOTS_PER_CTLR]; /* * mainboard chip select map -- maps i5100 chip selects to * DIMM slot chip selects. In the case of only 4 ranks per - * channel, the mapping is fairly obvious but not unique. - * we map -1 -> NC and assume both channels use the same + * controller, the mapping is fairly obvious but not unique. + * we map -1 -> NC and assume both controllers use the same * map... * */ - int dimm_csmap[I5100_MAX_DIMM_SLOTS_PER_CHAN][I5100_MAX_RANKS_PER_DIMM]; + int dimm_csmap[I5100_MAX_DIMM_SLOTS_PER_CTLR][I5100_MAX_RANKS_PER_DIMM]; /* memory interleave range */ struct { u64 limit; unsigned way[2]; - } mir[I5100_CHANNELS]; + } mir[I5100_MAX_CTLRS]; /* adjusted memory interleave range register */ - unsigned amir[I5100_CHANNELS]; + unsigned amir[I5100_MAX_CTLRS]; /* dimm interleave range */ struct { unsigned rank[I5100_MAX_RANK_INTERLEAVE]; u64 limit; - } dmir[I5100_CHANNELS][I5100_MAX_DMIRS]; + } dmir[I5100_MAX_CTLRS][I5100_MAX_DMIRS]; /* memory technology registers... */ struct { @@ -328,33 +310,30 @@ struct i5100_priv { unsigned numbank; /* 2 or 3 lines */ unsigned numrow; /* 13 .. 16 lines */ unsigned numcol; /* 11 .. 12 lines */ - } mtr[I5100_CHANNELS][I5100_MAX_RANKS_PER_CHAN]; + } mtr[I5100_MAX_CTLRS][I5100_MAX_RANKS_PER_CTLR]; u64 tolm; /* top of low memory in bytes */ - unsigned ranksperchan; /* number of ranks per channel */ + unsigned ranksperctlr; /* number of ranks per controller */ 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/chan to a slot number on the mainboard */ +/* map a rank/ctlr to a slot number on the mainboard */ static int i5100_rank_to_slot(const struct mem_ctl_info *mci, - int chan, int rank) + int ctlr, int rank) { const struct i5100_priv *priv = mci->pvt_info; int i; - for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CHAN; i++) { + for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CTLR; i++) { int j; - const int numrank = priv->dimm_numrank[chan][i]; + const int numrank = priv->dimm_numrank[ctlr][i]; for (j = 0; j < numrank; j++) if (priv->dimm_csmap[i][j] == rank) - return i * 2 + chan; + return i * 2 + ctlr; } return -1; @@ -395,32 +374,32 @@ static const char *i5100_err_msg(unsigned err) return "none"; } -/* convert csrow index into a rank (per channel -- 0..5) */ +/* convert csrow index into a rank (per controller -- 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->ranksperchan; + return csrow % priv->ranksperctlr; } -/* convert csrow index into a channel (0..1) */ -static int i5100_csrow_to_chan(const struct mem_ctl_info *mci, int csrow) +/* convert csrow index into a controller (0..1) */ +static int i5100_csrow_to_cntlr(const struct mem_ctl_info *mci, int csrow) { const struct i5100_priv *priv = mci->pvt_info; - return csrow / priv->ranksperchan; + return csrow / priv->ranksperctlr; } static unsigned i5100_rank_to_csrow(const struct mem_ctl_info *mci, - int chan, int rank) + int ctlr, int rank) { const struct i5100_priv *priv = mci->pvt_info; - return chan * priv->ranksperchan + rank; + return ctlr * priv->ranksperctlr + rank; } static void i5100_handle_ce(struct mem_ctl_info *mci, - int chan, + int ctlr, unsigned bank, unsigned rank, unsigned long syndrome, @@ -428,12 +407,12 @@ static void i5100_handle_ce(struct mem_ctl_info *mci, unsigned ras, const char *msg) { - const int csrow = i5100_rank_to_csrow(mci, chan, rank); + const int csrow = i5100_rank_to_csrow(mci, ctlr, rank); printk(KERN_ERR - "CE chan %d, bank %u, rank %u, syndrome 0x%lx, " + "CE ctlr %d, bank %u, rank %u, syndrome 0x%lx, " "cas %u, ras %u, csrow %u, label \"%s\": %s\n", - chan, bank, rank, syndrome, cas, ras, + ctlr, bank, rank, syndrome, cas, ras, csrow, mci->csrows[csrow].channels[0].label, msg); mci->ce_count++; @@ -442,7 +421,7 @@ static void i5100_handle_ce(struct mem_ctl_info *mci, } static void i5100_handle_ue(struct mem_ctl_info *mci, - int chan, + int ctlr, unsigned bank, unsigned rank, unsigned long syndrome, @@ -450,23 +429,23 @@ static void i5100_handle_ue(struct mem_ctl_info *mci, unsigned ras, const char *msg) { - const int csrow = i5100_rank_to_csrow(mci, chan, rank); + const int csrow = i5100_rank_to_csrow(mci, ctlr, rank); printk(KERN_ERR - "UE chan %d, bank %u, rank %u, syndrome 0x%lx, " + "UE ctlr %d, bank %u, rank %u, syndrome 0x%lx, " "cas %u, ras %u, csrow %u, label \"%s\": %s\n", - chan, bank, rank, syndrome, cas, ras, + ctlr, 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 chan, +static void i5100_read_log(struct mem_ctl_info *mci, int ctlr, u32 ferr, u32 nerr) { struct i5100_priv *priv = mci->pvt_info; - struct pci_dev *pdev = (chan) ? priv->ch1mm : priv->ch0mm; + struct pci_dev *pdev = (ctlr) ? priv->ch1mm : priv->ch0mm; u32 dw; u32 dw2; unsigned syndrome = 0; @@ -505,7 +484,7 @@ static void i5100_read_log(struct mem_ctl_info *mci, int chan, else msg = i5100_err_msg(nerr); - i5100_handle_ce(mci, chan, bank, rank, syndrome, cas, ras, msg); + i5100_handle_ce(mci, ctlr, bank, rank, syndrome, cas, ras, msg); } if (i5100_validlog_nrecmemvalid(dw)) { @@ -527,7 +506,7 @@ static void i5100_read_log(struct mem_ctl_info *mci, int chan, else msg = i5100_err_msg(nerr); - i5100_handle_ue(mci, chan, bank, rank, syndrome, cas, ras, msg); + i5100_handle_ue(mci, ctlr, bank, rank, syndrome, cas, ras, msg); } pci_write_config_dword(pdev, I5100_VALIDLOG, dw); @@ -555,80 +534,6 @@ 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) @@ -652,19 +557,19 @@ static unsigned long __devinit i5100_npages(struct mem_ctl_info *mci, int csrow) { struct i5100_priv *priv = mci->pvt_info; - const unsigned chan_rank = i5100_csrow_to_rank(mci, csrow); - const unsigned chan = i5100_csrow_to_chan(mci, csrow); + const unsigned ctlr_rank = i5100_csrow_to_rank(mci, csrow); + const unsigned ctlr = i5100_csrow_to_cntlr(mci, csrow); unsigned addr_lines; /* dimm present? */ - if (!priv->mtr[chan][chan_rank].present) + if (!priv->mtr[ctlr][ctlr_rank].present) return 0ULL; addr_lines = I5100_DIMM_ADDR_LINES + - priv->mtr[chan][chan_rank].numcol + - priv->mtr[chan][chan_rank].numrow + - priv->mtr[chan][chan_rank].numbank; + priv->mtr[ctlr][ctlr_rank].numcol + + priv->mtr[ctlr][ctlr_rank].numrow + + priv->mtr[ctlr][ctlr_rank].numbank; return (unsigned long) ((unsigned long long) (1ULL << addr_lines) / PAGE_SIZE); @@ -676,11 +581,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_CHANNELS; i++) { + for (i = 0; i < I5100_MAX_CTLRS; i++) { int j; struct pci_dev *pdev = mms[i]; - for (j = 0; j < I5100_MAX_RANKS_PER_CHAN; j++) { + for (j = 0; j < I5100_MAX_RANKS_PER_CTLR; j++) { const unsigned addr = (j < 4) ? I5100_MTR_0 + j * 2 : I5100_MTR_4 + (j - 4) * 2; @@ -739,6 +644,7 @@ 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 */ @@ -747,7 +653,9 @@ static void __devinit i5100_init_dimm_csmap(struct mem_ctl_info *mci) struct i5100_priv *priv = mci->pvt_info; int i; - for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CHAN; i++) { + WARN_ON(priv->ranksperctlr != 4); + + for (i = 0; i < I5100_MAX_DIMM_SLOTS_PER_CTLR; i++) { int j; for (j = 0; j < I5100_MAX_RANKS_PER_DIMM; j++) @@ -755,21 +663,12 @@ static void __devinit i5100_init_dimm_csmap(struct mem_ctl_info *mci) } /* only 2 chip selects per slot... */ - 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; - } + 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; } static void __devinit i5100_init_dimm_layout(struct pci_dev *pdev, @@ -778,10 +677,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_CHANNELS; i++) { + for (i = 0; i < I5100_MAX_CTLRS; i++) { int j; - for (j = 0; j < I5100_MAX_DIMM_SLOTS_PER_CHAN; j++) { + for (j = 0; j < I5100_MAX_DIMM_SLOTS_PER_CTLR; j++) { u8 rank; if (i5100_read_spd_byte(mci, i, j, 5, &rank) < 0) @@ -821,7 +720,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_CHANNELS; i++) { + for (i = 0; i < I5100_MAX_CTLRS; i++) { int j; for (j = 0; j < 5; j++) { @@ -848,7 +747,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 chan = i5100_csrow_to_chan(mci, i); + const unsigned cntlr = i5100_csrow_to_cntlr(mci, i); const unsigned rank = i5100_csrow_to_rank(mci, i); if (!npages) @@ -866,7 +765,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[chan][rank].width == 4) ? DEV_X4 : DEV_X8; + (priv->mtr[cntlr][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; @@ -878,7 +777,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, chan, rank)); + "DIMM%u", i5100_rank_to_slot(mci, cntlr, rank)); total_pages += npages; } @@ -916,6 +815,13 @@ 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; @@ -958,21 +864,11 @@ static int __devinit i5100_init_one(struct pci_dev *pdev, mci->dev = &pdev->dev; priv = mci->pvt_info; - priv->ranksperchan = ranksperch; + priv->ranksperctlr = 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); @@ -986,8 +882,6 @@ 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); @@ -1003,14 +897,12 @@ static int __devinit i5100_init_one(struct pci_dev *pdev, if (edac_mc_add_mc(mci)) { ret = -ENODEV; - goto bail_scrub; + goto bail_mc; } return ret; -bail_scrub: - priv->scrub_enable = 0; - cancel_delayed_work_sync(&(priv->i5100_scrubbing)); +bail_mc: edac_mc_free(mci); bail_disable_ch1: @@ -1043,10 +935,6 @@ 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); diff --git a/trunk/drivers/gpio/Kconfig b/trunk/drivers/gpio/Kconfig index a019b49ecc9b..57ca339924ef 100644 --- a/trunk/drivers/gpio/Kconfig +++ b/trunk/drivers/gpio/Kconfig @@ -206,12 +206,6 @@ 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 diff --git a/trunk/drivers/gpio/Makefile b/trunk/drivers/gpio/Makefile index 52fe4cf734c7..270b6d7839f5 100644 --- a/trunk/drivers/gpio/Makefile +++ b/trunk/drivers/gpio/Makefile @@ -13,7 +13,6 @@ 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 diff --git a/trunk/drivers/gpio/gpiolib.c b/trunk/drivers/gpio/gpiolib.c index a25ad284a272..50de0f5750d8 100644 --- a/trunk/drivers/gpio/gpiolib.c +++ b/trunk/drivers/gpio/gpiolib.c @@ -53,7 +53,6 @@ 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 */ @@ -211,11 +210,6 @@ 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, @@ -261,7 +255,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, @@ -273,17 +267,10 @@ 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 { - int value; - - value = !!gpio_get_value_cansleep(gpio); - if (test_bit(FLAG_ACTIVE_LOW, &desc->flags)) - value = !value; - - status = sprintf(buf, "%d\n", value); - } + else + status = sprintf(buf, "%d\n", !!gpio_get_value_cansleep(gpio)); mutex_unlock(&sysfs_lock); return status; @@ -307,8 +294,6 @@ 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; } @@ -318,7 +303,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) @@ -367,11 +352,9 @@ 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 |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? - IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING; + irq_flags |= IRQF_TRIGGER_FALLING; if (test_bit(FLAG_TRIG_RISE, &gpio_flags)) - irq_flags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ? - IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING; + irq_flags |= IRQF_TRIGGER_RISING; if (!pdesc) { pdesc = kmalloc(sizeof(*pdesc), GFP_KERNEL); @@ -492,79 +475,9 @@ static ssize_t gpio_edge_store(struct device *dev, 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, }; @@ -749,12 +662,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)) { - status = sysfs_create_group(&dev->kobj, + if (direction_may_change) + status = sysfs_create_group(&dev->kobj, &gpio_attr_group); - - if (!status && direction_may_change) + else status = device_create_file(dev, - &dev_attr_direction); + &dev_attr_value); if (!status && gpio_to_irq(gpio) >= 0 && (direction_may_change @@ -831,55 +744,6 @@ int gpio_export_link(struct device *dev, const char *name, unsigned gpio) } 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 @@ -1230,7 +1094,6 @@ 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); diff --git a/trunk/drivers/gpio/langwell_gpio.c b/trunk/drivers/gpio/langwell_gpio.c index 6c0ebbdc659e..4baf3d7d0f8e 100644 --- a/trunk/drivers/gpio/langwell_gpio.c +++ b/trunk/drivers/gpio/langwell_gpio.c @@ -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 >= lnw->chip.ngpio) + if (gpio < 0 || gpio > lnw->chip.ngpio) return -EINVAL; spin_lock_irqsave(&lnw->lock, flags); if (type & IRQ_TYPE_EDGE_RISING) diff --git a/trunk/drivers/gpio/timbgpio.c b/trunk/drivers/gpio/timbgpio.c deleted file mode 100644 index a4d344ba8e5c..000000000000 --- a/trunk/drivers/gpio/timbgpio.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * 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 -#include -#include -#include -#include -#include - -#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); - diff --git a/trunk/drivers/misc/sgi-gru/gru.h b/trunk/drivers/misc/sgi-gru/gru.h index 3ad76cd18b4b..f93f03a9e6e9 100644 --- a/trunk/drivers/misc/sgi-gru/gru.h +++ b/trunk/drivers/misc/sgi-gru/gru.h @@ -53,17 +53,6 @@ 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 */ diff --git a/trunk/drivers/misc/sgi-gru/gru_instructions.h b/trunk/drivers/misc/sgi-gru/gru_instructions.h index d95587cc794c..3c9c06618e6a 100644 --- a/trunk/drivers/misc/sgi-gru/gru_instructions.h +++ b/trunk/drivers/misc/sgi-gru/gru_instructions.h @@ -34,17 +34,17 @@ extern void gru_wait_abort_proc(void *cb); #include #define __flush_cache(p) ia64_fc((unsigned long)p) /* Use volatile on IA64 to ensure ordering via st4.rel */ -#define gru_ordered_store_ulong(p, v) \ +#define gru_ordered_store_int(p, v) \ do { \ barrier(); \ - *((volatile unsigned long *)(p)) = v; /* force st.rel */ \ + *((volatile int *)(p)) = v; /* force st.rel */ \ } while (0) #elif defined(CONFIG_X86_64) #define __flush_cache(p) clflush(p) -#define gru_ordered_store_ulong(p, v) \ +#define gru_ordered_store_int(p, v) \ do { \ barrier(); \ - *(unsigned long *)p = v; \ + *(int *)p = v; \ } while (0) #else #error "Unsupported architecture" @@ -129,13 +129,8 @@ struct gru_instruction_bits { */ struct gru_instruction { /* DW 0 */ - union { - unsigned long op64; /* icmd,xtype,iaa0,ima,opc,tri0 */ - struct { - unsigned int op32; - unsigned int tri0; - }; - }; + unsigned int op32; /* icmd,xtype,iaa0,ima,opc */ + unsigned int tri0; unsigned long tri1_bufsize; /* DW 1 */ unsigned long baddr0; /* DW 2 */ unsigned long nelem; /* DW 3 */ @@ -145,7 +140,7 @@ struct gru_instruction { unsigned long avalue; /* DW 7 */ }; -/* Some shifts and masks for the low 64 bits of a GRU command */ +/* Some shifts and masks for the low 32 bits of a GRU command */ #define GRU_CB_ICMD_SHFT 0 #define GRU_CB_ICMD_MASK 0x1 #define GRU_CB_XTYPE_SHFT 8 @@ -160,10 +155,6 @@ 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 @@ -265,7 +256,6 @@ 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 @@ -274,15 +264,13 @@ 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_EXS_TLB_INVAL (1 << CBR_EXS_TLB_INVAL_BIT) +#define CBR_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 @@ -308,14 +296,12 @@ union gru_mesqhead { /* Generate the low word of a GRU instruction */ -static inline unsigned long -__opdword(unsigned char opcode, unsigned char exopc, unsigned char xtype, +static inline unsigned int +__opword(unsigned char opcode, unsigned char exopc, unsigned char xtype, unsigned char iaa0, unsigned char iaa1, - unsigned long idef2, unsigned char ima) + 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) | @@ -333,13 +319,12 @@ static inline void gru_flush_cache(void *p) } /* - * Store the lower 64 bits of the command including the "start" bit. Then + * Store the lower 32 bits of the command including the "start" bit. Then * start the instruction executing. */ -static inline void gru_start_instruction(struct gru_instruction *ins, unsigned long op64) +static inline void gru_start_instruction(struct gru_instruction *ins, int op32) { - gru_ordered_store_ulong(ins, op64); - mb(); + gru_ordered_store_int(ins, op32); gru_flush_cache(ins); } @@ -355,30 +340,6 @@ static inline void gru_start_instruction(struct gru_instruction *ins, unsigned l * - 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) @@ -387,9 +348,10 @@ 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, __opdword(OP_VLOAD, 0, xtype, IAA_RAM, 0, - (unsigned long)tri0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_VLOAD, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_vstore(void *cb, unsigned long mem_addr, @@ -400,9 +362,10 @@ 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, __opdword(OP_VSTORE, 0, xtype, IAA_RAM, 0, - tri0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_VSTORE, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_ivload(void *cb, unsigned long mem_addr, @@ -413,9 +376,10 @@ 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, __opdword(OP_IVLOAD, 0, xtype, IAA_RAM, 0, - tri0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_IVLOAD, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_ivstore(void *cb, unsigned long mem_addr, @@ -426,9 +390,10 @@ 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, __opdword(OP_IVSTORE, 0, xtype, IAA_RAM, 0, - tri0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_IVSTORE, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_vset(void *cb, unsigned long mem_addr, @@ -441,8 +406,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, __opdword(OP_VSET, 0, xtype, IAA_RAM, 0, - 0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_VSET, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_ivset(void *cb, unsigned long mem_addr, @@ -455,8 +420,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, __opdword(OP_IVSET, 0, xtype, IAA_RAM, 0, - 0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_IVSET, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_vflush(void *cb, unsigned long mem_addr, @@ -468,15 +433,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, __opdword(OP_VFLUSH, 0, xtype, IAA_RAM, 0, - 0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_VFLUSH, 0, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_nop(void *cb, int hints) { struct gru_instruction *ins = (void *)cb; - gru_start_instruction(ins, __opdword(OP_NOP, 0, 0, 0, 0, 0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_NOP, 0, 0, 0, 0, CB_IMA(hints))); } @@ -490,9 +455,10 @@ 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, __opdword(OP_BCOPY, 0, xtype, IAA_RAM, - IAA_RAM, tri0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_BCOPY, 0, xtype, IAA_RAM, + IAA_RAM, CB_IMA(hints))); } static inline void gru_bstore(void *cb, const unsigned long src, @@ -504,8 +470,9 @@ static inline void gru_bstore(void *cb, const unsigned long src, ins->baddr0 = (long)src; ins->op2_value_baddr1 = (long)dest; ins->nelem = nelem; - gru_start_instruction(ins, __opdword(OP_BSTORE, 0, xtype, 0, IAA_RAM, - tri0, CB_IMA(hints))); + ins->tri0 = tri0; + gru_start_instruction(ins, __opword(OP_BSTORE, 0, xtype, 0, IAA_RAM, + CB_IMA(hints))); } static inline void gru_gamir(void *cb, int exopc, unsigned long src, @@ -514,8 +481,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, __opdword(OP_GAMIR, exopc, xtype, IAA_RAM, 0, - 0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_GAMIR, exopc, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_gamirr(void *cb, int exopc, unsigned long src, @@ -524,8 +491,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, __opdword(OP_GAMIRR, exopc, xtype, IAA_RAM, 0, - 0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_GAMIRR, exopc, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_gamer(void *cb, int exopc, unsigned long src, @@ -538,8 +505,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, __opdword(OP_GAMER, exopc, xtype, IAA_RAM, 0, - 0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_GAMER, exopc, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_gamerr(void *cb, int exopc, unsigned long src, @@ -551,8 +518,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, __opdword(OP_GAMERR, exopc, xtype, IAA_RAM, 0, - 0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_GAMERR, exopc, xtype, IAA_RAM, 0, + CB_IMA(hints))); } static inline void gru_gamxr(void *cb, unsigned long src, @@ -562,8 +529,8 @@ static inline void gru_gamxr(void *cb, unsigned long src, ins->baddr0 = (long)src; ins->nelem = 4; - gru_start_instruction(ins, __opdword(OP_GAMXR, EOP_XR_CSWAP, XTYPE_DW, - IAA_RAM, 0, 0, CB_IMA(hints))); + gru_start_instruction(ins, __opword(OP_GAMXR, EOP_XR_CSWAP, XTYPE_DW, + IAA_RAM, 0, CB_IMA(hints))); } static inline void gru_mesq(void *cb, unsigned long queue, @@ -574,8 +541,9 @@ static inline void gru_mesq(void *cb, unsigned long queue, ins->baddr0 = (long)queue; ins->nelem = nelem; - gru_start_instruction(ins, __opdword(OP_MESQ, 0, XTYPE_CL, IAA_RAM, 0, - tri0, CB_IMA(hints))); + ins->tri0 = tri0; + gru_start_instruction(ins, __opword(OP_MESQ, 0, XTYPE_CL, IAA_RAM, 0, + CB_IMA(hints))); } static inline unsigned long gru_get_amo_value(void *cb) @@ -694,14 +662,6 @@ 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 diff --git a/trunk/drivers/misc/sgi-gru/grufault.c b/trunk/drivers/misc/sgi-gru/grufault.c index 38657cdaf54d..679e01778286 100644 --- a/trunk/drivers/misc/sgi-gru/grufault.c +++ b/trunk/drivers/misc/sgi-gru/grufault.c @@ -40,12 +40,6 @@ #include "gru_instructions.h" #include -/* 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 */ @@ -96,22 +90,19 @@ 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 = ERR_PTR(-EINVAL); + struct gru_thread_state *gts = NULL; down_write(&mm->mmap_sem); vma = gru_find_vma(vaddr); - if (!vma) - goto err; - - gts = gru_alloc_thread_state(vma, TSID(vaddr, vma)); - if (IS_ERR(gts)) - goto err; - mutex_lock(>s->ts_ctxlock); - downgrade_write(&mm->mmap_sem); - return gts; + if (vma) + gts = gru_alloc_thread_state(vma, TSID(vaddr, vma)); + if (gts) { + mutex_lock(>s->ts_ctxlock); + downgrade_write(&mm->mmap_sem); + } else { + up_write(&mm->mmap_sem); + } -err: - up_write(&mm->mmap_sem); return gts; } @@ -131,14 +122,38 @@ 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(struct gru_instruction_bits *cbk) +static void gru_cb_set_istatus_active(unsigned long __user *cb) { - if (cbk) { - cbk->istatus = CBS_ACTIVE; + 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); } } +/* + * 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 * @@ -192,11 +207,10 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma, { struct page *page; -#ifdef CONFIG_HUGETLB_PAGE - *pageshift = is_vm_hugetlb_page(vma) ? HPAGE_SHIFT : PAGE_SHIFT; -#else + /* ZZZ Need to handle HUGE pages */ + if (is_vm_hugetlb_page(vma)) + return -EFAULT; *pageshift = PAGE_SHIFT; -#endif if (get_user_pages (current, current->mm, vaddr, 1, write, 0, &page, NULL) <= 0) return -EFAULT; @@ -254,6 +268,7 @@ static int atomic_pte_lookup(struct vm_area_struct *vma, unsigned long vaddr, return 0; err: + local_irq_enable(); return 1; } @@ -286,69 +301,14 @@ 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 VTOP_SUCCESS; + return 0; inval: - return VTOP_INVALID; + return -1; upm: - 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); - } + return -2; } -/* - * Preload the TLB with entries that may be required. Currently, preloading - * is implemented only for BCOPY. Preload 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. @@ -360,14 +320,11 @@ static void gru_preload_tlb(struct gru_state *gru, * < 0 = error code * */ -static int gru_try_dropin(struct gru_state *gru, - struct gru_thread_state *gts, +static int gru_try_dropin(struct gru_thread_state *gts, struct gru_tlb_fault_handle *tfh, - struct gru_instruction_bits *cbk) + unsigned long __user *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; + int pageshift = 0, asid, write, ret, atomic = !cb; unsigned long gpa = 0, vaddr = 0; /* @@ -377,14 +334,6 @@ static int gru_try_dropin(struct gru_state *gru, * 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 @@ -392,20 +341,18 @@ static int gru_try_dropin(struct gru_state *gru, */ 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 && cbk) + if (tfh->state == TFHSTATE_MISS_FMM && cb) goto failfmm; write = (tfh->cause & TFHCAUSE_TLB_MOD) != 0; vaddr = tfh->missvaddr; asid = tfh->missasid; - indexway = tfh->indexway; if (asid == 0) goto failnoasid; @@ -419,51 +366,41 @@ static int gru_try_dropin(struct gru_state *gru, goto failactive; ret = gru_vtop(gts, vaddr, write, atomic, &gpa, &pageshift); - if (ret == VTOP_INVALID) + if (ret == -1) goto failinval; - if (ret == VTOP_RETRY) + if (ret == -2) goto failupm; if (!(gts->ts_sizeavail & GRU_SIZEAVAIL(pageshift))) { gts->ts_sizeavail |= GRU_SIZEAVAIL(pageshift); - if (atomic || !gru_update_cch(gts)) { + if (atomic || !gru_update_cch(gts, 0)) { gts->ts_force_cch_reload = 1; goto failupm; } } - - 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++; + gru_cb_set_istatus_active(cb); tfh_write_restart(tfh, gpa, GAA_RAM, vaddr, asid, write, GRU_PAGESIZE(pageshift)); - gru_dbg(grudev, - "%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); + 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); 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 (!cbk) + if (!cb) 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; @@ -471,7 +408,6 @@ static int gru_try_dropin(struct gru_state *gru, 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; @@ -479,20 +415,17 @@ static int gru_try_dropin(struct gru_state *gru, failnoexception: /* TFH status did not show exception pending */ gru_flush_cache(tfh); - gru_flush_cache_cbe(cbe); - if (cbk) - gru_flush_cache(cbk); + if (cb) + gru_flush_cache(cb); 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); - gru_flush_cache_cbe(cbe); - if (cbk) - gru_flush_cache(cbk); + if (cb) + gru_flush_cache(cb); STAT(tlb_dropin_fail_idle); gru_dbg(grudev, "FAILED idle tfh: 0x%p, state %d\n", tfh, tfh->state); return 0; @@ -500,18 +433,16 @@ static int gru_try_dropin(struct gru_state *gru, 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 (!cbk) + if (!cb) 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); @@ -524,41 +455,31 @@ static int gru_try_dropin(struct gru_state *gru, * Note that this is the interrupt handler that is registered with linux * interrupt handlers. */ -static irqreturn_t gru_intr(int chiplet, int blade) +irqreturn_t gru_intr(int irq, void *dev_id) { 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 = &gru_base[blade]->bs_grus[chiplet]; + gru = irq_to_gru(irq); if (!gru) { - dev_err(grudev, "GRU: invalid interrupt: cpu %d, chiplet %d\n", - raw_smp_processor_id(), chiplet); + dev_err(grudev, "GRU: invalid interrupt: cpu %d, irq %d\n", + raw_smp_processor_id(), irq); 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) { - STAT(intr_cbr); - cmp = gru->gs_blade->bs_async_wq; - if (cmp) - complete(cmp); + complete(gru->gs_blade->bs_async_wq); gru_dbg(grudev, "gid %d, cbr_done %d, done %d\n", - gru->gs_gid, cbrnum, cmp ? cmp->done : -1); + gru->gs_gid, cbrnum, gru->gs_blade->bs_async_wq->done); } 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 */ @@ -571,20 +492,14 @@ static irqreturn_t gru_intr(int chiplet, int blade) 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(>s->ts_mm->mmap_sem)) { - gru_try_dropin(gru, gts, tfh, NULL); + gts->ustats.fmm_tlbdropin++; + gru_try_dropin(gts, tfh, NULL); up_read(>s->ts_mm->mmap_sem); } else { tfh_user_polling_mode(tfh); @@ -594,43 +509,20 @@ static irqreturn_t gru_intr(int chiplet, int blade) 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, - void *cb) + unsigned long __user *cb) { struct gru_mm_struct *gms = gts->ts_gms; int ret; - gts->ustats.upm_tlbmiss++; + gts->ustats.upm_tlbdropin++; 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->ts_gru, gts, tfh, cb); + ret = gru_try_dropin(gts, tfh, cb); if (ret <= 0) return ret; STAT(call_os_wait_queue); @@ -646,41 +538,52 @@ int gru_handle_user_call_os(unsigned long cb) { struct gru_tlb_fault_handle *tfh; struct gru_thread_state *gts; - void *cbk; + unsigned long __user *cbp; 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; - gru_check_context_placement(gts); + /* + * 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; + } /* * 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); + gru_update_cch(gts, 0); } ret = -EAGAIN; cbrnum = thread_cbr_number(gts, ucbnum); - if (gts->ts_gru) { + if (gts->ts_force_unload) { + gru_unload_context(gts, 1); + } else if (gts->ts_gru) { tfh = get_tfh_by_index(gts->ts_gru, cbrnum); - cbk = get_gseg_base_address_cb(gts->ts_gru->gs_gru_base_vaddr, - gts->ts_ctxnum, ucbnum); - ret = gru_user_dropin(gts, tfh, cbk); + ret = gru_user_dropin(gts, tfh, cbp); } exit: gru_unlock_gts(gts); @@ -702,11 +605,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; @@ -714,7 +617,6 @@ 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; @@ -722,7 +624,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(cbe); + gru_flush_cache(cbe); ret = 0; } else { ret = -EAGAIN; @@ -831,11 +733,6 @@ 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, >s->ustats, sizeof(gts->ustats)); @@ -865,25 +762,11 @@ 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_find_lock_gts(req.gseg); - if (!gts) { - gts = gru_alloc_locked_gts(req.gseg); - if (IS_ERR(gts)) - return PTR_ERR(gts); - } + gts = gru_alloc_locked_gts(req.gseg); + if (!gts) + return -EINVAL; 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; diff --git a/trunk/drivers/misc/sgi-gru/grufile.c b/trunk/drivers/misc/sgi-gru/grufile.c index cb3b4d228475..ce5eda985ab0 100644 --- a/trunk/drivers/misc/sgi-gru/grufile.c +++ b/trunk/drivers/misc/sgi-gru/grufile.c @@ -35,9 +35,6 @@ #include #include #include -#ifdef CONFIG_X86_64 -#include -#endif #include #include "gru.h" #include "grulib.h" @@ -133,6 +130,7 @@ 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; @@ -152,7 +150,6 @@ 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(¤t->mm->mmap_sem); @@ -193,7 +190,7 @@ static long gru_file_unlocked_ioctl(struct file *file, unsigned int req, { int err = -EBADRQC; - gru_dbg(grudev, "file %p, req 0x%x, 0x%lx\n", file, req, arg); + gru_dbg(grudev, "file %p\n", file); switch (req) { case GRU_CREATE_CONTEXT: @@ -235,24 +232,23 @@ 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 blade_id, int chiplet_id) + void *vaddr, int nid, int bid, int grunum) { 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 = 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_gid = bid * GRU_CHIPLETS_PER_BLADE + grunum; + gru->gs_blade = gru_base[bid]; + gru->gs_blade_id = bid; 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, gid %d, vaddr %p (0x%lx)\n", - blade_id, gru->gs_gid, gru->gs_gru_base_vaddr, + 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->gs_gru_base_paddr); } @@ -268,10 +264,12 @@ 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_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); + 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); if (!page) goto fail; gru_base[bid] = page_address(page); @@ -287,7 +285,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, bid, chip); + gru_init_chiplet(gru, paddr, vaddr, nid, 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; @@ -300,214 +298,38 @@ static int gru_init_tables(unsigned long gru_base_paddr, void *gru_base_vaddr) return 0; fail: - for (bid--; bid >= 0; bid--) - free_pages((unsigned long)gru_base[bid], order); + for (nid--; nid >= 0; nid--) + free_pages((unsigned long)gru_base[nid], order); return -ENOMEM; } -static void gru_free_tables(void) -{ - int bid; - int order = get_order(sizeof(struct gru_state) * - GRU_CHIPLETS_PER_BLADE); - - 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) -{ - 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; -} - #ifdef CONFIG_IA64 -static int gru_irq_count[GRU_CHIPLETS_PER_BLADE]; - -static void gru_noop(unsigned int irq) -{ -} - -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 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) +static int get_base_irq(void) { - 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); + return IRQ_GRU; } #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) +static void noop(unsigned int irq) { - 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 struct irq_chip gru_chip = { + .name = "gru", + .mask = noop, + .unmask = noop, + .ack = noop, +}; -static int gru_setup_tlb_irqs(void) +static int get_base_irq(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; + set_irq_chip(IRQ_GRU, &gru_chip); + set_irq_chip(IRQ_GRU + 1, &gru_chip); + return IRQ_GRU; } +#endif /* * gru_init @@ -516,7 +338,8 @@ static int gru_setup_tlb_irqs(void) */ static int __init gru_init(void) { - int ret; + int ret, irq, chip; + char id[10]; if (!is_uv_system()) return 0; @@ -531,29 +354,41 @@ 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 exit0; + goto exit1; } ret = gru_proc_init(); if (ret) { printk(KERN_ERR "%s: proc init failed\n", GRU_DRIVER_ID_STR); - goto exit1; + goto exit2; } 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 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, @@ -561,24 +396,31 @@ static int __init gru_init(void) return 0; exit3: - gru_free_tables(); -exit2: gru_proc_exit(); -exit1: +exit2: misc_deregister(&gru_miscdev); -exit0: +exit1: + for (--chip; chip >= 0; chip--) + free_irq(irq + chip, NULL); 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; - gru_teardown_tlb_irqs(); + for (i = 0; i < GRU_CHIPLETS_PER_BLADE; i++) + free_irq(IRQ_GRU + i, NULL); gru_kservices_exit(); - gru_free_tables(); + for (bid = 0; bid < GRU_MAX_BLADES; bid++) + free_pages((unsigned long)gru_base[bid], order); + misc_deregister(&gru_miscdev); gru_proc_exit(); } diff --git a/trunk/drivers/misc/sgi-gru/gruhandles.c b/trunk/drivers/misc/sgi-gru/gruhandles.c index 2f30badc6ffd..37e7cfc53b9c 100644 --- a/trunk/drivers/misc/sgi-gru/gruhandles.c +++ b/trunk/drivers/misc/sgi-gru/gruhandles.c @@ -27,11 +27,9 @@ #ifdef CONFIG_IA64 #include #define GRU_OPERATION_TIMEOUT (((cycles_t) local_cpu_data->itc_freq)*10) -#define CLKS2NSEC(c) ((c) *1000000000 / local_cpu_data->itc_freq) #else #include #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 */ @@ -41,39 +39,21 @@ 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(nsec, &mcs_op_statistics[op].total); - if (mcs_op_statistics[op].max < nsec) - mcs_op_statistics[op].max = nsec; + atomic_long_add(clks, &mcs_op_statistics[op].total); + if (mcs_op_statistics[op].max < clks) + mcs_op_statistics[op].max = clks; } static void start_instruction(void *h) { unsigned long *w0 = h; - wmb(); /* setting CMD/STATUS bits must be last */ - *w0 = *w0 | 0x20001; + wmb(); /* setting CMD bit must be last */ + *w0 = *w0 | 1; 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; @@ -84,10 +64,9 @@ 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)) { - report_instruction_timeout(h); - start_time = get_cycles(); - } + 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_options & OPT_STATS) update_mcs_stats(opc, get_cycles() - start_time); @@ -96,18 +75,9 @@ 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); - 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; + return wait_instruction_complete(cch, cchop_allocate); } int cch_start(struct gru_context_configuration_handle *cch) @@ -126,18 +96,9 @@ 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); - ret = wait_instruction_complete(cch, cchop_deallocate); - - /* - * Stop speculation into the GSEG being unmapped by the previous - * DEALLOCATE. - */ - sync_core(); - return ret; + return wait_instruction_complete(cch, cchop_deallocate); } int cch_interrupt_sync(struct gru_context_configuration_handle @@ -165,20 +126,17 @@ int tgh_invalidate(struct gru_tlb_global_handle *tgh, return wait_instruction_complete(tgh, tghop_invalidate); } -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_only(struct gru_tlb_fault_handle *tfh, + unsigned long pfn, unsigned long vaddr, + int asid, int dirty, int pagesize) { tfh->fillasid = asid; tfh->fillvaddr = vaddr; - tfh->pfn = paddr >> GRU_PADDR_SHIFT; - tfh->gaa = gaa; + tfh->pfn = pfn; 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, diff --git a/trunk/drivers/misc/sgi-gru/gruhandles.h b/trunk/drivers/misc/sgi-gru/gruhandles.h index 3f998b924d8f..f44112242d00 100644 --- a/trunk/drivers/misc/sgi-gru/gruhandles.h +++ b/trunk/drivers/misc/sgi-gru/gruhandles.h @@ -91,12 +91,6 @@ /* 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) { @@ -164,16 +158,6 @@ 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; -} - - /* @@ -252,17 +236,6 @@ 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. @@ -467,12 +440,6 @@ 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, @@ -520,8 +487,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); -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_only(struct gru_tlb_fault_handle *tfh, unsigned long pfn, + 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); diff --git a/trunk/drivers/misc/sgi-gru/grukdump.c b/trunk/drivers/misc/sgi-gru/grukdump.c index 9b2062d17327..55eabfa85585 100644 --- a/trunk/drivers/misc/sgi-gru/grukdump.c +++ b/trunk/drivers/misc/sgi-gru/grukdump.c @@ -44,8 +44,7 @@ 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, - int flush_cbrs) + void __user *ubuf, int ctxnum, int dsrcnt) { void *cb, *cbe, *tfh, *gseg; int i, scr; @@ -56,8 +55,6 @@ 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)) @@ -118,7 +115,7 @@ static int gru_dump_tgh(struct gru_state *gru, static int gru_dump_context(struct gru_state *gru, int ctxnum, void __user *ubuf, void __user *ubufend, char data_opt, - char lock_cch, char flush_cbrs) + char lock_cch) { struct gru_dump_context_header hdr; struct gru_dump_context_header __user *uhdr = ubuf; @@ -162,7 +159,8 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum, ret = -EFBIG; else ret = gru_dump_context_data(grubase, cch, ubuf, ctxnum, - dsrcnt, flush_cbrs); + dsrcnt); + } if (cch_locked) unlock_cch_handle(cch); @@ -217,8 +215,7 @@ 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.flush_cbrs); + req.data_opt, req.lock_cch); if (ret < 0) goto fail; ubuf += ret; diff --git a/trunk/drivers/misc/sgi-gru/grukservices.c b/trunk/drivers/misc/sgi-gru/grukservices.c index 34749ee88dfa..766e21e15574 100644 --- a/trunk/drivers/misc/sgi-gru/grukservices.c +++ b/trunk/drivers/misc/sgi-gru/grukservices.c @@ -31,7 +31,6 @@ #include #include #include -#include #include "gru.h" #include "grulib.h" #include "grutables.h" @@ -98,6 +97,9 @@ #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 @@ -158,10 +160,8 @@ 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, 0); - bs->bs_kgts->ts_user_blade_id = blade_id; - } + if (!bs->bs_kgts) + bs->bs_kgts = gru_alloc_gts(NULL, 0, 0, 0, 0); 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)) { + while (!gru_assign_gru_context(kgts, blade_id)) { msleep(1); - gru_steal_context(kgts); + gru_steal_context(kgts, blade_id); } gru_load_context(kgts); gru = bs->bs_kgts->ts_gru; @@ -200,15 +200,13 @@ 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++; } @@ -222,21 +220,13 @@ 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); -again: - bid = blade_id < 0 ? uv_numa_blade_id() : blade_id; - bs = gru_base[bid]; + bs = gru_base[blade_id]; - /* 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, bid); + gru_load_kernel_context(bs, blade_id); return bs; } @@ -265,7 +255,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(-1); + bs = gru_lock_kernel_context(uv_numa_blade_id()); lcpu = uv_blade_processor_id(); *cb = bs->kernel_cb + lcpu * GRU_HANDLE_STRIDE; *dsr = bs->kernel_dsr + lcpu * GRU_NUM_KERNEL_DSR_BYTES; @@ -394,31 +384,13 @@ int gru_get_cb_exception_detail(void *cb, struct control_block_extended_exc_detail *excdet) { struct gru_control_block_extended *cbe; - 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)); + struct gru_blade_state *bs; + int cbrnum; + + bs = KCB_TO_BS(cb); + cbrnum = thread_cbr_number(bs->bs_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; @@ -437,8 +409,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:%d exception: cb %p, opc %d, exopc %d, ecause 0x%x," - "excdet0 0x%lx, excdet1 0x%x", smp_processor_id(), + "GRU exception: cb %p, opc %d, exopc %d, ecause 0x%x," + "excdet0 0x%lx, excdet1 0x%x", gen, excdet.opc, excdet.exopc, excdet.ecause, excdet.exceptdet0, excdet.exceptdet1); } else { @@ -485,10 +457,9 @@ int gru_check_status_proc(void *cb) int ret; ret = gen->istatus; - if (ret == CBS_EXCEPTION) - ret = gru_retry_exception(cb); - rmb(); - return ret; + if (ret != CBS_EXCEPTION) + return ret; + return gru_retry_exception(cb); } @@ -500,7 +471,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; } @@ -567,7 +538,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 = nasid >> 1; + mqd->interrupt_pnode = UV_NASID_TO_PNODE(nasid); mqd->interrupt_vector = vector; mqd->interrupt_apicid = apicid; return 0; @@ -627,8 +598,6 @@ 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(); } @@ -703,6 +672,18 @@ static int send_message_queue_full(void *cb, struct gru_message_queue_desc *mqd, 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 @@ -712,8 +693,7 @@ static int send_message_queue_full(void *cb, 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, *val = mesg, gpa, save; - int ret; + unsigned long m; m = mqd->mq_gpa + (gru_get_amo_value_head(cb) << 6); if (lines == 2) { @@ -724,26 +704,7 @@ 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; - - 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; + send_message_queue_interrupt(mqd); return MQE_OK; } @@ -778,9 +739,6 @@ 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(); } @@ -873,6 +831,7 @@ 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; @@ -892,36 +851,12 @@ 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 */ @@ -963,24 +898,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:%d quicktest0: CBR failure 1\n", smp_processor_id()); + printk(KERN_DEBUG "GRU quicktest0: CBR failure 1\n"); goto done; } if (*p != MAGIC) { - printk(KERN_DEBUG "GRU:%d quicktest0 bad magic 0x%lx\n", smp_processor_id(), *p); + printk(KERN_DEBUG "GRU: quicktest0 bad magic 0x%lx\n", *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:%d quicktest0: CBR failure 2\n", smp_processor_id()); + printk(KERN_DEBUG "GRU quicktest0: CBR failure 2\n"); goto done; } if (word0 != word1 || word1 != MAGIC) { printk(KERN_DEBUG - "GRU:%d quicktest0 err: found 0x%lx, expected 0x%lx\n", - smp_processor_id(), word1, MAGIC); + "GRU quicktest0 err: found 0x%lx, expected 0x%lx\n", + word1, MAGIC); goto done; } ret = 0; @@ -1017,11 +952,8 @@ static int quicktest1(unsigned long arg) if (ret) break; } - if (ret != MQE_QUEUE_FULL || i != 4) { - printk(KERN_DEBUG "GRU:%d quicktest1: unexpect status %d, i %d\n", - smp_processor_id(), ret, i); + if (ret != MQE_QUEUE_FULL || i != 4) goto done; - } for (i = 0; i < 6; i++) { m = gru_get_next_message(&mqd); @@ -1029,12 +961,7 @@ static int quicktest1(unsigned long arg) break; gru_free_message(&mqd, m); } - 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; + ret = (i == 4) ? 0 : -EIO; done: kfree(p); @@ -1050,7 +977,6 @@ 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; @@ -1070,30 +996,20 @@ static int quicktest2(unsigned long arg) XTYPE_DW, 4, 1, IMA_INTERRUPT); ret = 0; - k = numcb; - do { + for (k = 0; k < numcb; k++) { 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 && istatus != CBS_CALL_OS) - break; + 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 (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); @@ -1103,22 +1019,6 @@ static int quicktest2(unsigned long arg) 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. @@ -1137,9 +1037,6 @@ 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; diff --git a/trunk/drivers/misc/sgi-gru/grukservices.h b/trunk/drivers/misc/sgi-gru/grukservices.h index 02aa94d8484a..d60d34bca44d 100644 --- a/trunk/drivers/misc/sgi-gru/grukservices.h +++ b/trunk/drivers/misc/sgi-gru/grukservices.h @@ -130,20 +130,6 @@ 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. diff --git a/trunk/drivers/misc/sgi-gru/grulib.h b/trunk/drivers/misc/sgi-gru/grulib.h index e77d1b1f9d05..889bc442a3e8 100644 --- a/trunk/drivers/misc/sgi-gru/grulib.h +++ b/trunk/drivers/misc/sgi-gru/grulib.h @@ -63,9 +63,18 @@ #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 gru_gseg_statistics stats; + unsigned long gseg; + struct gts_statistics stats; }; /* @@ -77,7 +86,6 @@ struct gru_create_context_req { unsigned int control_blocks; unsigned int maximum_thread_count; unsigned int options; - unsigned char tlb_preload_count; }; /* @@ -90,12 +98,11 @@ struct gru_unload_context_req { /* * Structure used to set context options */ -enum {sco_gseg_owner, sco_cch_req_slice, sco_blade_chiplet}; +enum {sco_gseg_owner, sco_cch_req_slice}; struct gru_set_context_option_req { unsigned long gseg; int op; - int val0; - long val1; + unsigned long val1; }; /* @@ -117,8 +124,6 @@ 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; diff --git a/trunk/drivers/misc/sgi-gru/grumain.c b/trunk/drivers/misc/sgi-gru/grumain.c index f8538bbd0bfa..3bc643dad606 100644 --- a/trunk/drivers/misc/sgi-gru/grumain.c +++ b/trunk/drivers/misc/sgi-gru/grumain.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include "gru.h" #include "grutables.h" @@ -49,20 +48,12 @@ 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 ------------------------------------------- @@ -295,8 +286,7 @@ static void gru_unload_mm_tracker(struct gru_state *gru, void gts_drop(struct gru_thread_state *gts) { if (gts && atomic_dec_return(>s->ts_refcnt) == 0) { - if (gts->ts_gms) - gru_drop_mmu_notifier(gts->ts_gms); + gru_drop_mmu_notifier(gts->ts_gms); kfree(gts); STAT(gts_free); } @@ -320,18 +310,16 @@ 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, - unsigned char tlb_preload_count, int options, int tsid) + int cbr_au_count, int dsr_au_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 ERR_PTR(-ENOMEM); + return NULL; STAT(gts_alloc); memset(gts, 0, sizeof(struct gru_thread_state)); /* zero out header */ @@ -339,10 +327,7 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, mutex_init(>s->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; @@ -351,10 +336,9 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, if (vma) { gts->ts_mm = current->mm; gts->ts_vma = vma; - gms = gru_register_mmu_notifier(); - if (IS_ERR(gms)) + gts->ts_gms = gru_register_mmu_notifier(); + if (!gts->ts_gms) goto err; - gts->ts_gms = gms; } gru_dbg(grudev, "alloc gts %p\n", gts); @@ -362,7 +346,7 @@ struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, err: gts_drop(gts); - return ERR_CAST(gms); + return NULL; } /* @@ -376,7 +360,6 @@ 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); @@ -409,12 +392,10 @@ 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, - vdata->vd_tlb_preload_count, + gts = gru_alloc_gts(vma, vdata->vd_cbr_au_count, vdata->vd_dsr_au_count, vdata->vd_user_options, tsid); - if (IS_ERR(gts)) - return gts; + if (!gts) + return NULL; spin_lock(&vdata->vd_lock); ngts = gru_find_current_gts_nolock(vdata, tsid); @@ -512,9 +493,6 @@ 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; } @@ -535,12 +513,6 @@ 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) { @@ -561,8 +533,7 @@ 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, cbrmap 0x%lx, dsrmap 0x%lx\n", - gts, gts->ts_cbr_map, gts->ts_dsr_map); + gru_dbg(grudev, "gts %p\n", gts); lock_cch_handle(cch); if (cch_interrupt_sync(cch)) BUG(); @@ -578,6 +549,7 @@ 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); @@ -593,7 +565,9 @@ 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 @@ -617,7 +591,6 @@ 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; @@ -643,18 +616,17 @@ 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 gru_update_cch(struct gru_thread_state *gts, int force_unload) { struct gru_context_configuration_handle *cch; struct gru_state *gru = gts->ts_gru; @@ -668,13 +640,21 @@ int gru_update_cch(struct gru_thread_state *gts) goto exit; if (cch_interrupt(cch)) BUG(); - 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 (!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; + } if (cch_start(cch)) BUG(); ret = 1; @@ -699,54 +679,7 @@ 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); -} - -/* - * 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); - } + return gru_update_cch(gts, 0); } @@ -779,17 +712,13 @@ static void gts_stolen(struct gru_thread_state *gts, } } -void gru_steal_context(struct gru_thread_state *gts) +void gru_steal_context(struct gru_thread_state *gts, int blade_id) { 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; @@ -800,39 +729,35 @@ void gru_steal_context(struct gru_thread_state *gts) 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 (gru_check_chiplet_assignment(gru, gts)) { - if (check_gru_resources(gru, cbr, dsr, GRU_NUM_CCH)) + 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) break; - 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)) + 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; + flag = 1; } - if (flag && gru == gru0) + spin_unlock(&gru->gs_lock); + if (ngts || (flag && gru == gru0 && ctxnum == ctxnum0)) 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) { @@ -850,35 +775,20 @@ void gru_steal_context(struct gru_thread_state *gts) 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) +struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts, + int blade) { 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_id, i) { - if (!gru_check_chiplet_assignment(grux, gts)) - continue; + for_each_gru_on_blade(grux, blade, i) { if (check_gru_resources(grux, gts->ts_cbr_au_count, gts->ts_dsr_au_count, max_active_contexts)) { @@ -899,9 +809,12 @@ struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts) reserve_gru_resources(gru, gts); gts->ts_gru = gru; gts->ts_blade = gru->gs_blade_id; - gts->ts_ctxnum = gru_assign_context_number(gru); + gts->ts_ctxnum = + find_first_zero_bit(&gru->gs_context_map, GRU_NUM_CCH); + BUG_ON(gts->ts_ctxnum == GRU_NUM_CCH); atomic_inc(>s->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); @@ -929,6 +842,7 @@ 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", @@ -943,18 +857,28 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) again: mutex_lock(>s->ts_ctxlock); preempt_disable(); + blade_id = uv_numa_blade_id(); - gru_check_context_placement(gts); + 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); + } + } if (!gts->ts_gru) { STAT(load_user_context); - if (!gru_assign_gru_context(gts)) { + if (!gru_assign_gru_context(gts, blade_id)) { preempt_enable(); mutex_unlock(>s->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); + gru_steal_context(gts, blade_id); goto again; } gru_load_context(gts); diff --git a/trunk/drivers/misc/sgi-gru/gruprocfs.c b/trunk/drivers/misc/sgi-gru/gruprocfs.c index 7768b87d995b..3f2375c5ba5b 100644 --- a/trunk/drivers/misc/sgi-gru/gruprocfs.c +++ b/trunk/drivers/misc/sgi-gru/gruprocfs.c @@ -36,7 +36,8 @@ static void printstat_val(struct seq_file *s, atomic_long_t *v, char *id) { unsigned long val = atomic_long_read(v); - seq_printf(s, "%16lu %s\n", val, id); + if (val) + seq_printf(s, "%16lu %s\n", val, id); } static int statistics_show(struct seq_file *s, void *p) @@ -45,8 +46,7 @@ static int statistics_show(struct seq_file *s, void *p) printstat(s, vdata_free); printstat(s, gts_alloc); printstat(s, gts_free); - printstat(s, gms_alloc); - printstat(s, gms_free); + printstat(s, vdata_double_alloc); printstat(s, gts_double_allocate); printstat(s, assign_context); printstat(s, assign_context_failed); @@ -59,25 +59,28 @@ 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, check_context_retarget_intr); - printstat(s, check_context_unload); + 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, 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); @@ -85,15 +88,16 @@ 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); @@ -104,6 +108,7 @@ 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); @@ -113,7 +118,6 @@ 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; } @@ -129,10 +133,8 @@ 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", "tfh_write_only", - "tfh_write_restart", "tgh_invalidate"}; + "cch_interrupt_sync", "cch_deallocate", "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); @@ -152,7 +154,6 @@ 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; } @@ -182,17 +183,16 @@ 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%7s%9s%6s%8s%8s\n", "gid", "bid", - "ctx#", "asid", "pid", "cbrs", "dsbytes", "mode"); + seq_printf(file, "#%5s%5s%6s%9s%6s%8s%8s\n", "gid", "bid", + "ctx#", "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%7d%9d%6d%8d%8s\n", + seq_printf(file, " %5d%5d%6d%9d%6d%8d%8s\n", gru->gs_gid, gru->gs_blade_id, i, - is_kernel_context(ts) ? 0 : ts->ts_gms->ms_asids[gid].mt_asid, - is_kernel_context(ts) ? 0 : ts->ts_tgid_owner, + 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", proc_gru->parent); + remove_proc_entry("gru", NULL); } } diff --git a/trunk/drivers/misc/sgi-gru/grutables.h b/trunk/drivers/misc/sgi-gru/grutables.h index 02a77b8b8eef..46990bcfa536 100644 --- a/trunk/drivers/misc/sgi-gru/grutables.h +++ b/trunk/drivers/misc/sgi-gru/grutables.h @@ -161,7 +161,7 @@ extern unsigned int gru_max_gids; #define GRU_MAX_GRUS (GRU_MAX_BLADES * GRU_CHIPLETS_PER_BLADE) #define GRU_DRIVER_ID_STR "SGI GRU Device Driver" -#define GRU_DRIVER_VERSION_STR "0.85" +#define GRU_DRIVER_VERSION_STR "0.80" /* * GRU statistics. @@ -171,8 +171,7 @@ struct gru_stats_s { atomic_long_t vdata_free; atomic_long_t gts_alloc; atomic_long_t gts_free; - atomic_long_t gms_alloc; - atomic_long_t gms_free; + atomic_long_t vdata_double_alloc; atomic_long_t gts_double_allocate; atomic_long_t assign_context; atomic_long_t assign_context_failed; @@ -185,25 +184,28 @@ struct gru_stats_s { atomic_long_t steal_kernel_context; atomic_long_t steal_context_failed; atomic_long_t nopfn; + atomic_long_t break_cow; atomic_long_t asid_new; atomic_long_t asid_next; atomic_long_t asid_wrap; atomic_long_t asid_reuse; atomic_long_t intr; - atomic_long_t intr_cbr; - atomic_long_t intr_tfh; - atomic_long_t intr_spurious; atomic_long_t intr_mm_lock_failed; atomic_long_t call_os; + atomic_long_t call_os_offnode_reference; + atomic_long_t call_os_check_for_bug; atomic_long_t call_os_wait_queue; atomic_long_t user_flush_tlb; atomic_long_t user_unload_context; atomic_long_t user_exception; atomic_long_t set_context_option; - atomic_long_t check_context_retarget_intr; - atomic_long_t check_context_unload; + atomic_long_t migrate_check; + atomic_long_t migrated_retarget; + atomic_long_t migrated_unload; + atomic_long_t migrated_unload_delay; + atomic_long_t migrated_nopfn_retarget; + atomic_long_t migrated_nopfn_unload; atomic_long_t tlb_dropin; - atomic_long_t tlb_preload_page; atomic_long_t tlb_dropin_fail_no_asid; atomic_long_t tlb_dropin_fail_upm; atomic_long_t tlb_dropin_fail_invalid; @@ -211,16 +213,17 @@ struct gru_stats_s { atomic_long_t tlb_dropin_fail_idle; atomic_long_t tlb_dropin_fail_fmm; atomic_long_t tlb_dropin_fail_no_exception; + atomic_long_t tlb_dropin_fail_no_exception_war; atomic_long_t tfh_stale_on_fault; atomic_long_t mmu_invalidate_range; atomic_long_t mmu_invalidate_page; + atomic_long_t mmu_clear_flush_young; atomic_long_t flush_tlb; atomic_long_t flush_tlb_gru; atomic_long_t flush_tlb_gru_tgh; atomic_long_t flush_tlb_gru_zero_asid; atomic_long_t copy_gpa; - atomic_long_t read_gpa; atomic_long_t mesq_receive; atomic_long_t mesq_receive_none; @@ -232,7 +235,7 @@ struct gru_stats_s { atomic_long_t mesq_send_qlimit_reached; atomic_long_t mesq_send_amo_nacked; atomic_long_t mesq_send_put_nacked; - atomic_long_t mesq_page_overflow; + atomic_long_t mesq_qf_not_full; atomic_long_t mesq_qf_locked; atomic_long_t mesq_qf_noop_not_full; atomic_long_t mesq_qf_switch_head_failed; @@ -242,13 +245,11 @@ struct gru_stats_s { atomic_long_t mesq_noop_qlimit_reached; atomic_long_t mesq_noop_amo_nacked; atomic_long_t mesq_noop_put_nacked; - atomic_long_t mesq_noop_page_overflow; }; enum mcs_op {cchop_allocate, cchop_start, cchop_interrupt, cchop_interrupt_sync, - cchop_deallocate, tfhop_write_only, tfhop_write_restart, - tghop_invalidate, mcsop_last}; + cchop_deallocate, tghop_invalidate, mcsop_last}; struct mcs_op_statistic { atomic_long_t count; @@ -258,8 +259,8 @@ struct mcs_op_statistic { extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; -#define OPT_DPRINT 1 -#define OPT_STATS 2 +#define OPT_DPRINT 1 +#define OPT_STATS 2 #define IRQ_GRU 110 /* Starting IRQ number for interrupts */ @@ -282,7 +283,7 @@ extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; #define gru_dbg(dev, fmt, x...) \ do { \ if (gru_options & OPT_DPRINT) \ - printk(KERN_DEBUG "GRU:%d %s: " fmt, smp_processor_id(), __func__, x);\ + dev_dbg(dev, "%s: " fmt, __func__, x); \ } while (0) #else #define gru_dbg(x...) @@ -296,7 +297,13 @@ extern struct mcs_op_statistic mcs_op_statistics[mcsop_last]; #define ASID_INC 8 /* number of regions */ /* Generate a GRU asid value from a GRU base asid & a virtual address. */ +#if defined CONFIG_IA64 #define VADDR_HI_BIT 64 +#elif defined CONFIG_X86_64 +#define VADDR_HI_BIT 48 +#else +#error "Unsupported architecture" +#endif #define GRUREGION(addr) ((addr) >> (VADDR_HI_BIT - 3) & 3) #define GRUASID(asid, addr) ((asid) + GRUREGION(addr)) @@ -338,7 +345,6 @@ struct gru_vma_data { long vd_user_options;/* misc user option flags */ int vd_cbr_au_count; int vd_dsr_au_count; - unsigned char vd_tlb_preload_count; }; /* @@ -354,7 +360,6 @@ struct gru_thread_state { struct gru_state *ts_gru; /* GRU where the context is loaded */ struct gru_mm_struct *ts_gms; /* asid & ioproc struct */ - unsigned char ts_tlb_preload_count; /* TLB preload pages */ unsigned long ts_cbr_map; /* map of allocated CBRs */ unsigned long ts_dsr_map; /* map of allocated DATA resources */ @@ -363,8 +368,6 @@ struct gru_thread_state { long ts_user_options;/* misc user option flags */ pid_t ts_tgid_owner; /* task that is using the context - for migration */ - short ts_user_blade_id;/* user selected blade */ - char ts_user_chiplet_id;/* user selected chiplet */ unsigned short ts_sizeavail; /* Pagesizes in use */ int ts_tsid; /* thread that owns the structure */ @@ -381,11 +384,13 @@ struct gru_thread_state { char ts_blade; /* If >= 0, migrate context if ref from diferent blade */ char ts_force_cch_reload; + char ts_force_unload;/* force context to be unloaded + after migration */ char ts_cbr_idx[GRU_CBR_AU];/* CBR numbers of each allocated CB */ int ts_data_valid; /* Indicates if ts_gdata has valid data */ - struct gru_gseg_statistics ustats; /* User statistics */ + struct gts_statistics ustats; /* User statistics */ unsigned long ts_gdata[0]; /* save area for GRU data (CB, DS, CBE) */ }; @@ -417,7 +422,6 @@ struct gru_state { gru segments (64) */ unsigned short gs_gid; /* unique GRU number */ unsigned short gs_blade_id; /* blade of GRU */ - unsigned char gs_chiplet_id; /* blade chiplet of GRU */ unsigned char gs_tgh_local_shift; /* used to pick TGH for local flush */ unsigned char gs_tgh_first_remote; /* starting TGH# for @@ -449,7 +453,6 @@ struct gru_state { in use */ struct gru_thread_state *gs_gts[GRU_NUM_CCH]; /* GTS currently using the context */ - int gs_irq[GRU_NUM_TFM]; /* Interrupt irqs */ }; /* @@ -616,15 +619,6 @@ static inline int is_kernel_context(struct gru_thread_state *gts) return !gts->ts_mm; } -/* - * The following are for Nehelem-EX. A more general scheme is needed for - * future processors. - */ -#define UV_MAX_INT_CORES 8 -#define uv_cpu_socket_number(p) ((cpu_physical_id(p) >> 5) & 1) -#define uv_cpu_ht_number(p) (cpu_physical_id(p) & 1) -#define uv_cpu_core_number(p) (((cpu_physical_id(p) >> 2) & 4) | \ - ((cpu_physical_id(p) >> 1) & 3)) /*----------------------------------------------------------------------------- * Function prototypes & externs */ @@ -639,26 +633,24 @@ extern struct gru_thread_state *gru_find_thread_state(struct vm_area_struct *vma, int tsid); extern struct gru_thread_state *gru_alloc_thread_state(struct vm_area_struct *vma, int tsid); -extern struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts); +extern struct gru_state *gru_assign_gru_context(struct gru_thread_state *gts, + int blade); extern void gru_load_context(struct gru_thread_state *gts); -extern void gru_steal_context(struct gru_thread_state *gts); +extern void gru_steal_context(struct gru_thread_state *gts, int blade_id); extern void gru_unload_context(struct gru_thread_state *gts, int savestate); -extern int gru_update_cch(struct gru_thread_state *gts); +extern int gru_update_cch(struct gru_thread_state *gts, int force_unload); extern void gts_drop(struct gru_thread_state *gts); extern void gru_tgh_flush_init(struct gru_state *gru); extern int gru_kservices_init(void); extern void gru_kservices_exit(void); -extern irqreturn_t gru0_intr(int irq, void *dev_id); -extern irqreturn_t gru1_intr(int irq, void *dev_id); -extern irqreturn_t gru_intr_mblade(int irq, void *dev_id); extern int gru_dump_chiplet_request(unsigned long arg); extern long gru_get_gseg_statistics(unsigned long arg); +extern irqreturn_t gru_intr(int irq, void *dev_id); extern int gru_handle_user_call_os(unsigned long address); extern int gru_user_flush_tlb(unsigned long arg); extern int gru_user_unload_context(unsigned long arg); extern int gru_get_exception_detail(unsigned long arg); extern int gru_set_context_option(unsigned long address); -extern void gru_check_context_placement(struct gru_thread_state *gts); extern int gru_cpu_fault_map_id(void); extern struct vm_area_struct *gru_find_vma(unsigned long vaddr); extern void gru_flush_all_tlb(struct gru_state *gru); @@ -666,8 +658,7 @@ extern int gru_proc_init(void); extern void gru_proc_exit(void); extern struct gru_thread_state *gru_alloc_gts(struct vm_area_struct *vma, - int cbr_au_count, int dsr_au_count, - unsigned char tlb_preload_count, int options, int tsid); + int cbr_au_count, int dsr_au_count, int options, int tsid); extern unsigned long gru_reserve_cb_resources(struct gru_state *gru, int cbr_au_count, char *cbmap); extern unsigned long gru_reserve_ds_resources(struct gru_state *gru, diff --git a/trunk/drivers/misc/sgi-gru/grutlbpurge.c b/trunk/drivers/misc/sgi-gru/grutlbpurge.c index 240a6d361665..1d125091f5e7 100644 --- a/trunk/drivers/misc/sgi-gru/grutlbpurge.c +++ b/trunk/drivers/misc/sgi-gru/grutlbpurge.c @@ -184,8 +184,8 @@ void gru_flush_tlb_range(struct gru_mm_struct *gms, unsigned long start, STAT(flush_tlb_gru_tgh); asid = GRUASID(asid, start); gru_dbg(grudev, - " FLUSH gruid %d, asid 0x%x, vaddr 0x%lx, vamask 0x%x, num %ld, cbmap 0x%x\n", - gid, asid, start, grupagesize, num, asids->mt_ctxbitmap); + " FLUSH gruid %d, asid 0x%x, num %ld, cbmap 0x%x\n", + gid, asid, num, asids->mt_ctxbitmap); tgh = get_lock_tgh_handle(gru); tgh_invalidate(tgh, start, ~0, asid, grupagesize, 0, num - 1, asids->mt_ctxbitmap); @@ -299,7 +299,6 @@ struct gru_mm_struct *gru_register_mmu_notifier(void) { struct gru_mm_struct *gms; struct mmu_notifier *mn; - int err; mn = mmu_find_ops(current->mm, &gru_mmuops); if (mn) { @@ -308,22 +307,16 @@ struct gru_mm_struct *gru_register_mmu_notifier(void) } else { gms = kzalloc(sizeof(*gms), GFP_KERNEL); if (gms) { - STAT(gms_alloc); spin_lock_init(&gms->ms_asid_lock); gms->ms_notifier.ops = &gru_mmuops; atomic_set(&gms->ms_refcnt, 1); init_waitqueue_head(&gms->ms_wait_queue); - err = __mmu_notifier_register(&gms->ms_notifier, current->mm); - if (err) - goto error; + __mmu_notifier_register(&gms->ms_notifier, current->mm); } } gru_dbg(grudev, "gms %p, refcnt %d\n", gms, atomic_read(&gms->ms_refcnt)); return gms; -error: - kfree(gms); - return ERR_PTR(err); } void gru_drop_mmu_notifier(struct gru_mm_struct *gms) @@ -334,7 +327,6 @@ void gru_drop_mmu_notifier(struct gru_mm_struct *gms) if (!gms->ms_released) mmu_notifier_unregister(&gms->ms_notifier, current->mm); kfree(gms); - STAT(gms_free); } } diff --git a/trunk/drivers/misc/sgi-xp/xp.h b/trunk/drivers/misc/sgi-xp/xp.h index 851b2f25ce0e..2275126cb334 100644 --- a/trunk/drivers/misc/sgi-xp/xp.h +++ b/trunk/drivers/misc/sgi-xp/xp.h @@ -339,7 +339,6 @@ extern short xp_partition_id; extern u8 xp_region_size; extern unsigned long (*xp_pa) (void *); -extern unsigned long (*xp_socket_pa) (unsigned long); extern enum xp_retval (*xp_remote_memcpy) (unsigned long, const unsigned long, size_t); extern int (*xp_cpu_to_nasid) (int); diff --git a/trunk/drivers/misc/sgi-xp/xp_main.c b/trunk/drivers/misc/sgi-xp/xp_main.c index 01be66d02ca8..7896849b16dc 100644 --- a/trunk/drivers/misc/sgi-xp/xp_main.c +++ b/trunk/drivers/misc/sgi-xp/xp_main.c @@ -44,9 +44,6 @@ EXPORT_SYMBOL_GPL(xp_region_size); unsigned long (*xp_pa) (void *addr); EXPORT_SYMBOL_GPL(xp_pa); -unsigned long (*xp_socket_pa) (unsigned long gpa); -EXPORT_SYMBOL_GPL(xp_socket_pa); - enum xp_retval (*xp_remote_memcpy) (unsigned long dst_gpa, const unsigned long src_gpa, size_t len); EXPORT_SYMBOL_GPL(xp_remote_memcpy); diff --git a/trunk/drivers/misc/sgi-xp/xp_sn2.c b/trunk/drivers/misc/sgi-xp/xp_sn2.c index d8e463f87241..fb3ec9d735a9 100644 --- a/trunk/drivers/misc/sgi-xp/xp_sn2.c +++ b/trunk/drivers/misc/sgi-xp/xp_sn2.c @@ -83,15 +83,6 @@ xp_pa_sn2(void *addr) return __pa(addr); } -/* - * Convert a global physical to a socket physical address. - */ -static unsigned long -xp_socket_pa_sn2(unsigned long gpa) -{ - return gpa; -} - /* * Wrapper for bte_copy(). * @@ -171,7 +162,6 @@ xp_init_sn2(void) xp_region_size = sn_region_size; xp_pa = xp_pa_sn2; - xp_socket_pa = xp_socket_pa_sn2; xp_remote_memcpy = xp_remote_memcpy_sn2; xp_cpu_to_nasid = xp_cpu_to_nasid_sn2; xp_expand_memprotect = xp_expand_memprotect_sn2; diff --git a/trunk/drivers/misc/sgi-xp/xp_uv.c b/trunk/drivers/misc/sgi-xp/xp_uv.c index a0d093274dc0..d238576b26fa 100644 --- a/trunk/drivers/misc/sgi-xp/xp_uv.c +++ b/trunk/drivers/misc/sgi-xp/xp_uv.c @@ -32,44 +32,12 @@ xp_pa_uv(void *addr) return uv_gpa(addr); } -/* - * Convert a global physical to socket physical address. - */ -static unsigned long -xp_socket_pa_uv(unsigned long gpa) -{ - return uv_gpa_to_soc_phys_ram(gpa); -} - -static enum xp_retval -xp_remote_mmr_read(unsigned long dst_gpa, const unsigned long src_gpa, - size_t len) -{ - int ret; - unsigned long *dst_va = __va(uv_gpa_to_soc_phys_ram(dst_gpa)); - - BUG_ON(!uv_gpa_in_mmr_space(src_gpa)); - BUG_ON(len != 8); - - ret = gru_read_gpa(dst_va, src_gpa); - if (ret == 0) - return xpSuccess; - - dev_err(xp, "gru_read_gpa() failed, dst_gpa=0x%016lx src_gpa=0x%016lx " - "len=%ld\n", dst_gpa, src_gpa, len); - return xpGruCopyError; -} - - static enum xp_retval xp_remote_memcpy_uv(unsigned long dst_gpa, const unsigned long src_gpa, size_t len) { int ret; - if (uv_gpa_in_mmr_space(src_gpa)) - return xp_remote_mmr_read(dst_gpa, src_gpa, len); - ret = gru_copy_gpa(dst_gpa, src_gpa, len); if (ret == 0) return xpSuccess; @@ -155,7 +123,6 @@ xp_init_uv(void) xp_region_size = sn_region_size; xp_pa = xp_pa_uv; - xp_socket_pa = xp_socket_pa_uv; xp_remote_memcpy = xp_remote_memcpy_uv; xp_cpu_to_nasid = xp_cpu_to_nasid_uv; xp_expand_memprotect = xp_expand_memprotect_uv; diff --git a/trunk/drivers/misc/sgi-xp/xpc_partition.c b/trunk/drivers/misc/sgi-xp/xpc_partition.c index 9a6268c89fdd..65877bc5edaa 100644 --- a/trunk/drivers/misc/sgi-xp/xpc_partition.c +++ b/trunk/drivers/misc/sgi-xp/xpc_partition.c @@ -18,7 +18,6 @@ #include #include #include "xpc.h" -#include /* XPC is exiting flag */ int xpc_exiting; @@ -93,12 +92,8 @@ xpc_get_rsvd_page_pa(int nasid) break; /* !!! L1_CACHE_ALIGN() is only a sn2-bte_copy requirement */ - if (is_shub()) - len = L1_CACHE_ALIGN(len); - - if (len > buf_len) { - if (buf_base != NULL) - kfree(buf_base); + if (L1_CACHE_ALIGN(len) > buf_len) { + kfree(buf_base); buf_len = L1_CACHE_ALIGN(len); buf = xpc_kmalloc_cacheline_aligned(buf_len, GFP_KERNEL, &buf_base); @@ -110,7 +105,7 @@ xpc_get_rsvd_page_pa(int nasid) } } - ret = xp_remote_memcpy(xp_pa(buf), rp_pa, len); + ret = xp_remote_memcpy(xp_pa(buf), rp_pa, buf_len); if (ret != xpSuccess) { dev_dbg(xpc_part, "xp_remote_memcpy failed %d\n", ret); break; @@ -148,7 +143,7 @@ xpc_setup_rsvd_page(void) dev_err(xpc_part, "SAL failed to locate the reserved page\n"); return -ESRCH; } - rp = (struct xpc_rsvd_page *)__va(xp_socket_pa(rp_pa)); + rp = (struct xpc_rsvd_page *)__va(rp_pa); if (rp->SAL_version < 3) { /* SAL_versions < 3 had a SAL_partid defined as a u8 */ diff --git a/trunk/drivers/misc/sgi-xp/xpc_uv.c b/trunk/drivers/misc/sgi-xp/xpc_uv.c index 8725d5e8ab0c..b5bbe59f9c57 100644 --- a/trunk/drivers/misc/sgi-xp/xpc_uv.c +++ b/trunk/drivers/misc/sgi-xp/xpc_uv.c @@ -157,24 +157,22 @@ xpc_gru_mq_watchlist_alloc_uv(struct xpc_gru_mq_uv *mq) { int ret; -#if defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV - int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); - - ret = sn_mq_watchlist_alloc(mmr_pnode, (void *)uv_gpa(mq->address), - mq->order, &mq->mmr_offset); - if (ret < 0) { - dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n", - ret); - return -EBUSY; - } -#elif defined CONFIG_X86_64 - ret = uv_bios_mq_watchlist_alloc(uv_gpa(mq->address), +#if defined CONFIG_X86_64 + ret = uv_bios_mq_watchlist_alloc(mq->mmr_blade, uv_gpa(mq->address), mq->order, &mq->mmr_offset); if (ret < 0) { dev_err(xpc_part, "uv_bios_mq_watchlist_alloc() failed, " "ret=%d\n", ret); return ret; } +#elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV + ret = sn_mq_watchlist_alloc(mq->mmr_blade, (void *)uv_gpa(mq->address), + mq->order, &mq->mmr_offset); + if (ret < 0) { + dev_err(xpc_part, "sn_mq_watchlist_alloc() failed, ret=%d\n", + ret); + return -EBUSY; + } #else #error not a supported configuration #endif @@ -187,13 +185,12 @@ static void xpc_gru_mq_watchlist_free_uv(struct xpc_gru_mq_uv *mq) { int ret; - int mmr_pnode = uv_blade_to_pnode(mq->mmr_blade); #if defined CONFIG_X86_64 - ret = uv_bios_mq_watchlist_free(mmr_pnode, mq->watchlist_num); + ret = uv_bios_mq_watchlist_free(mq->mmr_blade, mq->watchlist_num); BUG_ON(ret != BIOS_STATUS_SUCCESS); #elif defined CONFIG_IA64_GENERIC || defined CONFIG_IA64_SGI_UV - ret = sn_mq_watchlist_free(mmr_pnode, mq->watchlist_num); + ret = sn_mq_watchlist_free(mq->mmr_blade, mq->watchlist_num); BUG_ON(ret != SALRET_OK); #else #error not a supported configuration @@ -207,7 +204,6 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, enum xp_retval xp_ret; int ret; int nid; - int nasid; int pg_order; struct page *page; struct xpc_gru_mq_uv *mq; @@ -263,11 +259,9 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, goto out_5; } - nasid = UV_PNODE_TO_NASID(uv_cpu_to_pnode(cpu)); - mmr_value = (struct uv_IO_APIC_route_entry *)&mq->mmr_value; ret = gru_create_message_queue(mq->gru_mq_desc, mq->address, mq_size, - nasid, mmr_value->vector, mmr_value->dest); + nid, mmr_value->vector, mmr_value->dest); if (ret != 0) { dev_err(xpc_part, "gru_create_message_queue() returned " "error=%d\n", ret); @@ -952,13 +946,11 @@ xpc_get_fifo_entry_uv(struct xpc_fifo_head_uv *head) head->first = first->next; if (head->first == NULL) head->last = NULL; - - head->n_entries--; - BUG_ON(head->n_entries < 0); - - first->next = NULL; } + head->n_entries--; + BUG_ON(head->n_entries < 0); spin_unlock_irqrestore(&head->lock, irq_flags); + first->next = NULL; return first; } @@ -1027,8 +1019,7 @@ xpc_make_first_contact_uv(struct xpc_partition *part) xpc_send_activate_IRQ_part_uv(part, &msg, sizeof(msg), XPC_ACTIVATE_MQ_MSG_SYNC_ACT_STATE_UV); - while (!((part->sn.uv.remote_act_state == XPC_P_AS_ACTIVATING) || - (part->sn.uv.remote_act_state == XPC_P_AS_ACTIVE))) { + while (part->sn.uv.remote_act_state != XPC_P_AS_ACTIVATING) { dev_dbg(xpc_part, "waiting to make first contact with " "partition %d\n", XPC_PARTID(part)); @@ -1431,6 +1422,7 @@ xpc_handle_notify_mq_msg_uv(struct xpc_partition *part, msg_slot = ch_uv->recv_msg_slots + (msg->hdr.msg_slot_number % ch->remote_nentries) * ch->entry_size; + BUG_ON(msg->hdr.msg_slot_number != msg_slot->hdr.msg_slot_number); BUG_ON(msg_slot->hdr.size != 0); memcpy(msg_slot, msg, msg->hdr.size); @@ -1654,6 +1646,8 @@ xpc_received_payload_uv(struct xpc_channel *ch, void *payload) sizeof(struct xpc_notify_mq_msghdr_uv)); if (ret != xpSuccess) XPC_DEACTIVATE_PARTITION(&xpc_partitions[ch->partid], ret); + + msg->hdr.msg_slot_number += ch->remote_nentries; } static struct xpc_arch_operations xpc_arch_ops_uv = { diff --git a/trunk/drivers/net/mlx4/alloc.c b/trunk/drivers/net/mlx4/alloc.c index 8c8515619b8e..ad95d5f7b630 100644 --- a/trunk/drivers/net/mlx4/alloc.c +++ b/trunk/drivers/net/mlx4/alloc.c @@ -72,6 +72,35 @@ void mlx4_bitmap_free(struct mlx4_bitmap *bitmap, u32 obj) mlx4_bitmap_free_range(bitmap, obj, 1); } +static unsigned long find_aligned_range(unsigned long *bitmap, + u32 start, u32 nbits, + int len, int align) +{ + unsigned long end, i; + +again: + start = ALIGN(start, align); + + while ((start < nbits) && test_bit(start, bitmap)) + start += align; + + if (start >= nbits) + return -1; + + end = start+len; + if (end > nbits) + return -1; + + for (i = start + 1; i < end; i++) { + if (test_bit(i, bitmap)) { + start = i + 1; + goto again; + } + } + + return start; +} + u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) { u32 obj, i; @@ -81,13 +110,13 @@ u32 mlx4_bitmap_alloc_range(struct mlx4_bitmap *bitmap, int cnt, int align) spin_lock(&bitmap->lock); - obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, - bitmap->last, cnt, align - 1); + obj = find_aligned_range(bitmap->table, bitmap->last, + bitmap->max, cnt, align); if (obj >= bitmap->max) { bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) & bitmap->mask; - obj = bitmap_find_next_zero_area(bitmap->table, bitmap->max, - 0, cnt, align - 1); + obj = find_aligned_range(bitmap->table, 0, bitmap->max, + cnt, align); } if (obj < bitmap->max) { diff --git a/trunk/drivers/parport/parport_pc.c b/trunk/drivers/parport/parport_pc.c index ad113b0f62db..2597145a066e 100644 --- a/trunk/drivers/parport/parport_pc.c +++ b/trunk/drivers/parport/parport_pc.c @@ -3403,7 +3403,7 @@ static int __init parport_parse_param(const char *s, int *val, *val = automatic; else if (!strncmp(s, "none", 4)) *val = none; - else if (nofifo && !strncmp(s, "nofifo", 6)) + else if (nofifo && !strncmp(s, "nofifo", 4)) *val = nofifo; else { char *ep; diff --git a/trunk/drivers/pnp/pnpbios/proc.c b/trunk/drivers/pnp/pnpbios/proc.c index 2d8ac43f78e8..b35d921bac6e 100644 --- a/trunk/drivers/pnp/pnpbios/proc.c +++ b/trunk/drivers/pnp/pnpbios/proc.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -34,65 +33,42 @@ static struct proc_dir_entry *proc_pnp = NULL; static struct proc_dir_entry *proc_pnp_boot = NULL; -static int pnpconfig_proc_show(struct seq_file *m, void *v) +static int proc_read_pnpconfig(char *buf, char **start, off_t pos, + int count, int *eof, void *data) { struct pnp_isa_config_struc pnps; if (pnp_bios_isapnp_config(&pnps)) return -EIO; - seq_printf(m, "structure_revision %d\n" - "number_of_CSNs %d\n" - "ISA_read_data_port 0x%x\n", - pnps.revision, pnps.no_csns, pnps.isa_rd_data_port); - return 0; + return snprintf(buf, count, + "structure_revision %d\n" + "number_of_CSNs %d\n" + "ISA_read_data_port 0x%x\n", + pnps.revision, pnps.no_csns, pnps.isa_rd_data_port); } -static int pnpconfig_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pnpconfig_proc_show, NULL); -} - -static const struct file_operations pnpconfig_proc_fops = { - .owner = THIS_MODULE, - .open = pnpconfig_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int escd_info_proc_show(struct seq_file *m, void *v) +static int proc_read_escdinfo(char *buf, char **start, off_t pos, + int count, int *eof, void *data) { struct escd_info_struc escd; if (pnp_bios_escd_info(&escd)) return -EIO; - seq_printf(m, "min_ESCD_write_size %d\n" + return snprintf(buf, count, + "min_ESCD_write_size %d\n" "ESCD_size %d\n" "NVRAM_base 0x%x\n", escd.min_escd_write_size, escd.escd_size, escd.nv_storage_base); - return 0; } -static int escd_info_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, escd_info_proc_show, NULL); -} - -static const struct file_operations escd_info_proc_fops = { - .owner = THIS_MODULE, - .open = escd_info_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - #define MAX_SANE_ESCD_SIZE (32*1024) -static int escd_proc_show(struct seq_file *m, void *v) +static int proc_read_escd(char *buf, char **start, off_t pos, + int count, int *eof, void *data) { struct escd_info_struc escd; char *tmpbuf; - int escd_size; + int escd_size, escd_left_to_read, n; if (pnp_bios_escd_info(&escd)) return -EIO; @@ -100,7 +76,7 @@ static int escd_proc_show(struct seq_file *m, void *v) /* sanity check */ if (escd.escd_size > MAX_SANE_ESCD_SIZE) { printk(KERN_ERR - "PnPBIOS: %s: ESCD size reported by BIOS escd_info call is too great\n", __func__); + "PnPBIOS: proc_read_escd: ESCD size reported by BIOS escd_info call is too great\n"); return -EFBIG; } @@ -118,75 +94,56 @@ static int escd_proc_show(struct seq_file *m, void *v) /* sanity check */ if (escd_size > MAX_SANE_ESCD_SIZE) { - printk(KERN_ERR "PnPBIOS: %s: ESCD size reported by" - " BIOS read_escd call is too great\n", __func__); + printk(KERN_ERR "PnPBIOS: proc_read_escd: ESCD size reported by" + " BIOS read_escd call is too great\n"); kfree(tmpbuf); return -EFBIG; } - seq_write(m, tmpbuf, escd_size); + escd_left_to_read = escd_size - pos; + if (escd_left_to_read < 0) + escd_left_to_read = 0; + if (escd_left_to_read == 0) + *eof = 1; + n = min(count, escd_left_to_read); + memcpy(buf, tmpbuf + pos, n); kfree(tmpbuf); - return 0; + *start = buf; + return n; } -static int escd_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, escd_proc_show, NULL); -} - -static const struct file_operations escd_proc_fops = { - .owner = THIS_MODULE, - .open = escd_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int pnp_legacyres_proc_show(struct seq_file *m, void *v) +static int proc_read_legacyres(char *buf, char **start, off_t pos, + int count, int *eof, void *data) { - void *buf; - - buf = kmalloc(65536, GFP_KERNEL); - if (!buf) - return -ENOMEM; - if (pnp_bios_get_stat_res(buf)) { - kfree(buf); + /* Assume that the following won't overflow the buffer */ + if (pnp_bios_get_stat_res(buf)) return -EIO; - } - - seq_write(m, buf, 65536); - kfree(buf); - return 0; -} -static int pnp_legacyres_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pnp_legacyres_proc_show, NULL); + return count; // FIXME: Return actual length } -static const struct file_operations pnp_legacyres_proc_fops = { - .owner = THIS_MODULE, - .open = pnp_legacyres_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int pnp_devices_proc_show(struct seq_file *m, void *v) +static int proc_read_devices(char *buf, char **start, off_t pos, + int count, int *eof, void *data) { struct pnp_bios_node *node; u8 nodenum; + char *p = buf; + + if (pos >= 0xff) + return 0; node = kzalloc(node_info.max_node_size, GFP_KERNEL); if (!node) return -ENOMEM; - for (nodenum = 0; nodenum < 0xff;) { + for (nodenum = pos; nodenum < 0xff;) { u8 thisnodenum = nodenum; - + /* 26 = the number of characters per line sprintf'ed */ + if ((p - buf + 26) > count) + break; if (pnp_bios_get_dev_node(&nodenum, PNPMODE_DYNAMIC, node)) break; - seq_printf(m, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n", + p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n", node->handle, node->eisa_id, node->type_code[0], node->type_code[1], node->type_code[2], node->flags); @@ -196,29 +153,20 @@ static int pnp_devices_proc_show(struct seq_file *m, void *v) "PnPBIOS: proc_read_devices:", (unsigned int)nodenum, (unsigned int)thisnodenum); + *eof = 1; break; } } kfree(node); - return 0; -} - -static int pnp_devices_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pnp_devices_proc_show, NULL); + if (nodenum == 0xff) + *eof = 1; + *start = (char *)((off_t) nodenum - pos); + return p - buf; } -static const struct file_operations pnp_devices_proc_fops = { - .owner = THIS_MODULE, - .open = pnp_devices_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int pnpbios_proc_show(struct seq_file *m, void *v) +static int proc_read_node(char *buf, char **start, off_t pos, + int count, int *eof, void *data) { - void *data = m->private; struct pnp_bios_node *node; int boot = (long)data >> 8; u8 nodenum = (long)data; @@ -232,20 +180,14 @@ static int pnpbios_proc_show(struct seq_file *m, void *v) return -EIO; } len = node->size - sizeof(struct pnp_bios_node); - seq_write(m, node->data, len); + memcpy(buf, node->data, len); kfree(node); - return 0; -} - -static int pnpbios_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, pnpbios_proc_show, PDE(inode)->data); + return len; } -static ssize_t pnpbios_proc_write(struct file *file, const char __user *buf, - size_t count, loff_t *pos) +static int proc_write_node(struct file *file, const char __user * buf, + unsigned long count, void *data) { - void *data = PDE(file->f_path.dentry->d_inode)->data; struct pnp_bios_node *node; int boot = (long)data >> 8; u8 nodenum = (long)data; @@ -276,33 +218,34 @@ static ssize_t pnpbios_proc_write(struct file *file, const char __user *buf, return ret; } -static const struct file_operations pnpbios_proc_fops = { - .owner = THIS_MODULE, - .open = pnpbios_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = pnpbios_proc_write, -}; - int pnpbios_interface_attach_device(struct pnp_bios_node *node) { char name[3]; + struct proc_dir_entry *ent; sprintf(name, "%02x", node->handle); if (!proc_pnp) return -EIO; if (!pnpbios_dont_use_current_config) { - proc_create_data(name, 0644, proc_pnp, &pnpbios_proc_fops, - (void *)(long)(node->handle)); + ent = create_proc_entry(name, 0, proc_pnp); + if (ent) { + ent->read_proc = proc_read_node; + ent->write_proc = proc_write_node; + ent->data = (void *)(long)(node->handle); + } } if (!proc_pnp_boot) return -EIO; - if (proc_create_data(name, 0644, proc_pnp_boot, &pnpbios_proc_fops, - (void *)(long)(node->handle + 0x100))) + ent = create_proc_entry(name, 0, proc_pnp_boot); + if (ent) { + ent->read_proc = proc_read_node; + ent->write_proc = proc_write_node; + ent->data = (void *)(long)(node->handle + 0x100); return 0; + } + return -EIO; } @@ -319,11 +262,14 @@ int __init pnpbios_proc_init(void) proc_pnp_boot = proc_mkdir("boot", proc_pnp); if (!proc_pnp_boot) return -EIO; - proc_create("devices", 0, proc_pnp, &pnp_devices_proc_fops); - proc_create("configuration_info", 0, proc_pnp, &pnpconfig_proc_fops); - proc_create("escd_info", 0, proc_pnp, &escd_info_proc_fops); - proc_create("escd", S_IRUSR, proc_pnp, &escd_proc_fops); - proc_create("legacy_device_resources", 0, proc_pnp, &pnp_legacyres_proc_fops); + create_proc_read_entry("devices", 0, proc_pnp, proc_read_devices, NULL); + create_proc_read_entry("configuration_info", 0, proc_pnp, + proc_read_pnpconfig, NULL); + create_proc_read_entry("escd_info", 0, proc_pnp, proc_read_escdinfo, + NULL); + create_proc_read_entry("escd", S_IRUSR, proc_pnp, proc_read_escd, NULL); + create_proc_read_entry("legacy_device_resources", 0, proc_pnp, + proc_read_legacyres, NULL); return 0; } diff --git a/trunk/drivers/rtc/Kconfig b/trunk/drivers/rtc/Kconfig index 8167e9e6827a..71fbd6e8edf7 100644 --- a/trunk/drivers/rtc/Kconfig +++ b/trunk/drivers/rtc/Kconfig @@ -242,15 +242,6 @@ config RTC_DRV_M41T80_WDT If you say Y here you will get support for the watchdog timer in the ST M41T60 and M41T80 RTC chips series. -config RTC_DRV_BQ32K - tristate "TI BQ32000" - help - If you say Y here you will get support for the TI - BQ32000 I2C RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-bq32k. - config RTC_DRV_DM355EVM tristate "TI DaVinci DM355 EVM RTC" depends on MFD_DM355EVM_MSP @@ -601,22 +592,15 @@ config RTC_DRV_AB3100 Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC support. This chip contains a battery- and capacitor-backed RTC. -config RTC_DRV_NUC900 - tristate "NUC910/NUC920 RTC driver" - depends on RTC_CLASS && ARCH_W90X900 - help - If you say yes here you get support for the RTC subsystem of the - NUC910/NUC920 used in embedded systems. comment "on-CPU RTC drivers" config RTC_DRV_OMAP tristate "TI OMAP1" - depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX + depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 help - Say "yes" here to support the real time clock on TI OMAP1 and - DA8xx/OMAP-L13x chips. This driver can also be built as a - module called rtc-omap. + Say "yes" here to support the real time clock on TI OMAP1 chips. + This driver can also be built as a module called rtc-omap. config RTC_DRV_S3C tristate "Samsung S3C series SoC RTC" @@ -862,10 +846,4 @@ config RTC_DRV_PCAP If you say Y here you will get support for the RTC found on the PCAP2 ASIC used on some Motorola phones. -config RTC_DRV_MC13783 - depends on MFD_MC13783 - tristate "Freescale MC13783 RTC" - help - This enables support for the Freescale MC13783 PMIC RTC - endif # RTC_CLASS diff --git a/trunk/drivers/rtc/Makefile b/trunk/drivers/rtc/Makefile index e5160fddc446..7da6efb3e953 100644 --- a/trunk/drivers/rtc/Makefile +++ b/trunk/drivers/rtc/Makefile @@ -23,7 +23,6 @@ obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o -obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o @@ -53,10 +52,8 @@ obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_MXC) += rtc-mxc.o obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o -obj-$(CONFIG_RTC_DRV_MC13783) += rtc-mc13783.o obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o -obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o diff --git a/trunk/drivers/rtc/rtc-at32ap700x.c b/trunk/drivers/rtc/rtc-at32ap700x.c index 8825695777df..e1ec33e40e38 100644 --- a/trunk/drivers/rtc/rtc-at32ap700x.c +++ b/trunk/drivers/rtc/rtc-at32ap700x.c @@ -256,8 +256,6 @@ static int __init at32_rtc_probe(struct platform_device *pdev) goto out_iounmap; } - platform_set_drvdata(pdev, rtc); - rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, &at32_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc)) { @@ -266,6 +264,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev) goto out_free_irq; } + platform_set_drvdata(pdev, rtc); device_init_wakeup(&pdev->dev, 1); dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n", @@ -274,7 +273,6 @@ static int __init at32_rtc_probe(struct platform_device *pdev) return 0; out_free_irq: - platform_set_drvdata(pdev, NULL); free_irq(irq, rtc); out_iounmap: iounmap(rtc->regs); diff --git a/trunk/drivers/rtc/rtc-bq32k.c b/trunk/drivers/rtc/rtc-bq32k.c deleted file mode 100644 index 408cc8f735be..000000000000 --- a/trunk/drivers/rtc/rtc-bq32k.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Driver for TI BQ32000 RTC. - * - * Copyright (C) 2009 Semihalf. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#define BQ32K_SECONDS 0x00 /* Seconds register address */ -#define BQ32K_SECONDS_MASK 0x7F /* Mask over seconds value */ -#define BQ32K_STOP 0x80 /* Oscillator Stop flat */ - -#define BQ32K_MINUTES 0x01 /* Minutes register address */ -#define BQ32K_MINUTES_MASK 0x7F /* Mask over minutes value */ -#define BQ32K_OF 0x80 /* Oscillator Failure flag */ - -#define BQ32K_HOURS_MASK 0x3F /* Mask over hours value */ -#define BQ32K_CENT 0x40 /* Century flag */ -#define BQ32K_CENT_EN 0x80 /* Century flag enable bit */ - -struct bq32k_regs { - uint8_t seconds; - uint8_t minutes; - uint8_t cent_hours; - uint8_t day; - uint8_t date; - uint8_t month; - uint8_t years; -}; - -static struct i2c_driver bq32k_driver; - -static int bq32k_read(struct device *dev, void *data, uint8_t off, uint8_t len) -{ - struct i2c_client *client = to_i2c_client(dev); - struct i2c_msg msgs[] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &off, - }, { - .addr = client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = data, - } - }; - - if (i2c_transfer(client->adapter, msgs, 2) == 2) - return 0; - - return -EIO; -} - -static int bq32k_write(struct device *dev, void *data, uint8_t off, uint8_t len) -{ - struct i2c_client *client = to_i2c_client(dev); - uint8_t buffer[len + 1]; - - buffer[0] = off; - memcpy(&buffer[1], data, len); - - if (i2c_master_send(client, buffer, len + 1) == len + 1) - return 0; - - return -EIO; -} - -static int bq32k_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - struct bq32k_regs regs; - int error; - - error = bq32k_read(dev, ®s, 0, sizeof(regs)); - if (error) - return error; - - tm->tm_sec = bcd2bin(regs.seconds & BQ32K_SECONDS_MASK); - tm->tm_min = bcd2bin(regs.minutes & BQ32K_SECONDS_MASK); - tm->tm_hour = bcd2bin(regs.cent_hours & BQ32K_HOURS_MASK); - tm->tm_mday = bcd2bin(regs.date); - tm->tm_wday = bcd2bin(regs.day) - 1; - tm->tm_mon = bcd2bin(regs.month) - 1; - tm->tm_year = bcd2bin(regs.years) + - ((regs.cent_hours & BQ32K_CENT) ? 100 : 0); - - return rtc_valid_tm(tm); -} - -static int bq32k_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - struct bq32k_regs regs; - - regs.seconds = bin2bcd(tm->tm_sec); - regs.minutes = bin2bcd(tm->tm_min); - regs.cent_hours = bin2bcd(tm->tm_hour) | BQ32K_CENT_EN; - regs.day = bin2bcd(tm->tm_wday + 1); - regs.date = bin2bcd(tm->tm_mday); - regs.month = bin2bcd(tm->tm_mon + 1); - - if (tm->tm_year >= 100) { - regs.cent_hours |= BQ32K_CENT; - regs.years = bin2bcd(tm->tm_year - 100); - } else - regs.years = bin2bcd(tm->tm_year); - - return bq32k_write(dev, ®s, 0, sizeof(regs)); -} - -static const struct rtc_class_ops bq32k_rtc_ops = { - .read_time = bq32k_rtc_read_time, - .set_time = bq32k_rtc_set_time, -}; - -static int bq32k_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct device *dev = &client->dev; - struct rtc_device *rtc; - uint8_t reg; - int error; - - if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) - return -ENODEV; - - /* Check Oscillator Stop flag */ - error = bq32k_read(dev, ®, BQ32K_SECONDS, 1); - if (!error && (reg & BQ32K_STOP)) { - dev_warn(dev, "Oscillator was halted. Restarting...\n"); - reg &= ~BQ32K_STOP; - error = bq32k_write(dev, ®, BQ32K_SECONDS, 1); - } - if (error) - return error; - - /* Check Oscillator Failure flag */ - error = bq32k_read(dev, ®, BQ32K_MINUTES, 1); - if (!error && (reg & BQ32K_OF)) { - dev_warn(dev, "Oscillator Failure. Check RTC battery.\n"); - reg &= ~BQ32K_OF; - error = bq32k_write(dev, ®, BQ32K_MINUTES, 1); - } - if (error) - return error; - - rtc = rtc_device_register(bq32k_driver.driver.name, &client->dev, - &bq32k_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); - - i2c_set_clientdata(client, rtc); - - return 0; -} - -static int __devexit bq32k_remove(struct i2c_client *client) -{ - struct rtc_device *rtc = i2c_get_clientdata(client); - - rtc_device_unregister(rtc); - return 0; -} - -static const struct i2c_device_id bq32k_id[] = { - { "bq32000", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, bq32k_id); - -static struct i2c_driver bq32k_driver = { - .driver = { - .name = "bq32k", - .owner = THIS_MODULE, - }, - .probe = bq32k_probe, - .remove = __devexit_p(bq32k_remove), - .id_table = bq32k_id, -}; - -static __init int bq32k_init(void) -{ - return i2c_add_driver(&bq32k_driver); -} -module_init(bq32k_init); - -static __exit void bq32k_exit(void) -{ - i2c_del_driver(&bq32k_driver); -} -module_exit(bq32k_exit); - -MODULE_AUTHOR("Semihalf, Piotr Ziecik "); -MODULE_DESCRIPTION("TI BQ32000 I2C RTC driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/rtc/rtc-bq4802.c b/trunk/drivers/rtc/rtc-bq4802.c index 280fe48ada0b..d00a274df8fc 100644 --- a/trunk/drivers/rtc/rtc-bq4802.c +++ b/trunk/drivers/rtc/rtc-bq4802.c @@ -169,8 +169,6 @@ static int __devinit bq4802_probe(struct platform_device *pdev) goto out_free; } - platform_set_drvdata(pdev, p); - p->rtc = rtc_device_register("bq4802", &pdev->dev, &bq4802_ops, THIS_MODULE); if (IS_ERR(p->rtc)) { @@ -178,6 +176,7 @@ static int __devinit bq4802_probe(struct platform_device *pdev) goto out_iounmap; } + platform_set_drvdata(pdev, p); err = 0; out: return err; diff --git a/trunk/drivers/rtc/rtc-cmos.c b/trunk/drivers/rtc/rtc-cmos.c index eb154dc57164..f7a4701bf863 100644 --- a/trunk/drivers/rtc/rtc-cmos.c +++ b/trunk/drivers/rtc/rtc-cmos.c @@ -420,44 +420,50 @@ static int cmos_irq_set_state(struct device *dev, int enabled) return 0; } -static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct cmos_rtc *cmos = dev_get_drvdata(dev); - unsigned long flags; - - if (!is_valid_irq(cmos->irq)) - return -EINVAL; - - spin_lock_irqsave(&rtc_lock, flags); - - if (enabled) - cmos_irq_enable(cmos, RTC_AIE); - else - cmos_irq_disable(cmos, RTC_AIE); - - spin_unlock_irqrestore(&rtc_lock, flags); - return 0; -} +#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) -static int cmos_update_irq_enable(struct device *dev, unsigned int enabled) +static int +cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned long flags; - if (!is_valid_irq(cmos->irq)) - return -EINVAL; + switch (cmd) { + case RTC_AIE_OFF: + case RTC_AIE_ON: + case RTC_UIE_OFF: + case RTC_UIE_ON: + if (!is_valid_irq(cmos->irq)) + return -EINVAL; + break; + /* PIE ON/OFF is handled by cmos_irq_set_state() */ + default: + return -ENOIOCTLCMD; + } spin_lock_irqsave(&rtc_lock, flags); - - if (enabled) - cmos_irq_enable(cmos, RTC_UIE); - else + switch (cmd) { + case RTC_AIE_OFF: /* alarm off */ + cmos_irq_disable(cmos, RTC_AIE); + break; + case RTC_AIE_ON: /* alarm on */ + cmos_irq_enable(cmos, RTC_AIE); + break; + case RTC_UIE_OFF: /* update off */ cmos_irq_disable(cmos, RTC_UIE); - + break; + case RTC_UIE_ON: /* update on */ + cmos_irq_enable(cmos, RTC_UIE); + break; + } spin_unlock_irqrestore(&rtc_lock, flags); return 0; } +#else +#define cmos_rtc_ioctl NULL +#endif + #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) static int cmos_procfs(struct device *dev, struct seq_file *seq) @@ -497,15 +503,14 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq) #endif static const struct rtc_class_ops cmos_rtc_ops = { - .read_time = cmos_read_time, - .set_time = cmos_set_time, - .read_alarm = cmos_read_alarm, - .set_alarm = cmos_set_alarm, - .proc = cmos_procfs, - .irq_set_freq = cmos_irq_set_freq, - .irq_set_state = cmos_irq_set_state, - .alarm_irq_enable = cmos_alarm_irq_enable, - .update_irq_enable = cmos_update_irq_enable, + .ioctl = cmos_rtc_ioctl, + .read_time = cmos_read_time, + .set_time = cmos_set_time, + .read_alarm = cmos_read_alarm, + .set_alarm = cmos_set_alarm, + .proc = cmos_procfs, + .irq_set_freq = cmos_irq_set_freq, + .irq_set_state = cmos_irq_set_state, }; /*----------------------------------------------------------------*/ @@ -866,9 +871,8 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg) mask = RTC_IRQMASK; tmp &= ~mask; CMOS_WRITE(tmp, RTC_CONTROL); + hpet_mask_rtc_irq_bit(mask); - /* shut down hpet emulation - we don't need it for alarm */ - hpet_mask_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE); cmos_checkintr(cmos, tmp); } spin_unlock_irq(&rtc_lock); diff --git a/trunk/drivers/rtc/rtc-ds1302.c b/trunk/drivers/rtc/rtc-ds1302.c index 532acf9b05d8..1e73c8f42e38 100644 --- a/trunk/drivers/rtc/rtc-ds1302.c +++ b/trunk/drivers/rtc/rtc-ds1302.c @@ -143,6 +143,7 @@ static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd, #ifdef RTC_SET_CHARGE case RTC_SET_CHARGE: { + struct ds1302_rtc *rtc = dev_get_drvdata(dev); int tcs_val; if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int))) diff --git a/trunk/drivers/rtc/rtc-ds1305.c b/trunk/drivers/rtc/rtc-ds1305.c index 259db7f3535b..2736b11a1b1e 100644 --- a/trunk/drivers/rtc/rtc-ds1305.c +++ b/trunk/drivers/rtc/rtc-ds1305.c @@ -617,6 +617,7 @@ static struct bin_attribute nvram = { static int __devinit ds1305_probe(struct spi_device *spi) { struct ds1305 *ds1305; + struct rtc_device *rtc; int status; u8 addr, value; struct ds1305_platform_data *pdata = spi->dev.platform_data; @@ -755,13 +756,14 @@ static int __devinit ds1305_probe(struct spi_device *spi) dev_dbg(&spi->dev, "AM/PM\n"); /* register RTC ... from here on, ds1305->ctrl needs locking */ - ds1305->rtc = rtc_device_register("ds1305", &spi->dev, + rtc = rtc_device_register("ds1305", &spi->dev, &ds1305_ops, THIS_MODULE); - if (IS_ERR(ds1305->rtc)) { - status = PTR_ERR(ds1305->rtc); + if (IS_ERR(rtc)) { + status = PTR_ERR(rtc); dev_dbg(&spi->dev, "register rtc --> %d\n", status); goto fail0; } + ds1305->rtc = rtc; /* Maybe set up alarm IRQ; be ready to handle it triggering right * away. NOTE that we don't share this. The signal is active low, @@ -772,7 +774,7 @@ static int __devinit ds1305_probe(struct spi_device *spi) if (spi->irq) { INIT_WORK(&ds1305->work, ds1305_work); status = request_irq(spi->irq, ds1305_irq, - 0, dev_name(&ds1305->rtc->dev), ds1305); + 0, dev_name(&rtc->dev), ds1305); if (status < 0) { dev_dbg(&spi->dev, "request_irq %d --> %d\n", spi->irq, status); @@ -792,7 +794,7 @@ static int __devinit ds1305_probe(struct spi_device *spi) fail2: free_irq(spi->irq, ds1305); fail1: - rtc_device_unregister(ds1305->rtc); + rtc_device_unregister(rtc); fail0: kfree(ds1305); return status; @@ -800,7 +802,7 @@ static int __devinit ds1305_probe(struct spi_device *spi) static int __devexit ds1305_remove(struct spi_device *spi) { - struct ds1305 *ds1305 = spi_get_drvdata(spi); + struct ds1305 *ds1305 = spi_get_drvdata(spi); sysfs_remove_bin_file(&spi->dev.kobj, &nvram); diff --git a/trunk/drivers/rtc/rtc-ds1307.c b/trunk/drivers/rtc/rtc-ds1307.c index 8a99da6f2f24..eb99ee4fa0f5 100644 --- a/trunk/drivers/rtc/rtc-ds1307.c +++ b/trunk/drivers/rtc/rtc-ds1307.c @@ -874,7 +874,7 @@ static int __devinit ds1307_probe(struct i2c_client *client, } if (want_irq) { - err = request_irq(client->irq, ds1307_irq, IRQF_SHARED, + err = request_irq(client->irq, ds1307_irq, 0, ds1307->rtc->name, client); if (err) { dev_err(&client->dev, diff --git a/trunk/drivers/rtc/rtc-ds1511.c b/trunk/drivers/rtc/rtc-ds1511.c index 4166b84cb514..539676e25fd8 100644 --- a/trunk/drivers/rtc/rtc-ds1511.c +++ b/trunk/drivers/rtc/rtc-ds1511.c @@ -87,6 +87,7 @@ enum ds1511reg { struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; /* virtual base address */ + unsigned long baseaddr; /* physical base address */ int size; /* amount of memory mapped */ int irq; unsigned int irqen; @@ -94,7 +95,6 @@ struct rtc_plat_data { int alrm_min; int alrm_hour; int alrm_mday; - spinlock_t lock; }; static DEFINE_SPINLOCK(ds1511_lock); @@ -302,7 +302,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata) { unsigned long flags; - spin_lock_irqsave(&pdata->lock, flags); + spin_lock_irqsave(&pdata->rtc->irq_lock, flags); rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? 0x80 : bin2bcd(pdata->alrm_mday) & 0x3f, RTC_ALARM_DATE); @@ -317,7 +317,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata) RTC_ALARM_SEC); rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD); rtc_read(RTC_CMD1); /* clear interrupts */ - spin_unlock_irqrestore(&pdata->lock, flags); + spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); } static int @@ -362,63 +362,61 @@ ds1511_interrupt(int irq, void *dev_id) { struct platform_device *pdev = dev_id; struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - unsigned long events = 0; + unsigned long events = RTC_IRQF; - spin_lock(&pdata->lock); /* * read and clear interrupt */ - if (rtc_read(RTC_CMD1) & DS1511_IRQF) { - events = RTC_IRQF; - if (rtc_read(RTC_ALARM_SEC) & 0x80) - events |= RTC_UF; - else - events |= RTC_AF; - if (likely(pdata->rtc)) - rtc_update_irq(pdata->rtc, 1, events); - } - spin_unlock(&pdata->lock); - return events ? IRQ_HANDLED : IRQ_NONE; + if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) { + return IRQ_NONE; + } + if (rtc_read(RTC_ALARM_SEC) & 0x80) { + events |= RTC_UF; + } else { + events |= RTC_AF; + } + rtc_update_irq(pdata->rtc, 1, events); + return IRQ_HANDLED; } -static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) + static int +ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq <= 0) - return -EINVAL; - if (enabled) - pdata->irqen |= RTC_AF; - else + if (pdata->irq <= 0) { + return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ + } + switch (cmd) { + case RTC_AIE_OFF: pdata->irqen &= ~RTC_AF; - ds1511_rtc_update_alarm(pdata); - return 0; -} - -static int ds1511_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) -{ - struct platform_device *pdev = to_platform_device(dev); - struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - - if (pdata->irq <= 0) - return -EINVAL; - if (enabled) - pdata->irqen |= RTC_UF; - else + ds1511_rtc_update_alarm(pdata); + break; + case RTC_AIE_ON: + pdata->irqen |= RTC_AF; + ds1511_rtc_update_alarm(pdata); + break; + case RTC_UIE_OFF: pdata->irqen &= ~RTC_UF; - ds1511_rtc_update_alarm(pdata); + ds1511_rtc_update_alarm(pdata); + break; + case RTC_UIE_ON: + pdata->irqen |= RTC_UF; + ds1511_rtc_update_alarm(pdata); + break; + default: + return -ENOIOCTLCMD; + } return 0; } static const struct rtc_class_ops ds1511_rtc_ops = { - .read_time = ds1511_rtc_read_time, - .set_time = ds1511_rtc_set_time, - .read_alarm = ds1511_rtc_read_alarm, - .set_alarm = ds1511_rtc_set_alarm, - .alarm_irq_enable = ds1511_rtc_alarm_irq_enable, - .update_irq_enable = ds1511_rtc_update_irq_enable, + .read_time = ds1511_rtc_read_time, + .set_time = ds1511_rtc_set_time, + .read_alarm = ds1511_rtc_read_alarm, + .set_alarm = ds1511_rtc_set_alarm, + .ioctl = ds1511_rtc_ioctl, }; static ssize_t @@ -494,23 +492,29 @@ ds1511_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; struct resource *res; - struct rtc_plat_data *pdata; + struct rtc_plat_data *pdata = NULL; int ret = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { return -ENODEV; } - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { return -ENOMEM; + } pdata->size = res->end - res->start + 1; - if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, - pdev->name)) - return -EBUSY; - ds1511_base = devm_ioremap(&pdev->dev, res->start, pdata->size); - if (!ds1511_base) - return -ENOMEM; + if (!request_mem_region(res->start, pdata->size, pdev->name)) { + ret = -EBUSY; + goto out; + } + pdata->baseaddr = res->start; + pdata->size = pdata->size; + ds1511_base = ioremap(pdata->baseaddr, pdata->size); + if (!ds1511_base) { + ret = -ENOMEM; + goto out; + } pdata->ioaddr = ds1511_base; pdata->irq = platform_get_irq(pdev, 0); @@ -536,15 +540,13 @@ ds1511_rtc_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "voltage-low detected.\n"); } - spin_lock_init(&pdata->lock); - platform_set_drvdata(pdev, pdata); /* * if the platform has an interrupt in mind for this device, * then by all means, set it */ if (pdata->irq > 0) { rtc_read(RTC_CMD1); - if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt, + if (request_irq(pdata->irq, ds1511_interrupt, IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); @@ -554,13 +556,33 @@ ds1511_rtc_probe(struct platform_device *pdev) rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } pdata->rtc = rtc; - + platform_set_drvdata(pdev, pdata); ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); - if (ret) + if (ret) { + goto out; + } + return 0; + out: + if (pdata->rtc) { rtc_device_unregister(pdata->rtc); + } + if (pdata->irq > 0) { + free_irq(pdata->irq, pdev); + } + if (ds1511_base) { + iounmap(ds1511_base); + ds1511_base = NULL; + } + if (pdata->baseaddr) { + release_mem_region(pdata->baseaddr, pdata->size); + } + + kfree(pdata); return ret; } @@ -571,13 +593,19 @@ ds1511_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); rtc_device_unregister(pdata->rtc); + pdata->rtc = NULL; if (pdata->irq > 0) { /* * disable the alarm interrupt */ rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD); rtc_read(RTC_CMD1); + free_irq(pdata->irq, pdev); } + iounmap(pdata->ioaddr); + ds1511_base = NULL; + release_mem_region(pdata->baseaddr, pdata->size); + kfree(pdata); return 0; } diff --git a/trunk/drivers/rtc/rtc-ds1553.c b/trunk/drivers/rtc/rtc-ds1553.c index ed1ef7c9cc06..717288527c6b 100644 --- a/trunk/drivers/rtc/rtc-ds1553.c +++ b/trunk/drivers/rtc/rtc-ds1553.c @@ -18,7 +18,7 @@ #include #include -#define DRV_VERSION "0.3" +#define DRV_VERSION "0.2" #define RTC_REG_SIZE 0x2000 #define RTC_OFFSET 0x1ff0 @@ -61,6 +61,7 @@ struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; + resource_size_t baseaddr; unsigned long last_jiffies; int irq; unsigned int irqen; @@ -68,7 +69,6 @@ struct rtc_plat_data { int alrm_min; int alrm_hour; int alrm_mday; - spinlock_t lock; }; static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -139,7 +139,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata) void __iomem *ioaddr = pdata->ioaddr; unsigned long flags; - spin_lock_irqsave(&pdata->lock, flags); + spin_lock_irqsave(&pdata->rtc->irq_lock, flags); writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? 0x80 : bin2bcd(pdata->alrm_mday), ioaddr + RTC_DATE_ALARM); @@ -154,7 +154,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata) ioaddr + RTC_SECONDS_ALARM); writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS); readb(ioaddr + RTC_FLAGS); /* clear interrupts */ - spin_unlock_irqrestore(&pdata->lock, flags); + spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); } static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -194,69 +194,64 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id) struct platform_device *pdev = dev_id; struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; - unsigned long events = 0; + unsigned long events = RTC_IRQF; - spin_lock(&pdata->lock); /* read and clear interrupt */ - if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) { - events = RTC_IRQF; - if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) - events |= RTC_UF; - else - events |= RTC_AF; - if (likely(pdata->rtc)) - rtc_update_irq(pdata->rtc, 1, events); - } - spin_unlock(&pdata->lock); - return events ? IRQ_HANDLED : IRQ_NONE; -} - -static int ds1553_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct platform_device *pdev = to_platform_device(dev); - struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - - if (pdata->irq <= 0) - return -EINVAL; - if (enabled) - pdata->irqen |= RTC_AF; + if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) + return IRQ_NONE; + if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) + events |= RTC_UF; else - pdata->irqen &= ~RTC_AF; - ds1553_rtc_update_alarm(pdata); - return 0; + events |= RTC_AF; + rtc_update_irq(pdata->rtc, 1, events); + return IRQ_HANDLED; } -static int ds1553_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) +static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) { struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); if (pdata->irq <= 0) - return -EINVAL; - if (enabled) - pdata->irqen |= RTC_UF; - else + return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ + switch (cmd) { + case RTC_AIE_OFF: + pdata->irqen &= ~RTC_AF; + ds1553_rtc_update_alarm(pdata); + break; + case RTC_AIE_ON: + pdata->irqen |= RTC_AF; + ds1553_rtc_update_alarm(pdata); + break; + case RTC_UIE_OFF: pdata->irqen &= ~RTC_UF; - ds1553_rtc_update_alarm(pdata); + ds1553_rtc_update_alarm(pdata); + break; + case RTC_UIE_ON: + pdata->irqen |= RTC_UF; + ds1553_rtc_update_alarm(pdata); + break; + default: + return -ENOIOCTLCMD; + } return 0; } static const struct rtc_class_ops ds1553_rtc_ops = { - .read_time = ds1553_rtc_read_time, - .set_time = ds1553_rtc_set_time, - .read_alarm = ds1553_rtc_read_alarm, - .set_alarm = ds1553_rtc_set_alarm, - .alarm_irq_enable = ds1553_rtc_alarm_irq_enable, - .update_irq_enable = ds1553_rtc_update_irq_enable, + .read_time = ds1553_rtc_read_time, + .set_time = ds1553_rtc_set_time, + .read_alarm = ds1553_rtc_read_alarm, + .set_alarm = ds1553_rtc_set_alarm, + .ioctl = ds1553_rtc_ioctl, }; static ssize_t ds1553_nvram_read(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t size) { - struct device *dev = container_of(kobj, struct device, kobj); - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *pdev = + to_platform_device(container_of(kobj, struct device, kobj)); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; ssize_t count; @@ -270,8 +265,8 @@ static ssize_t ds1553_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t size) { - struct device *dev = container_of(kobj, struct device, kobj); - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *pdev = + to_platform_device(container_of(kobj, struct device, kobj)); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; ssize_t count; @@ -296,23 +291,26 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) struct rtc_device *rtc; struct resource *res; unsigned int cen, sec; - struct rtc_plat_data *pdata; - void __iomem *ioaddr; + struct rtc_plat_data *pdata = NULL; + void __iomem *ioaddr = NULL; int ret = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, - pdev->name)) - return -EBUSY; - - ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); - if (!ioaddr) - return -ENOMEM; + if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { + ret = -EBUSY; + goto out; + } + pdata->baseaddr = res->start; + ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); + if (!ioaddr) { + ret = -ENOMEM; + goto out; + } pdata->ioaddr = ioaddr; pdata->irq = platform_get_irq(pdev, 0); @@ -328,13 +326,9 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF) dev_warn(&pdev->dev, "voltage-low detected.\n"); - spin_lock_init(&pdata->lock); - pdata->last_jiffies = jiffies; - platform_set_drvdata(pdev, pdata); if (pdata->irq > 0) { writeb(0, ioaddr + RTC_INTERRUPTS); - if (devm_request_irq(&pdev->dev, pdata->irq, - ds1553_rtc_interrupt, + if (request_irq(pdata->irq, ds1553_rtc_interrupt, IRQF_DISABLED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); pdata->irq = 0; @@ -343,13 +337,27 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev) rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1553_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } pdata->rtc = rtc; - + pdata->last_jiffies = jiffies; + platform_set_drvdata(pdev, pdata); ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); if (ret) - rtc_device_unregister(rtc); + goto out; + return 0; + out: + if (pdata->rtc) + rtc_device_unregister(pdata->rtc); + if (pdata->irq > 0) + free_irq(pdata->irq, pdev); + if (ioaddr) + iounmap(ioaddr); + if (pdata->baseaddr) + release_mem_region(pdata->baseaddr, RTC_REG_SIZE); + kfree(pdata); return ret; } @@ -359,8 +367,13 @@ static int __devexit ds1553_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); rtc_device_unregister(pdata->rtc); - if (pdata->irq > 0) + if (pdata->irq > 0) { writeb(0, pdata->ioaddr + RTC_INTERRUPTS); + free_irq(pdata->irq, pdev); + } + iounmap(pdata->ioaddr); + release_mem_region(pdata->baseaddr, RTC_REG_SIZE); + kfree(pdata); return 0; } diff --git a/trunk/drivers/rtc/rtc-ds1742.c b/trunk/drivers/rtc/rtc-ds1742.c index a1273360a44e..09249459e9a4 100644 --- a/trunk/drivers/rtc/rtc-ds1742.c +++ b/trunk/drivers/rtc/rtc-ds1742.c @@ -21,7 +21,7 @@ #include #include -#define DRV_VERSION "0.4" +#define DRV_VERSION "0.3" #define RTC_SIZE 8 @@ -55,6 +55,7 @@ struct rtc_plat_data { void __iomem *ioaddr_rtc; size_t size_nvram; size_t size; + resource_size_t baseaddr; unsigned long last_jiffies; struct bin_attribute nvram_attr; }; @@ -131,8 +132,8 @@ static ssize_t ds1742_nvram_read(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t size) { - struct device *dev = container_of(kobj, struct device, kobj); - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *pdev = + to_platform_device(container_of(kobj, struct device, kobj)); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr_nvram; ssize_t count; @@ -146,8 +147,8 @@ static ssize_t ds1742_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr, char *buf, loff_t pos, size_t size) { - struct device *dev = container_of(kobj, struct device, kobj); - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *pdev = + to_platform_device(container_of(kobj, struct device, kobj)); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr_nvram; ssize_t count; @@ -162,24 +163,27 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev) struct rtc_device *rtc; struct resource *res; unsigned int cen, sec; - struct rtc_plat_data *pdata; - void __iomem *ioaddr; + struct rtc_plat_data *pdata = NULL; + void __iomem *ioaddr = NULL; int ret = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; pdata->size = res->end - res->start + 1; - if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, - pdev->name)) - return -EBUSY; - ioaddr = devm_ioremap(&pdev->dev, res->start, pdata->size); - if (!ioaddr) - return -ENOMEM; - + if (!request_mem_region(res->start, pdata->size, pdev->name)) { + ret = -EBUSY; + goto out; + } + pdata->baseaddr = res->start; + ioaddr = ioremap(pdata->baseaddr, pdata->size); + if (!ioaddr) { + ret = -ENOMEM; + goto out; + } pdata->ioaddr_nvram = ioaddr; pdata->size_nvram = pdata->size - RTC_SIZE; pdata->ioaddr_rtc = ioaddr + pdata->size_nvram; @@ -203,19 +207,31 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev) if (!(readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG)) dev_warn(&pdev->dev, "voltage-low detected.\n"); - pdata->last_jiffies = jiffies; - platform_set_drvdata(pdev, pdata); rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1742_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } pdata->rtc = rtc; + pdata->last_jiffies = jiffies; + platform_set_drvdata(pdev, pdata); ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); if (ret) { dev_err(&pdev->dev, "creating nvram file in sysfs failed\n"); - rtc_device_unregister(rtc); + goto out; } + + return 0; + out: + if (pdata->rtc) + rtc_device_unregister(pdata->rtc); + if (pdata->ioaddr_nvram) + iounmap(pdata->ioaddr_nvram); + if (pdata->baseaddr) + release_mem_region(pdata->baseaddr, pdata->size); + kfree(pdata); return ret; } @@ -225,6 +241,9 @@ static int __devexit ds1742_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); rtc_device_unregister(pdata->rtc); + iounmap(pdata->ioaddr_nvram); + release_mem_region(pdata->baseaddr, pdata->size); + kfree(pdata); return 0; } diff --git a/trunk/drivers/rtc/rtc-m48t35.c b/trunk/drivers/rtc/rtc-m48t35.c index 8cb5b8959e5b..0b2197559940 100644 --- a/trunk/drivers/rtc/rtc-m48t35.c +++ b/trunk/drivers/rtc/rtc-m48t35.c @@ -142,6 +142,7 @@ static const struct rtc_class_ops m48t35_ops = { static int __devinit m48t35_probe(struct platform_device *pdev) { + struct rtc_device *rtc; struct resource *res; struct m48t35_priv *priv; int ret = 0; @@ -170,21 +171,20 @@ static int __devinit m48t35_probe(struct platform_device *pdev) ret = -ENOMEM; goto out; } - spin_lock_init(&priv->lock); - - platform_set_drvdata(pdev, priv); - - priv->rtc = rtc_device_register("m48t35", &pdev->dev, + rtc = rtc_device_register("m48t35", &pdev->dev, &m48t35_ops, THIS_MODULE); - if (IS_ERR(priv->rtc)) { - ret = PTR_ERR(priv->rtc); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); goto out; } - + priv->rtc = rtc; + platform_set_drvdata(pdev, priv); return 0; out: + if (priv->rtc) + rtc_device_unregister(priv->rtc); if (priv->reg) iounmap(priv->reg); if (priv->baseaddr) diff --git a/trunk/drivers/rtc/rtc-m48t59.c b/trunk/drivers/rtc/rtc-m48t59.c index ede43b846859..33921a6b1707 100644 --- a/trunk/drivers/rtc/rtc-m48t59.c +++ b/trunk/drivers/rtc/rtc-m48t59.c @@ -481,9 +481,6 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) goto out; } - spin_lock_init(&m48t59->lock); - platform_set_drvdata(pdev, m48t59); - m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE); if (IS_ERR(m48t59->rtc)) { ret = PTR_ERR(m48t59->rtc); @@ -493,14 +490,16 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev) m48t59_nvram_attr.size = pdata->offset; ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); - if (ret) { - rtc_device_unregister(m48t59->rtc); + if (ret) goto out; - } + spin_lock_init(&m48t59->lock); + platform_set_drvdata(pdev, m48t59); return 0; out: + if (!IS_ERR(m48t59->rtc)) + rtc_device_unregister(m48t59->rtc); if (m48t59->irq != NO_IRQ) free_irq(m48t59->irq, &pdev->dev); if (m48t59->ioaddr) diff --git a/trunk/drivers/rtc/rtc-mc13783.c b/trunk/drivers/rtc/rtc-mc13783.c deleted file mode 100644 index 850f983c039c..000000000000 --- a/trunk/drivers/rtc/rtc-mc13783.c +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Real Time Clock driver for Freescale MC13783 PMIC - * - * (C) 2009 Sascha Hauer, Pengutronix - * (C) 2009 Uwe Kleine-Koenig, Pengutronix - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#define DRIVER_NAME "mc13783-rtc" - -#define MC13783_RTCTOD 20 -#define MC13783_RTCTODA 21 -#define MC13783_RTCDAY 22 -#define MC13783_RTCDAYA 23 - -struct mc13783_rtc { - struct rtc_device *rtc; - struct mc13783 *mc13783; - int valid; -}; - -static int mc13783_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - struct mc13783_rtc *priv = dev_get_drvdata(dev); - unsigned int seconds, days1, days2; - unsigned long s1970; - int ret; - - mc13783_lock(priv->mc13783); - - if (!priv->valid) { - ret = -ENODATA; - goto out; - } - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days1); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTOD, &seconds); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days2); -out: - mc13783_unlock(priv->mc13783); - - if (ret) - return ret; - - if (days2 == days1 + 1) { - if (seconds >= 86400 / 2) - days2 = days1; - else - days1 = days2; - } - - if (days1 != days2) - return -EIO; - - s1970 = days1 * 86400 + seconds; - - rtc_time_to_tm(s1970, tm); - - return rtc_valid_tm(tm); -} - -static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs) -{ - struct mc13783_rtc *priv = dev_get_drvdata(dev); - unsigned int seconds, days; - int ret; - - seconds = secs % 86400; - days = secs / 86400; - - mc13783_lock(priv->mc13783); - - /* - * first write seconds=0 to prevent a day switch between writing days - * and seconds below - */ - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, 0); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAY, days); - if (unlikely(ret)) - goto out; - - ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, seconds); - if (unlikely(ret)) - goto out; - - ret = mc13783_ackirq(priv->mc13783, MC13783_IRQ_RTCRST); - if (unlikely(ret)) - goto out; - - ret = mc13783_unmask(priv->mc13783, MC13783_IRQ_RTCRST); -out: - priv->valid = !ret; - - mc13783_unlock(priv->mc13783); - - return ret; -} - -static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev) -{ - struct mc13783_rtc *priv = dev; - struct mc13783 *mc13783 = priv->mc13783; - - dev_dbg(&priv->rtc->dev, "1HZ\n"); - - rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); - - mc13783_ackirq(mc13783, irq); - - return IRQ_HANDLED; -} - -static int mc13783_rtc_update_irq_enable(struct device *dev, - unsigned int enabled) -{ - struct mc13783_rtc *priv = dev_get_drvdata(dev); - int ret = -ENODATA; - - mc13783_lock(priv->mc13783); - if (!priv->valid) - goto out; - - ret = (enabled ? mc13783_unmask : mc13783_mask)(priv->mc13783, - MC13783_IRQ_1HZ); -out: - mc13783_unlock(priv->mc13783); - - return ret; -} - -static const struct rtc_class_ops mc13783_rtc_ops = { - .read_time = mc13783_rtc_read_time, - .set_mmss = mc13783_rtc_set_mmss, - .update_irq_enable = mc13783_rtc_update_irq_enable, -}; - -static irqreturn_t mc13783_rtc_reset_handler(int irq, void *dev) -{ - struct mc13783_rtc *priv = dev; - struct mc13783 *mc13783 = priv->mc13783; - - dev_dbg(&priv->rtc->dev, "RTCRST\n"); - priv->valid = 0; - - mc13783_mask(mc13783, irq); - - return IRQ_HANDLED; -} - -static int __devinit mc13783_rtc_probe(struct platform_device *pdev) -{ - int ret; - struct mc13783_rtc *priv; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->mc13783 = dev_get_drvdata(pdev->dev.parent); - platform_set_drvdata(pdev, priv); - - priv->valid = 1; - - mc13783_lock(priv->mc13783); - - ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST, - mc13783_rtc_reset_handler, DRIVER_NAME, priv); - if (ret) - goto err_reset_irq_request; - - ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ, - mc13783_rtc_update_handler, DRIVER_NAME, priv); - if (ret) - goto err_update_irq_request; - - mc13783_unlock(priv->mc13783); - - priv->rtc = rtc_device_register(pdev->name, - &pdev->dev, &mc13783_rtc_ops, THIS_MODULE); - - if (IS_ERR(priv->rtc)) { - ret = PTR_ERR(priv->rtc); - - mc13783_lock(priv->mc13783); - - mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); -err_update_irq_request: - - mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); -err_reset_irq_request: - - mc13783_unlock(priv->mc13783); - - platform_set_drvdata(pdev, NULL); - kfree(priv); - } - - return ret; -} - -static int __devexit mc13783_rtc_remove(struct platform_device *pdev) -{ - struct mc13783_rtc *priv = platform_get_drvdata(pdev); - - rtc_device_unregister(priv->rtc); - - mc13783_lock(priv->mc13783); - - mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); - mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); - - mc13783_unlock(priv->mc13783); - - platform_set_drvdata(pdev, NULL); - - kfree(priv); - - return 0; -} - -static struct platform_driver mc13783_rtc_driver = { - .remove = __devexit_p(mc13783_rtc_remove), - .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init mc13783_rtc_init(void) -{ - return platform_driver_probe(&mc13783_rtc_driver, &mc13783_rtc_probe); -} -module_init(mc13783_rtc_init); - -static void __exit mc13783_rtc_exit(void) -{ - platform_driver_unregister(&mc13783_rtc_driver); -} -module_exit(mc13783_rtc_exit); - -MODULE_AUTHOR("Sascha Hauer "); -MODULE_DESCRIPTION("RTC driver for Freescale MC13783 PMIC"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/trunk/drivers/rtc/rtc-mv.c b/trunk/drivers/rtc/rtc-mv.c index dc052ce6e63a..e0263d2005ee 100644 --- a/trunk/drivers/rtc/rtc-mv.c +++ b/trunk/drivers/rtc/rtc-mv.c @@ -27,17 +27,10 @@ #define RTC_MONTH_OFFS 8 #define RTC_YEAR_OFFS 16 -#define RTC_ALARM_TIME_REG_OFFS 8 -#define RTC_ALARM_DATE_REG_OFFS 0xc -#define RTC_ALARM_VALID (1 << 7) - -#define RTC_ALARM_INTERRUPT_MASK_REG_OFFS 0x10 -#define RTC_ALARM_INTERRUPT_CASUE_REG_OFFS 0x14 struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; - int irq; }; static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -91,134 +84,12 @@ static int mv_rtc_read_time(struct device *dev, struct rtc_time *tm) return rtc_valid_tm(tm); } -static int mv_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) -{ - struct rtc_plat_data *pdata = dev_get_drvdata(dev); - void __iomem *ioaddr = pdata->ioaddr; - u32 rtc_time, rtc_date; - unsigned int year, month, day, hour, minute, second, wday; - - rtc_time = readl(ioaddr + RTC_ALARM_TIME_REG_OFFS); - rtc_date = readl(ioaddr + RTC_ALARM_DATE_REG_OFFS); - - second = rtc_time & 0x7f; - minute = (rtc_time >> RTC_MINUTES_OFFS) & 0x7f; - hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hours mode */ - wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7; - - day = rtc_date & 0x3f; - month = (rtc_date >> RTC_MONTH_OFFS) & 0x3f; - year = (rtc_date >> RTC_YEAR_OFFS) & 0xff; - - alm->time.tm_sec = bcd2bin(second); - alm->time.tm_min = bcd2bin(minute); - alm->time.tm_hour = bcd2bin(hour); - alm->time.tm_mday = bcd2bin(day); - alm->time.tm_wday = bcd2bin(wday); - alm->time.tm_mon = bcd2bin(month) - 1; - /* hw counts from year 2000, but tm_year is relative to 1900 */ - alm->time.tm_year = bcd2bin(year) + 100; - - if (rtc_valid_tm(&alm->time) < 0) { - dev_err(dev, "retrieved alarm date/time is not valid.\n"); - rtc_time_to_tm(0, &alm->time); - } - - alm->enabled = !!readl(ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); - return 0; -} - -static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) -{ - struct rtc_plat_data *pdata = dev_get_drvdata(dev); - void __iomem *ioaddr = pdata->ioaddr; - u32 rtc_reg = 0; - - if (alm->time.tm_sec >= 0) - rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_sec)) - << RTC_SECONDS_OFFS; - if (alm->time.tm_min >= 0) - rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_min)) - << RTC_MINUTES_OFFS; - if (alm->time.tm_hour >= 0) - rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_hour)) - << RTC_HOURS_OFFS; - - writel(rtc_reg, ioaddr + RTC_ALARM_TIME_REG_OFFS); - - if (alm->time.tm_mday >= 0) - rtc_reg = (RTC_ALARM_VALID | bin2bcd(alm->time.tm_mday)) - << RTC_MDAY_OFFS; - else - rtc_reg = 0; - - if (alm->time.tm_mon >= 0) - rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_mon + 1)) - << RTC_MONTH_OFFS; - - if (alm->time.tm_year >= 0) - rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_year % 100)) - << RTC_YEAR_OFFS; - - writel(rtc_reg, ioaddr + RTC_ALARM_DATE_REG_OFFS); - writel(0, ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS); - writel(alm->enabled ? 1 : 0, - ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); - - return 0; -} - -static int mv_rtc_ioctl(struct device *dev, unsigned int cmd, - unsigned long arg) -{ - struct platform_device *pdev = to_platform_device(dev); - struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - void __iomem *ioaddr = pdata->ioaddr; - - if (pdata->irq < 0) - return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ - switch (cmd) { - case RTC_AIE_OFF: - writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); - break; - case RTC_AIE_ON: - writel(1, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); - break; - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static irqreturn_t mv_rtc_interrupt(int irq, void *data) -{ - struct rtc_plat_data *pdata = data; - void __iomem *ioaddr = pdata->ioaddr; - - /* alarm irq? */ - if (!readl(ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS)) - return IRQ_NONE; - - /* clear interrupt */ - writel(0, ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS); - rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF); - return IRQ_HANDLED; -} - static const struct rtc_class_ops mv_rtc_ops = { .read_time = mv_rtc_read_time, .set_time = mv_rtc_set_time, }; -static const struct rtc_class_ops mv_rtc_alarm_ops = { - .read_time = mv_rtc_read_time, - .set_time = mv_rtc_set_time, - .read_alarm = mv_rtc_read_alarm, - .set_alarm = mv_rtc_set_alarm, - .ioctl = mv_rtc_ioctl, -}; - -static int __devinit mv_rtc_probe(struct platform_device *pdev) +static int __init mv_rtc_probe(struct platform_device *pdev) { struct resource *res; struct rtc_plat_data *pdata; @@ -259,31 +130,12 @@ static int __devinit mv_rtc_probe(struct platform_device *pdev) } } - pdata->irq = platform_get_irq(pdev, 0); - platform_set_drvdata(pdev, pdata); - - if (pdata->irq >= 0) { - device_init_wakeup(&pdev->dev, 1); - pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, - &mv_rtc_alarm_ops, - THIS_MODULE); - } else - pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, - &mv_rtc_ops, THIS_MODULE); + pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, + &mv_rtc_ops, THIS_MODULE); if (IS_ERR(pdata->rtc)) return PTR_ERR(pdata->rtc); - if (pdata->irq >= 0) { - writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); - if (devm_request_irq(&pdev->dev, pdata->irq, mv_rtc_interrupt, - IRQF_DISABLED | IRQF_SHARED, - pdev->name, pdata) < 0) { - dev_warn(&pdev->dev, "interrupt not available.\n"); - pdata->irq = -1; - } - } - return 0; } @@ -291,9 +143,6 @@ static int __exit mv_rtc_remove(struct platform_device *pdev) { struct rtc_plat_data *pdata = platform_get_drvdata(pdev); - if (pdata->irq >= 0) - device_init_wakeup(&pdev->dev, 0); - rtc_device_unregister(pdata->rtc); return 0; } diff --git a/trunk/drivers/rtc/rtc-nuc900.c b/trunk/drivers/rtc/rtc-nuc900.c deleted file mode 100644 index bf59c9c586b2..000000000000 --- a/trunk/drivers/rtc/rtc-nuc900.c +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (c) 2008-2009 Nuvoton technology corporation. - * - * Wan ZongShun - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation;version 2 of the License. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -/* RTC Control Registers */ -#define REG_RTC_INIR 0x00 -#define REG_RTC_AER 0x04 -#define REG_RTC_FCR 0x08 -#define REG_RTC_TLR 0x0C -#define REG_RTC_CLR 0x10 -#define REG_RTC_TSSR 0x14 -#define REG_RTC_DWR 0x18 -#define REG_RTC_TAR 0x1C -#define REG_RTC_CAR 0x20 -#define REG_RTC_LIR 0x24 -#define REG_RTC_RIER 0x28 -#define REG_RTC_RIIR 0x2C -#define REG_RTC_TTR 0x30 - -#define RTCSET 0x01 -#define AERRWENB 0x10000 -#define INIRRESET 0xa5eb1357 -#define AERPOWERON 0xA965 -#define AERPOWEROFF 0x0000 -#define LEAPYEAR 0x0001 -#define TICKENB 0x80 -#define TICKINTENB 0x0002 -#define ALARMINTENB 0x0001 -#define MODE24 0x0001 - -struct nuc900_rtc { - int irq_num; - void __iomem *rtc_reg; - struct rtc_device *rtcdev; -}; - -struct nuc900_bcd_time { - int bcd_sec; - int bcd_min; - int bcd_hour; - int bcd_mday; - int bcd_mon; - int bcd_year; -}; - -static irqreturn_t nuc900_rtc_interrupt(int irq, void *_rtc) -{ - struct nuc900_rtc *rtc = _rtc; - unsigned long events = 0, rtc_irq; - - rtc_irq = __raw_readl(rtc->rtc_reg + REG_RTC_RIIR); - - if (rtc_irq & ALARMINTENB) { - rtc_irq &= ~ALARMINTENB; - __raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR); - events |= RTC_AF | RTC_IRQF; - } - - if (rtc_irq & TICKINTENB) { - rtc_irq &= ~TICKINTENB; - __raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR); - events |= RTC_UF | RTC_IRQF; - } - - rtc_update_irq(rtc->rtcdev, 1, events); - - return IRQ_HANDLED; -} - -static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc) -{ - unsigned int i; - __raw_writel(INIRRESET, nuc900_rtc->rtc_reg + REG_RTC_INIR); - - mdelay(10); - - __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER); - - for (i = 0; i < 1000; i++) { - if (__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) - return 0; - } - - if ((__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) == 0x0) - return ERR_PTR(-ENODEV); - - return ERR_PTR(-EPERM); -} - -static void nuc900_rtc_bcd2bin(unsigned int timereg, - unsigned int calreg, struct rtc_time *tm) -{ - tm->tm_mday = bcd2bin(calreg >> 0); - tm->tm_mon = bcd2bin(calreg >> 8); - tm->tm_year = bcd2bin(calreg >> 16) + 100; - - tm->tm_sec = bcd2bin(timereg >> 0); - tm->tm_min = bcd2bin(timereg >> 8); - tm->tm_hour = bcd2bin(timereg >> 16); - - rtc_valid_tm(tm); -} - -static void nuc900_rtc_bin2bcd(struct rtc_time *settm, - struct nuc900_bcd_time *gettm) -{ - gettm->bcd_mday = bin2bcd(settm->tm_mday) << 0; - gettm->bcd_mon = bin2bcd(settm->tm_mon) << 8; - gettm->bcd_year = bin2bcd(settm->tm_year - 100) << 16; - - gettm->bcd_sec = bin2bcd(settm->tm_sec) << 0; - gettm->bcd_min = bin2bcd(settm->tm_min) << 8; - gettm->bcd_hour = bin2bcd(settm->tm_hour) << 16; -} - -static int nuc900_update_irq_enable(struct device *dev, unsigned int enabled) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - - if (enabled) - __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)| - (TICKINTENB), rtc->rtc_reg + REG_RTC_RIER); - else - __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)& - (~TICKINTENB), rtc->rtc_reg + REG_RTC_RIER); - - return 0; -} - -static int nuc900_alarm_irq_enable(struct device *dev, unsigned int enabled) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - - if (enabled) - __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)| - (ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER); - else - __raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)& - (~ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER); - - return 0; -} - -static int nuc900_rtc_read_time(struct device *dev, struct rtc_time *tm) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - unsigned int timeval, clrval; - - timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TLR); - clrval = __raw_readl(rtc->rtc_reg + REG_RTC_CLR); - - nuc900_rtc_bcd2bin(timeval, clrval, tm); - - return 0; -} - -static int nuc900_rtc_set_time(struct device *dev, struct rtc_time *tm) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - struct nuc900_bcd_time gettm; - unsigned long val; - int *err; - - nuc900_rtc_bin2bcd(tm, &gettm); - - err = check_rtc_access_enable(rtc); - if (IS_ERR(err)) - return PTR_ERR(err); - - val = gettm.bcd_mday | gettm.bcd_mon | gettm.bcd_year; - __raw_writel(val, rtc->rtc_reg + REG_RTC_CLR); - - val = gettm.bcd_sec | gettm.bcd_min | gettm.bcd_hour; - __raw_writel(val, rtc->rtc_reg + REG_RTC_TLR); - - return 0; -} - -static int nuc900_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - unsigned int timeval, carval; - - timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TAR); - carval = __raw_readl(rtc->rtc_reg + REG_RTC_CAR); - - nuc900_rtc_bcd2bin(timeval, carval, &alrm->time); - - return 0; -} - -static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) -{ - struct nuc900_rtc *rtc = dev_get_drvdata(dev); - struct nuc900_bcd_time tm; - unsigned long val; - int *err; - - nuc900_rtc_bin2bcd(&alrm->time, &tm); - - err = check_rtc_access_enable(rtc); - if (IS_ERR(err)) - return PTR_ERR(err); - - val = tm.bcd_mday | tm.bcd_mon | tm.bcd_year; - __raw_writel(val, rtc->rtc_reg + REG_RTC_CAR); - - val = tm.bcd_sec | tm.bcd_min | tm.bcd_hour; - __raw_writel(val, rtc->rtc_reg + REG_RTC_TAR); - - return 0; -} - -static struct rtc_class_ops nuc900_rtc_ops = { - .read_time = nuc900_rtc_read_time, - .set_time = nuc900_rtc_set_time, - .read_alarm = nuc900_rtc_read_alarm, - .set_alarm = nuc900_rtc_set_alarm, - .alarm_irq_enable = nuc900_alarm_irq_enable, - .update_irq_enable = nuc900_update_irq_enable, -}; - -static int __devinit nuc900_rtc_probe(struct platform_device *pdev) -{ - struct resource *res; - struct nuc900_rtc *nuc900_rtc; - int err = 0; - - nuc900_rtc = kzalloc(sizeof(struct nuc900_rtc), GFP_KERNEL); - if (!nuc900_rtc) { - dev_err(&pdev->dev, "kzalloc nuc900_rtc failed\n"); - return -ENOMEM; - } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "platform_get_resource failed\n"); - err = -ENXIO; - goto fail1; - } - - if (!request_mem_region(res->start, resource_size(res), - pdev->name)) { - dev_err(&pdev->dev, "request_mem_region failed\n"); - err = -EBUSY; - goto fail1; - } - - nuc900_rtc->rtc_reg = ioremap(res->start, resource_size(res)); - if (!nuc900_rtc->rtc_reg) { - dev_err(&pdev->dev, "ioremap rtc_reg failed\n"); - err = -ENOMEM; - goto fail2; - } - - nuc900_rtc->irq_num = platform_get_irq(pdev, 0); - if (request_irq(nuc900_rtc->irq_num, nuc900_rtc_interrupt, - IRQF_DISABLED, "nuc900rtc", nuc900_rtc)) { - dev_err(&pdev->dev, "NUC900 RTC request irq failed\n"); - err = -EBUSY; - goto fail3; - } - - nuc900_rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev, - &nuc900_rtc_ops, THIS_MODULE); - if (IS_ERR(nuc900_rtc->rtcdev)) { - dev_err(&pdev->dev, "rtc device register faild\n"); - err = PTR_ERR(nuc900_rtc->rtcdev); - goto fail4; - } - - platform_set_drvdata(pdev, nuc900_rtc); - __raw_writel(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_TSSR) | MODE24, - nuc900_rtc->rtc_reg + REG_RTC_TSSR); - - return 0; - -fail4: free_irq(nuc900_rtc->irq_num, nuc900_rtc); -fail3: iounmap(nuc900_rtc->rtc_reg); -fail2: release_mem_region(res->start, resource_size(res)); -fail1: kfree(nuc900_rtc); - return err; -} - -static int __devexit nuc900_rtc_remove(struct platform_device *pdev) -{ - struct nuc900_rtc *nuc900_rtc = platform_get_drvdata(pdev); - struct resource *res; - - rtc_device_unregister(nuc900_rtc->rtcdev); - free_irq(nuc900_rtc->irq_num, nuc900_rtc); - iounmap(nuc900_rtc->rtc_reg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - kfree(nuc900_rtc); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver nuc900_rtc_driver = { - .remove = __devexit_p(nuc900_rtc_remove), - .driver = { - .name = "nuc900-rtc", - .owner = THIS_MODULE, - }, -}; - -static int __init nuc900_rtc_init(void) -{ - return platform_driver_probe(&nuc900_rtc_driver, nuc900_rtc_probe); -} - -static void __exit nuc900_rtc_exit(void) -{ - platform_driver_unregister(&nuc900_rtc_driver); -} - -module_init(nuc900_rtc_init); -module_exit(nuc900_rtc_exit); - -MODULE_AUTHOR("Wan ZongShun "); -MODULE_DESCRIPTION("nuc910/nuc920 RTC driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:nuc900-rtc"); diff --git a/trunk/drivers/rtc/rtc-omap.c b/trunk/drivers/rtc/rtc-omap.c index 64d9727b7229..0587d53987fe 100644 --- a/trunk/drivers/rtc/rtc-omap.c +++ b/trunk/drivers/rtc/rtc-omap.c @@ -87,10 +87,9 @@ #define OMAP_RTC_INTERRUPTS_IT_ALARM (1<<3) #define OMAP_RTC_INTERRUPTS_IT_TIMER (1<<2) -static void __iomem *rtc_base; -#define rtc_read(addr) __raw_readb(rtc_base + (addr)) -#define rtc_write(val, addr) __raw_writeb(val, rtc_base + (addr)) +#define rtc_read(addr) omap_readb(OMAP_RTC_BASE + (addr)) +#define rtc_write(val, addr) omap_writeb(val, OMAP_RTC_BASE + (addr)) /* we rely on the rtc framework to handle locking (rtc->ops_lock), @@ -331,31 +330,32 @@ static int __init omap_rtc_probe(struct platform_device *pdev) return -ENOENT; } + /* NOTE: using static mapping for RTC registers */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - pr_debug("%s: RTC resource data missing\n", pdev->name); + if (res && res->start != OMAP_RTC_BASE) { + pr_debug("%s: RTC registers at %08x, expected %08x\n", + pdev->name, (unsigned) res->start, OMAP_RTC_BASE); return -ENOENT; } - mem = request_mem_region(res->start, resource_size(res), pdev->name); + if (res) + mem = request_mem_region(res->start, + res->end - res->start + 1, + pdev->name); + else + mem = NULL; if (!mem) { pr_debug("%s: RTC registers at %08x are not free\n", - pdev->name, res->start); + pdev->name, OMAP_RTC_BASE); return -EBUSY; } - rtc_base = ioremap(res->start, resource_size(res)); - if (!rtc_base) { - pr_debug("%s: RTC registers can't be mapped\n", pdev->name); - goto fail; - } - rtc = rtc_device_register(pdev->name, &pdev->dev, &omap_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { pr_debug("%s: can't register RTC device, err %ld\n", pdev->name, PTR_ERR(rtc)); - goto fail0; + goto fail; } platform_set_drvdata(pdev, rtc); dev_set_drvdata(&rtc->dev, mem); @@ -380,14 +380,13 @@ static int __init omap_rtc_probe(struct platform_device *pdev) dev_name(&rtc->dev), rtc)) { pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n", pdev->name, omap_rtc_timer); - goto fail1; + goto fail0; } - if ((omap_rtc_timer != omap_rtc_alarm) && - (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, - dev_name(&rtc->dev), rtc))) { + if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, + dev_name(&rtc->dev), rtc)) { pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n", pdev->name, omap_rtc_alarm); - goto fail2; + goto fail1; } /* On boards with split power, RTC_ON_NOFF won't reset the RTC */ @@ -420,12 +419,10 @@ static int __init omap_rtc_probe(struct platform_device *pdev) return 0; -fail2: - free_irq(omap_rtc_timer, NULL); fail1: - rtc_device_unregister(rtc); + free_irq(omap_rtc_timer, NULL); fail0: - iounmap(rtc_base); + rtc_device_unregister(rtc); fail: release_resource(mem); return -EIO; @@ -441,9 +438,7 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) rtc_write(0, OMAP_RTC_INTERRUPTS_REG); free_irq(omap_rtc_timer, rtc); - - if (omap_rtc_timer != omap_rtc_alarm) - free_irq(omap_rtc_alarm, rtc); + free_irq(omap_rtc_alarm, rtc); release_resource(dev_get_drvdata(&rtc->dev)); rtc_device_unregister(rtc); diff --git a/trunk/drivers/rtc/rtc-pcf50633.c b/trunk/drivers/rtc/rtc-pcf50633.c index 854c3cb365a1..9b74e9c9151c 100644 --- a/trunk/drivers/rtc/rtc-pcf50633.c +++ b/trunk/drivers/rtc/rtc-pcf50633.c @@ -58,7 +58,6 @@ struct pcf50633_time { struct pcf50633_rtc { int alarm_enabled; int second_enabled; - int alarm_pending; struct pcf50633 *pcf; struct rtc_device *rtc_dev; @@ -210,7 +209,6 @@ static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) rtc = dev_get_drvdata(dev); alrm->enabled = rtc->alarm_enabled; - alrm->pending = rtc->alarm_pending; ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA, PCF50633_TI_EXTENT, &pcf_tm.time[0]); @@ -246,8 +244,6 @@ static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) /* Returns 0 on success */ ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA, PCF50633_TI_EXTENT, &pcf_tm.time[0]); - if (!alrm->enabled) - rtc->alarm_pending = 0; if (!alarm_masked || alrm->enabled) pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); @@ -272,7 +268,6 @@ static void pcf50633_rtc_irq(int irq, void *data) switch (irq) { case PCF50633_IRQ_ALARM: rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); - rtc->alarm_pending = 1; break; case PCF50633_IRQ_SECOND: rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); diff --git a/trunk/drivers/rtc/rtc-pcf8563.c b/trunk/drivers/rtc/rtc-pcf8563.c index 65f346b2fbae..b725913ccbe8 100644 --- a/trunk/drivers/rtc/rtc-pcf8563.c +++ b/trunk/drivers/rtc/rtc-pcf8563.c @@ -212,8 +212,6 @@ static int pcf8563_probe(struct i2c_client *client, dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - i2c_set_clientdata(client, pcf8563); - pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev, &pcf8563_rtc_ops, THIS_MODULE); @@ -222,6 +220,8 @@ static int pcf8563_probe(struct i2c_client *client, goto exit_kfree; } + i2c_set_clientdata(client, pcf8563); + return 0; exit_kfree: diff --git a/trunk/drivers/rtc/rtc-pcf8583.c b/trunk/drivers/rtc/rtc-pcf8583.c index 2d201afead3b..7d33cda3f8f6 100644 --- a/trunk/drivers/rtc/rtc-pcf8583.c +++ b/trunk/drivers/rtc/rtc-pcf8583.c @@ -277,8 +277,6 @@ static int pcf8583_probe(struct i2c_client *client, if (!pcf8583) return -ENOMEM; - i2c_set_clientdata(client, pcf8583); - pcf8583->rtc = rtc_device_register(pcf8583_driver.driver.name, &client->dev, &pcf8583_rtc_ops, THIS_MODULE); @@ -287,6 +285,7 @@ static int pcf8583_probe(struct i2c_client *client, goto exit_kfree; } + i2c_set_clientdata(client, pcf8583); return 0; exit_kfree: diff --git a/trunk/drivers/rtc/rtc-pl031.c b/trunk/drivers/rtc/rtc-pl031.c index 0264b117893b..f41873f98f66 100644 --- a/trunk/drivers/rtc/rtc-pl031.c +++ b/trunk/drivers/rtc/rtc-pl031.c @@ -51,10 +51,10 @@ static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) switch (cmd) { case RTC_AIE_OFF: - writel(1, ldata->base + RTC_MIS); + __raw_writel(1, ldata->base + RTC_MIS); return 0; case RTC_AIE_ON: - writel(0, ldata->base + RTC_MIS); + __raw_writel(0, ldata->base + RTC_MIS); return 0; } @@ -65,7 +65,7 @@ static int pl031_read_time(struct device *dev, struct rtc_time *tm) { struct pl031_local *ldata = dev_get_drvdata(dev); - rtc_time_to_tm(readl(ldata->base + RTC_DR), tm); + rtc_time_to_tm(__raw_readl(ldata->base + RTC_DR), tm); return 0; } @@ -76,7 +76,7 @@ static int pl031_set_time(struct device *dev, struct rtc_time *tm) struct pl031_local *ldata = dev_get_drvdata(dev); rtc_tm_to_time(tm, &time); - writel(time, ldata->base + RTC_LR); + __raw_writel(time, ldata->base + RTC_LR); return 0; } @@ -85,9 +85,9 @@ static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct pl031_local *ldata = dev_get_drvdata(dev); - rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time); - alarm->pending = readl(ldata->base + RTC_RIS); - alarm->enabled = readl(ldata->base + RTC_IMSC); + rtc_time_to_tm(__raw_readl(ldata->base + RTC_MR), &alarm->time); + alarm->pending = __raw_readl(ldata->base + RTC_RIS); + alarm->enabled = __raw_readl(ldata->base + RTC_IMSC); return 0; } @@ -99,8 +99,8 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) rtc_tm_to_time(&alarm->time, &time); - writel(time, ldata->base + RTC_MR); - writel(!alarm->enabled, ldata->base + RTC_MIS); + __raw_writel(time, ldata->base + RTC_MR); + __raw_writel(!alarm->enabled, ldata->base + RTC_MIS); return 0; } @@ -180,9 +180,8 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id) static struct amba_id pl031_ids[] __initdata = { { - .id = 0x00041031, - .mask = 0x000fffff, - }, + .id = 0x00041031, + .mask = 0x000fffff, }, {0, 0}, }; diff --git a/trunk/drivers/rtc/rtc-stk17ta8.c b/trunk/drivers/rtc/rtc-stk17ta8.c index 67700831b5c9..d491eb265c38 100644 --- a/trunk/drivers/rtc/rtc-stk17ta8.c +++ b/trunk/drivers/rtc/rtc-stk17ta8.c @@ -62,6 +62,7 @@ struct rtc_plat_data { struct rtc_device *rtc; void __iomem *ioaddr; + unsigned long baseaddr; unsigned long last_jiffies; int irq; unsigned int irqen; @@ -69,7 +70,6 @@ struct rtc_plat_data { int alrm_min; int alrm_hour; int alrm_mday; - spinlock_t lock; }; static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -142,7 +142,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) unsigned long irqflags; u8 flags; - spin_lock_irqsave(&pdata->lock, irqflags); + spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags); flags = readb(ioaddr + RTC_FLAGS); writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); @@ -162,7 +162,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata) writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS); readb(ioaddr + RTC_FLAGS); /* clear interrupts */ writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); - spin_unlock_irqrestore(&pdata->lock, irqflags); + spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags); } static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -202,53 +202,56 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id) struct platform_device *pdev = dev_id; struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; - unsigned long events = 0; + unsigned long events = RTC_IRQF; - spin_lock(&pdata->lock); /* read and clear interrupt */ - if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) { - events = RTC_IRQF; - if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) - events |= RTC_UF; - else - events |= RTC_AF; - if (likely(pdata->rtc)) - rtc_update_irq(pdata->rtc, 1, events); - } - spin_unlock(&pdata->lock); - return events ? IRQ_HANDLED : IRQ_NONE; + if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) + return IRQ_NONE; + if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) + events |= RTC_UF; + else + events |= RTC_AF; + rtc_update_irq(pdata->rtc, 1, events); + return IRQ_HANDLED; } -static int stk17ta8_rtc_alarm_irq_enable(struct device *dev, - unsigned int enabled) +static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) { struct platform_device *pdev = to_platform_device(dev); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); if (pdata->irq <= 0) - return -EINVAL; - if (enabled) - pdata->irqen |= RTC_AF; - else + return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ + switch (cmd) { + case RTC_AIE_OFF: pdata->irqen &= ~RTC_AF; - stk17ta8_rtc_update_alarm(pdata); + stk17ta8_rtc_update_alarm(pdata); + break; + case RTC_AIE_ON: + pdata->irqen |= RTC_AF; + stk17ta8_rtc_update_alarm(pdata); + break; + default: + return -ENOIOCTLCMD; + } return 0; } static const struct rtc_class_ops stk17ta8_rtc_ops = { - .read_time = stk17ta8_rtc_read_time, - .set_time = stk17ta8_rtc_set_time, - .read_alarm = stk17ta8_rtc_read_alarm, - .set_alarm = stk17ta8_rtc_set_alarm, - .alarm_irq_enable = stk17ta8_rtc_alarm_irq_enable, + .read_time = stk17ta8_rtc_read_time, + .set_time = stk17ta8_rtc_set_time, + .read_alarm = stk17ta8_rtc_read_alarm, + .set_alarm = stk17ta8_rtc_set_alarm, + .ioctl = stk17ta8_rtc_ioctl, }; static ssize_t stk17ta8_nvram_read(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t size) { - struct device *dev = container_of(kobj, struct device, kobj); - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *pdev = + to_platform_device(container_of(kobj, struct device, kobj)); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; ssize_t count; @@ -262,8 +265,8 @@ static ssize_t stk17ta8_nvram_write(struct kobject *kobj, struct bin_attribute *attr, char *buf, loff_t pos, size_t size) { - struct device *dev = container_of(kobj, struct device, kobj); - struct platform_device *pdev = to_platform_device(dev); + struct platform_device *pdev = + to_platform_device(container_of(kobj, struct device, kobj)); struct rtc_plat_data *pdata = platform_get_drvdata(pdev); void __iomem *ioaddr = pdata->ioaddr; ssize_t count; @@ -285,26 +288,31 @@ static struct bin_attribute stk17ta8_nvram_attr = { static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) { + struct rtc_device *rtc; struct resource *res; unsigned int cal; unsigned int flags; struct rtc_plat_data *pdata; - void __iomem *ioaddr; + void __iomem *ioaddr = NULL; int ret = 0; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -ENODEV; - pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; - if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, - pdev->name)) - return -EBUSY; - ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); - if (!ioaddr) - return -ENOMEM; + if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { + ret = -EBUSY; + goto out; + } + pdata->baseaddr = res->start; + ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); + if (!ioaddr) { + ret = -ENOMEM; + goto out; + } pdata->ioaddr = ioaddr; pdata->irq = platform_get_irq(pdev, 0); @@ -320,13 +328,9 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF) dev_warn(&pdev->dev, "voltage-low detected.\n"); - spin_lock_init(&pdata->lock); - pdata->last_jiffies = jiffies; - platform_set_drvdata(pdev, pdata); if (pdata->irq > 0) { writeb(0, ioaddr + RTC_INTERRUPTS); - if (devm_request_irq(&pdev->dev, pdata->irq, - stk17ta8_rtc_interrupt, + if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { dev_warn(&pdev->dev, "interrupt not available.\n"); @@ -334,14 +338,29 @@ static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev) } } - pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, + rtc = rtc_device_register(pdev->name, &pdev->dev, &stk17ta8_rtc_ops, THIS_MODULE); - if (IS_ERR(pdata->rtc)) - return PTR_ERR(pdata->rtc); - + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } + pdata->rtc = rtc; + pdata->last_jiffies = jiffies; + platform_set_drvdata(pdev, pdata); ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); if (ret) + goto out; + return 0; + out: + if (pdata->rtc) rtc_device_unregister(pdata->rtc); + if (pdata->irq > 0) + free_irq(pdata->irq, pdev); + if (ioaddr) + iounmap(ioaddr); + if (pdata->baseaddr) + release_mem_region(pdata->baseaddr, RTC_REG_SIZE); + kfree(pdata); return ret; } @@ -351,8 +370,13 @@ static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev) sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr); rtc_device_unregister(pdata->rtc); - if (pdata->irq > 0) + if (pdata->irq > 0) { writeb(0, pdata->ioaddr + RTC_INTERRUPTS); + free_irq(pdata->irq, pdev); + } + iounmap(pdata->ioaddr); + release_mem_region(pdata->baseaddr, RTC_REG_SIZE); + kfree(pdata); return 0; } diff --git a/trunk/drivers/rtc/rtc-tx4939.c b/trunk/drivers/rtc/rtc-tx4939.c index 9ee81d8aa7c0..4a6ed1104fbb 100644 --- a/trunk/drivers/rtc/rtc-tx4939.c +++ b/trunk/drivers/rtc/rtc-tx4939.c @@ -17,7 +17,6 @@ struct tx4939rtc_plat_data { struct rtc_device *rtc; struct tx4939_rtc_reg __iomem *rtcreg; - spinlock_t lock; }; static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev) @@ -53,14 +52,14 @@ static int tx4939_rtc_set_mmss(struct device *dev, unsigned long secs) buf[3] = secs >> 8; buf[4] = secs >> 16; buf[5] = secs >> 24; - spin_lock_irq(&pdata->lock); + spin_lock_irq(&pdata->rtc->irq_lock); __raw_writel(0, &rtcreg->adr); for (i = 0; i < 6; i++) __raw_writel(buf[i], &rtcreg->dat); ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETTIME | (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&pdata->rtc->irq_lock); return ret; } @@ -72,18 +71,18 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm) unsigned long sec; unsigned char buf[6]; - spin_lock_irq(&pdata->lock); + spin_lock_irq(&pdata->rtc->irq_lock); ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_GETTIME | (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); if (ret) { - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&pdata->rtc->irq_lock); return ret; } __raw_writel(2, &rtcreg->adr); for (i = 2; i < 6; i++) buf[i] = __raw_readl(&rtcreg->dat); - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&pdata->rtc->irq_lock); sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; rtc_time_to_tm(sec, tm); return rtc_valid_tm(tm); @@ -111,13 +110,13 @@ static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) buf[3] = sec >> 8; buf[4] = sec >> 16; buf[5] = sec >> 24; - spin_lock_irq(&pdata->lock); + spin_lock_irq(&pdata->rtc->irq_lock); __raw_writel(0, &rtcreg->adr); for (i = 0; i < 6; i++) __raw_writel(buf[i], &rtcreg->dat); ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETALARM | (alrm->enabled ? TX4939_RTCCTL_ALME : 0)); - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&pdata->rtc->irq_lock); return ret; } @@ -130,12 +129,12 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) unsigned char buf[6]; u32 ctl; - spin_lock_irq(&pdata->lock); + spin_lock_irq(&pdata->rtc->irq_lock); ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_GETALARM | (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); if (ret) { - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&pdata->rtc->irq_lock); return ret; } __raw_writel(2, &rtcreg->adr); @@ -144,7 +143,7 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) ctl = __raw_readl(&rtcreg->ctl); alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0; alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&pdata->rtc->irq_lock); sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2]; rtc_time_to_tm(sec, &alrm->time); return rtc_valid_tm(&alrm->time); @@ -154,11 +153,11 @@ static int tx4939_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); - spin_lock_irq(&pdata->lock); + spin_lock_irq(&pdata->rtc->irq_lock); tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP | (enabled ? TX4939_RTCCTL_ALME : 0)); - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&pdata->rtc->irq_lock); return 0; } @@ -168,14 +167,13 @@ static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id) struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; unsigned long events = RTC_IRQF; - spin_lock(&pdata->lock); + spin_lock(&pdata->rtc->irq_lock); if (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALMD) { events |= RTC_AF; tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP); } - spin_unlock(&pdata->lock); - if (likely(pdata->rtc)) - rtc_update_irq(pdata->rtc, 1, events); + spin_unlock(&pdata->rtc->irq_lock); + rtc_update_irq(pdata->rtc, 1, events); return IRQ_HANDLED; } @@ -196,13 +194,13 @@ static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj, struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; ssize_t count; - spin_lock_irq(&pdata->lock); + spin_lock_irq(&pdata->rtc->irq_lock); for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; count++, size--) { __raw_writel(pos++, &rtcreg->adr); *buf++ = __raw_readl(&rtcreg->dat); } - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&pdata->rtc->irq_lock); return count; } @@ -215,13 +213,13 @@ static ssize_t tx4939_rtc_nvram_write(struct kobject *kobj, struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg; ssize_t count; - spin_lock_irq(&pdata->lock); + spin_lock_irq(&pdata->rtc->irq_lock); for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; count++, size--) { __raw_writel(pos++, &rtcreg->adr); __raw_writel(*buf++, &rtcreg->dat); } - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&pdata->rtc->irq_lock); return count; } @@ -261,7 +259,6 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev) if (!pdata->rtcreg) return -EBUSY; - spin_lock_init(&pdata->lock); tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt, IRQF_DISABLED, pdev->name, &pdev->dev) < 0) @@ -280,12 +277,14 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev) static int __exit tx4939_rtc_remove(struct platform_device *pdev) { struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev); + struct rtc_device *rtc = pdata->rtc; - sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); - rtc_device_unregister(pdata->rtc); - spin_lock_irq(&pdata->lock); + spin_lock_irq(&rtc->irq_lock); tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); - spin_unlock_irq(&pdata->lock); + spin_unlock_irq(&rtc->irq_lock); + sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); + rtc_device_unregister(rtc); + platform_set_drvdata(pdev, NULL); return 0; } diff --git a/trunk/drivers/rtc/rtc-v3020.c b/trunk/drivers/rtc/rtc-v3020.c index bed4cab07043..ad741afd47d8 100644 --- a/trunk/drivers/rtc/rtc-v3020.c +++ b/trunk/drivers/rtc/rtc-v3020.c @@ -304,6 +304,7 @@ static int rtc_probe(struct platform_device *pdev) { struct v3020_platform_data *pdata = pdev->dev.platform_data; struct v3020 *chip; + struct rtc_device *rtc; int retval = -EBUSY; int i; int temp; @@ -352,12 +353,13 @@ static int rtc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, chip); - chip->rtc = rtc_device_register("v3020", + rtc = rtc_device_register("v3020", &pdev->dev, &v3020_rtc_ops, THIS_MODULE); - if (IS_ERR(chip->rtc)) { - retval = PTR_ERR(chip->rtc); + if (IS_ERR(rtc)) { + retval = PTR_ERR(rtc); goto err_io; } + chip->rtc = rtc; return 0; diff --git a/trunk/drivers/rtc/rtc-vr41xx.c b/trunk/drivers/rtc/rtc-vr41xx.c index c3244244e8cf..fadddac1e5a4 100644 --- a/trunk/drivers/rtc/rtc-vr41xx.c +++ b/trunk/drivers/rtc/rtc-vr41xx.c @@ -327,7 +327,7 @@ static int __devinit rtc_probe(struct platform_device *pdev) if (!res) return -EBUSY; - rtc1_base = ioremap(res->start, resource_size(res)); + rtc1_base = ioremap(res->start, res->end - res->start + 1); if (!rtc1_base) return -EBUSY; @@ -337,7 +337,7 @@ static int __devinit rtc_probe(struct platform_device *pdev) goto err_rtc1_iounmap; } - rtc2_base = ioremap(res->start, resource_size(res)); + rtc2_base = ioremap(res->start, res->end - res->start + 1); if (!rtc2_base) { retval = -EBUSY; goto err_rtc1_iounmap; diff --git a/trunk/drivers/rtc/rtc-wm8350.c b/trunk/drivers/rtc/rtc-wm8350.c index f1e440521c54..f16486635a8e 100644 --- a/trunk/drivers/rtc/rtc-wm8350.c +++ b/trunk/drivers/rtc/rtc-wm8350.c @@ -354,9 +354,8 @@ static const struct rtc_class_ops wm8350_rtc_ops = { }; #ifdef CONFIG_PM -static int wm8350_rtc_suspend(struct device *dev) +static int wm8350_rtc_suspend(struct platform_device *pdev, pm_message_t state) { - struct platform_device *pdev = to_platform_device(dev); struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); int ret = 0; u16 reg; @@ -374,9 +373,8 @@ static int wm8350_rtc_suspend(struct device *dev) return ret; } -static int wm8350_rtc_resume(struct device *dev) +static int wm8350_rtc_resume(struct platform_device *pdev) { - struct platform_device *pdev = to_platform_device(dev); struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev); int ret; @@ -486,17 +484,13 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev) return 0; } -static struct dev_pm_ops wm8350_rtc_pm_ops = { - .suspend = wm8350_rtc_suspend, - .resume = wm8350_rtc_resume, -}; - static struct platform_driver wm8350_rtc_driver = { .probe = wm8350_rtc_probe, .remove = __devexit_p(wm8350_rtc_remove), + .suspend = wm8350_rtc_suspend, + .resume = wm8350_rtc_resume, .driver = { .name = "wm8350-rtc", - .pm = &wm8350_rtc_pm_ops, }, }; diff --git a/trunk/drivers/rtc/rtc-x1205.c b/trunk/drivers/rtc/rtc-x1205.c index 9aae49139a0a..6583c1a8b070 100644 --- a/trunk/drivers/rtc/rtc-x1205.c +++ b/trunk/drivers/rtc/rtc-x1205.c @@ -155,11 +155,11 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr) } static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, - u8 reg_base, unsigned char alm_enable) + int datetoo, u8 reg_base, unsigned char alm_enable) { - int i, xfer; + int i, xfer, nbytes; + unsigned char buf[8]; unsigned char rdata[10] = { 0, reg_base }; - unsigned char *buf = rdata + 2; static const unsigned char wel[3] = { 0, X1205_REG_SR, X1205_SR_WEL }; @@ -170,9 +170,9 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 }; dev_dbg(&client->dev, - "%s: sec=%d min=%d hour=%d mday=%d mon=%d year=%d wday=%d\n", - __func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, - tm->tm_mon, tm->tm_year, tm->tm_wday); + "%s: secs=%d, mins=%d, hours=%d\n", + __func__, + tm->tm_sec, tm->tm_min, tm->tm_hour); buf[CCR_SEC] = bin2bcd(tm->tm_sec); buf[CCR_MIN] = bin2bcd(tm->tm_min); @@ -180,15 +180,23 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, /* set hour and 24hr bit */ buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | X1205_HR_MIL; - buf[CCR_MDAY] = bin2bcd(tm->tm_mday); + /* should we also set the date? */ + if (datetoo) { + dev_dbg(&client->dev, + "%s: mday=%d, mon=%d, year=%d, wday=%d\n", + __func__, + tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - /* month, 1 - 12 */ - buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1); + buf[CCR_MDAY] = bin2bcd(tm->tm_mday); - /* year, since the rtc epoch*/ - buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100); - buf[CCR_WDAY] = tm->tm_wday & 0x07; - buf[CCR_Y2K] = bin2bcd((tm->tm_year + 1900) / 100); + /* month, 1 - 12 */ + buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1); + + /* year, since the rtc epoch*/ + buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100); + buf[CCR_WDAY] = tm->tm_wday & 0x07; + buf[CCR_Y2K] = bin2bcd((tm->tm_year + 1900) / 100); + } /* If writing alarm registers, set compare bits on registers 0-4 */ if (reg_base < X1205_CCR_BASE) @@ -206,8 +214,17 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, return -EIO; } - xfer = i2c_master_send(client, rdata, sizeof(rdata)); - if (xfer != sizeof(rdata)) { + + /* write register's data */ + if (datetoo) + nbytes = 8; + else + nbytes = 3; + for (i = 0; i < nbytes; i++) + rdata[2+i] = buf[i]; + + xfer = i2c_master_send(client, rdata, nbytes+2); + if (xfer != nbytes+2) { dev_err(&client->dev, "%s: result=%d addr=%02x, data=%02x\n", __func__, @@ -265,7 +282,7 @@ static int x1205_fix_osc(struct i2c_client *client) memset(&tm, 0, sizeof(tm)); - err = x1205_set_datetime(client, &tm, X1205_CCR_BASE, 0); + err = x1205_set_datetime(client, &tm, 1, X1205_CCR_BASE, 0); if (err < 0) dev_err(&client->dev, "unable to restart the oscillator\n"); @@ -464,7 +481,7 @@ static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { return x1205_set_datetime(to_i2c_client(dev), - &alrm->time, X1205_ALM0_BASE, alrm->enabled); + &alrm->time, 1, X1205_ALM0_BASE, alrm->enabled); } static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -476,7 +493,7 @@ static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm) { return x1205_set_datetime(to_i2c_client(dev), - tm, X1205_CCR_BASE, 0); + tm, 1, X1205_CCR_BASE, 0); } static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) diff --git a/trunk/drivers/usb/host/isp1362-hcd.c b/trunk/drivers/usb/host/isp1362-hcd.c index 73352f3739b5..5c774ab98252 100644 --- a/trunk/drivers/usb/host/isp1362-hcd.c +++ b/trunk/drivers/usb/host/isp1362-hcd.c @@ -80,7 +80,7 @@ #include #include #include -#include +#include #include #include @@ -190,8 +190,10 @@ static int claim_ptd_buffers(struct isp1362_ep_queue *epq, struct isp1362_ep *ep, u16 len) { int ptd_offset = -EINVAL; + int index; int num_ptds = ((len + PTD_HEADER_SIZE - 1) / epq->blk_size) + 1; - int found; + int found = -1; + int last = -1; BUG_ON(len > epq->buf_size); @@ -203,9 +205,20 @@ static int claim_ptd_buffers(struct isp1362_ep_queue *epq, epq->name, len, epq->blk_size, num_ptds, epq->buf_map, epq->skip_map); BUG_ON(ep->num_ptds != 0); - found = bitmap_find_next_zero_area(&epq->buf_map, epq->buf_count, 0, - num_ptds, 0); - if (found >= epq->buf_count) + for (index = 0; index <= epq->buf_count - num_ptds; index++) { + if (test_bit(index, &epq->buf_map)) + continue; + found = index; + for (last = index + 1; last < index + num_ptds; last++) { + if (test_bit(last, &epq->buf_map)) { + found = -1; + break; + } + } + if (found >= 0) + break; + } + if (found < 0) return -EOVERFLOW; DBG(1, "%s: Found %d PTDs[%d] for %d/%d byte\n", __func__, @@ -217,7 +230,8 @@ static int claim_ptd_buffers(struct isp1362_ep_queue *epq, epq->buf_avail -= num_ptds; BUG_ON(epq->buf_avail > epq->buf_count); ep->ptd_index = found; - bitmap_set(&epq->buf_map, found, num_ptds); + for (index = found; index < last; index++) + __set_bit(index, &epq->buf_map); DBG(1, "%s: Done %s PTD[%d] $%04x, avail %d count %d claimed %d %08lx:%08lx\n", __func__, epq->name, ep->ptd_index, ep->ptd_offset, epq->buf_avail, epq->buf_count, num_ptds, epq->buf_map, epq->skip_map); diff --git a/trunk/drivers/video/Kconfig b/trunk/drivers/video/Kconfig index 5a5c303a6373..99c0df1c7ebf 100644 --- a/trunk/drivers/video/Kconfig +++ b/trunk/drivers/video/Kconfig @@ -614,21 +614,6 @@ config FB_BFIN_T350MCQB This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. -config FB_BFIN_LQ035Q1 - tristate "SHARP LQ035Q1DH02 TFT LCD" - depends on FB && BLACKFIN && SPI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BFIN_GPTIMERS - help - This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on - the Blackfin Landscape LCD EZ-Extender Card. - This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI - It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK. - - To compile this driver as a module, choose M here: the - module will be called bfin-lq035q1-fb. config FB_STI tristate "HP STI frame buffer device support" diff --git a/trunk/drivers/video/Makefile b/trunk/drivers/video/Makefile index 4ecb30c4f3f2..0f8da331ba0f 100644 --- a/trunk/drivers/video/Makefile +++ b/trunk/drivers/video/Makefile @@ -137,7 +137,6 @@ obj-$(CONFIG_FB_EFI) += efifb.o obj-$(CONFIG_FB_VGA16) += vga16fb.o obj-$(CONFIG_FB_OF) += offb.o obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o -obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o obj-$(CONFIG_FB_MX3) += mx3fb.o obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o diff --git a/trunk/drivers/video/atafb.c b/trunk/drivers/video/atafb.c index 2051c9dc813b..b7687c55fe16 100644 --- a/trunk/drivers/video/atafb.c +++ b/trunk/drivers/video/atafb.c @@ -2245,9 +2245,6 @@ static int ext_setcolreg(unsigned int regno, unsigned int red, if (regno > 255) return 1; - if (regno > 255) - return 1; - switch (external_card_type) { case IS_VGA: OUTB(0x3c8, regno); diff --git a/trunk/drivers/video/bfin-lq035q1-fb.c b/trunk/drivers/video/bfin-lq035q1-fb.c deleted file mode 100644 index b690c269784a..000000000000 --- a/trunk/drivers/video/bfin-lq035q1-fb.c +++ /dev/null @@ -1,826 +0,0 @@ -/* - * Blackfin LCD Framebuffer driver SHARP LQ035Q1DH02 - * - * Copyright 2008-2009 Analog Devices Inc. - * Licensed under the GPL-2 or later. - */ - -#define DRIVER_NAME "bfin-lq035q1" -#define pr_fmt(fmt) DRIVER_NAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#if defined(BF533_FAMILY) || defined(BF538_FAMILY) -#define TIMER_HSYNC_id TIMER1_id -#define TIMER_HSYNCbit TIMER1bit -#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 -#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 -#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 - -#define TIMER_VSYNC_id TIMER2_id -#define TIMER_VSYNCbit TIMER2bit -#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN2 -#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL2 -#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF2 -#else -#define TIMER_HSYNC_id TIMER0_id -#define TIMER_HSYNCbit TIMER0bit -#define TIMER_HSYNC_STATUS_TRUN TIMER_STATUS_TRUN0 -#define TIMER_HSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL0 -#define TIMER_HSYNC_STATUS_TOVF TIMER_STATUS_TOVF0 - -#define TIMER_VSYNC_id TIMER1_id -#define TIMER_VSYNCbit TIMER1bit -#define TIMER_VSYNC_STATUS_TRUN TIMER_STATUS_TRUN1 -#define TIMER_VSYNC_STATUS_TIMIL TIMER_STATUS_TIMIL1 -#define TIMER_VSYNC_STATUS_TOVF TIMER_STATUS_TOVF1 -#endif - -#define LCD_X_RES 320 /* Horizontal Resolution */ -#define LCD_Y_RES 240 /* Vertical Resolution */ -#define DMA_BUS_SIZE 16 - -#define USE_RGB565_16_BIT_PPI - -#ifdef USE_RGB565_16_BIT_PPI -#define LCD_BPP 16 /* Bit Per Pixel */ -#define CLOCKS_PER_PIX 1 -#define CPLD_PIPELINE_DELAY_COR 0 /* NO CPLB */ -#endif - -/* Interface 16/18-bit TFT over an 8-bit wide PPI using a small Programmable Logic Device (CPLD) - * http://blackfin.uclinux.org/gf/project/stamp/frs/?action=FrsReleaseBrowse&frs_package_id=165 - */ - -#ifdef USE_RGB565_8_BIT_PPI -#define LCD_BPP 16 /* Bit Per Pixel */ -#define CLOCKS_PER_PIX 2 -#define CPLD_PIPELINE_DELAY_COR 3 /* RGB565 */ -#endif - -#ifdef USE_RGB888_8_BIT_PPI -#define LCD_BPP 24 /* Bit Per Pixel */ -#define CLOCKS_PER_PIX 3 -#define CPLD_PIPELINE_DELAY_COR 5 /* RGB888 */ -#endif - - /* - * HS and VS timing parameters (all in number of PPI clk ticks) - */ - -#define U_LINE 4 /* Blanking Lines */ - -#define H_ACTPIX (LCD_X_RES * CLOCKS_PER_PIX) /* active horizontal pixel */ -#define H_PERIOD (336 * CLOCKS_PER_PIX) /* HS period */ -#define H_PULSE (2 * CLOCKS_PER_PIX) /* HS pulse width */ -#define H_START (7 * CLOCKS_PER_PIX + CPLD_PIPELINE_DELAY_COR) /* first valid pixel */ - -#define V_LINES (LCD_Y_RES + U_LINE) /* total vertical lines */ -#define V_PULSE (2 * CLOCKS_PER_PIX) /* VS pulse width (1-5 H_PERIODs) */ -#define V_PERIOD (H_PERIOD * V_LINES) /* VS period */ - -#define ACTIVE_VIDEO_MEM_OFFSET ((U_LINE / 2) * LCD_X_RES * (LCD_BPP / 8)) - -#define BFIN_LCD_NBR_PALETTE_ENTRIES 256 - -#define PPI_TX_MODE 0x2 -#define PPI_XFER_TYPE_11 0xC -#define PPI_PORT_CFG_01 0x10 -#define PPI_POLS_1 0x8000 - -#if (CLOCKS_PER_PIX > 1) -#define PPI_PMODE (DLEN_8 | PACK_EN) -#else -#define PPI_PMODE (DLEN_16) -#endif - -#define LQ035_INDEX 0x74 -#define LQ035_DATA 0x76 - -#define LQ035_DRIVER_OUTPUT_CTL 0x1 -#define LQ035_SHUT_CTL 0x11 - -#define LQ035_DRIVER_OUTPUT_MASK (LQ035_LR | LQ035_TB | LQ035_BGR | LQ035_REV) -#define LQ035_DRIVER_OUTPUT_DEFAULT (0x2AEF & ~LQ035_DRIVER_OUTPUT_MASK) - -#define LQ035_SHUT (1 << 0) /* Shutdown */ -#define LQ035_ON (0 << 0) /* Shutdown */ - -struct bfin_lq035q1fb_info { - struct fb_info *fb; - struct device *dev; - struct spi_driver spidrv; - struct bfin_lq035q1fb_disp_info *disp_info; - unsigned char *fb_buffer; /* RGB Buffer */ - dma_addr_t dma_handle; - int lq035_open_cnt; - int irq; - spinlock_t lock; /* lock */ - u32 pseudo_pal[16]; -}; - -static int nocursor; -module_param(nocursor, int, 0644); -MODULE_PARM_DESC(nocursor, "cursor enable/disable"); - -struct spi_control { - unsigned short mode; -}; - -static int lq035q1_control(struct spi_device *spi, unsigned char reg, unsigned short value) -{ - int ret; - u8 regs[3] = { LQ035_INDEX, 0, 0 }; - u8 dat[3] = { LQ035_DATA, 0, 0 }; - - if (!spi) - return -ENODEV; - - regs[2] = reg; - dat[1] = value >> 8; - dat[2] = value & 0xFF; - - ret = spi_write(spi, regs, ARRAY_SIZE(regs)); - ret |= spi_write(spi, dat, ARRAY_SIZE(dat)); - return ret; -} - -static int __devinit lq035q1_spidev_probe(struct spi_device *spi) -{ - int ret; - struct spi_control *ctl; - struct bfin_lq035q1fb_info *info = container_of(spi->dev.driver, - struct bfin_lq035q1fb_info, - spidrv.driver); - - ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); - - if (!ctl) - return -ENOMEM; - - ctl->mode = (info->disp_info->mode & - LQ035_DRIVER_OUTPUT_MASK) | LQ035_DRIVER_OUTPUT_DEFAULT; - - ret = lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); - ret |= lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); - if (ret) - return ret; - - spi_set_drvdata(spi, ctl); - - return 0; -} - -static int lq035q1_spidev_remove(struct spi_device *spi) -{ - return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); -} - -#ifdef CONFIG_PM -static int lq035q1_spidev_suspend(struct spi_device *spi, pm_message_t state) -{ - return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); -} - -static int lq035q1_spidev_resume(struct spi_device *spi) -{ - int ret; - struct spi_control *ctl = spi_get_drvdata(spi); - - ret = lq035q1_control(spi, LQ035_DRIVER_OUTPUT_CTL, ctl->mode); - if (ret) - return ret; - - return lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_ON); -} -#else -# define lq035q1_spidev_suspend NULL -# define lq035q1_spidev_resume NULL -#endif - -/* Power down all displays on reboot, poweroff or halt */ -static void lq035q1_spidev_shutdown(struct spi_device *spi) -{ - lq035q1_control(spi, LQ035_SHUT_CTL, LQ035_SHUT); -} - -static int lq035q1_backlight(struct bfin_lq035q1fb_info *info, unsigned arg) -{ - if (info->disp_info->use_bl) - gpio_set_value(info->disp_info->gpio_bl, arg); - - return 0; -} - -static void bfin_lq035q1_config_ppi(struct bfin_lq035q1fb_info *fbi) -{ - bfin_write_PPI_DELAY(H_START); - bfin_write_PPI_COUNT(H_ACTPIX - 1); - bfin_write_PPI_FRAME(V_LINES); - - bfin_write_PPI_CONTROL(PPI_TX_MODE | /* output mode , PORT_DIR */ - PPI_XFER_TYPE_11 | /* sync mode XFR_TYPE */ - PPI_PORT_CFG_01 | /* two frame sync PORT_CFG */ - PPI_PMODE | /* 8/16 bit data length / PACK_EN? */ - PPI_POLS_1); /* faling edge syncs POLS */ -} - -static inline void bfin_lq035q1_disable_ppi(void) -{ - bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() & ~PORT_EN); -} - -static inline void bfin_lq035q1_enable_ppi(void) -{ - bfin_write_PPI_CONTROL(bfin_read_PPI_CONTROL() | PORT_EN); -} - -static void bfin_lq035q1_start_timers(void) -{ - enable_gptimers(TIMER_VSYNCbit | TIMER_HSYNCbit); -} - -static void bfin_lq035q1_stop_timers(void) -{ - disable_gptimers(TIMER_HSYNCbit | TIMER_VSYNCbit); - - set_gptimer_status(0, TIMER_HSYNC_STATUS_TRUN | TIMER_VSYNC_STATUS_TRUN | - TIMER_HSYNC_STATUS_TIMIL | TIMER_VSYNC_STATUS_TIMIL | - TIMER_HSYNC_STATUS_TOVF | TIMER_VSYNC_STATUS_TOVF); - -} - -static void bfin_lq035q1_init_timers(void) -{ - - bfin_lq035q1_stop_timers(); - - set_gptimer_period(TIMER_HSYNC_id, H_PERIOD); - set_gptimer_pwidth(TIMER_HSYNC_id, H_PULSE); - set_gptimer_config(TIMER_HSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | - TIMER_TIN_SEL | TIMER_CLK_SEL| - TIMER_EMU_RUN); - - set_gptimer_period(TIMER_VSYNC_id, V_PERIOD); - set_gptimer_pwidth(TIMER_VSYNC_id, V_PULSE); - set_gptimer_config(TIMER_VSYNC_id, TIMER_MODE_PWM | TIMER_PERIOD_CNT | - TIMER_TIN_SEL | TIMER_CLK_SEL | - TIMER_EMU_RUN); - -} - -static void bfin_lq035q1_config_dma(struct bfin_lq035q1fb_info *fbi) -{ - - set_dma_config(CH_PPI, - set_bfin_dma_config(DIR_READ, DMA_FLOW_AUTO, - INTR_DISABLE, DIMENSION_2D, - DATA_SIZE_16, - DMA_NOSYNC_KEEP_DMA_BUF)); - set_dma_x_count(CH_PPI, (LCD_X_RES * LCD_BPP) / DMA_BUS_SIZE); - set_dma_x_modify(CH_PPI, DMA_BUS_SIZE / 8); - set_dma_y_count(CH_PPI, V_LINES); - - set_dma_y_modify(CH_PPI, DMA_BUS_SIZE / 8); - set_dma_start_addr(CH_PPI, (unsigned long)fbi->fb_buffer); - -} - -#if (CLOCKS_PER_PIX == 1) -static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, - P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, - P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, - P_PPI0_D6, P_PPI0_D7, P_PPI0_D8, - P_PPI0_D9, P_PPI0_D10, P_PPI0_D11, - P_PPI0_D12, P_PPI0_D13, P_PPI0_D14, - P_PPI0_D15, 0}; -#else -static const u16 ppi0_req_16[] = {P_PPI0_CLK, P_PPI0_FS1, P_PPI0_FS2, - P_PPI0_D0, P_PPI0_D1, P_PPI0_D2, - P_PPI0_D3, P_PPI0_D4, P_PPI0_D5, - P_PPI0_D6, P_PPI0_D7, 0}; -#endif - -static inline void bfin_lq035q1_free_ports(void) -{ - peripheral_free_list(ppi0_req_16); - if (ANOMALY_05000400) - gpio_free(P_IDENT(P_PPI0_FS3)); -} - -static int __devinit bfin_lq035q1_request_ports(struct platform_device *pdev) -{ - /* ANOMALY_05000400 - PPI Does Not Start Properly In Specific Mode: - * Drive PPI_FS3 Low - */ - if (ANOMALY_05000400) { - int ret = gpio_request(P_IDENT(P_PPI0_FS3), "PPI_FS3"); - if (ret) - return ret; - gpio_direction_output(P_IDENT(P_PPI0_FS3), 0); - } - - if (peripheral_request_list(ppi0_req_16, DRIVER_NAME)) { - dev_err(&pdev->dev, "requesting peripherals failed\n"); - return -EFAULT; - } - - return 0; -} - -static int bfin_lq035q1_fb_open(struct fb_info *info, int user) -{ - struct bfin_lq035q1fb_info *fbi = info->par; - - spin_lock(&fbi->lock); - fbi->lq035_open_cnt++; - - if (fbi->lq035_open_cnt <= 1) { - - bfin_lq035q1_disable_ppi(); - SSYNC(); - - bfin_lq035q1_config_dma(fbi); - bfin_lq035q1_config_ppi(fbi); - bfin_lq035q1_init_timers(); - - /* start dma */ - enable_dma(CH_PPI); - bfin_lq035q1_enable_ppi(); - bfin_lq035q1_start_timers(); - lq035q1_backlight(fbi, 1); - } - - spin_unlock(&fbi->lock); - - return 0; -} - -static int bfin_lq035q1_fb_release(struct fb_info *info, int user) -{ - struct bfin_lq035q1fb_info *fbi = info->par; - - spin_lock(&fbi->lock); - - fbi->lq035_open_cnt--; - - if (fbi->lq035_open_cnt <= 0) { - lq035q1_backlight(fbi, 0); - bfin_lq035q1_disable_ppi(); - SSYNC(); - disable_dma(CH_PPI); - bfin_lq035q1_stop_timers(); - } - - spin_unlock(&fbi->lock); - - return 0; -} - -static int bfin_lq035q1_fb_check_var(struct fb_var_screeninfo *var, - struct fb_info *info) -{ - switch (var->bits_per_pixel) { -#if (LCD_BPP == 24) - case 24:/* TRUECOLOUR, 16m */ -#else - case 16:/* DIRECTCOLOUR, 64k */ -#endif - var->red.offset = info->var.red.offset; - var->green.offset = info->var.green.offset; - var->blue.offset = info->var.blue.offset; - var->red.length = info->var.red.length; - var->green.length = info->var.green.length; - var->blue.length = info->var.blue.length; - var->transp.offset = 0; - var->transp.length = 0; - var->transp.msb_right = 0; - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - break; - default: - pr_debug("%s: depth not supported: %u BPP\n", __func__, - var->bits_per_pixel); - return -EINVAL; - } - - if (info->var.xres != var->xres || info->var.yres != var->yres || - info->var.xres_virtual != var->xres_virtual || - info->var.yres_virtual != var->yres_virtual) { - pr_debug("%s: Resolution not supported: X%u x Y%u \n", - __func__, var->xres, var->yres); - return -EINVAL; - } - - /* - * Memory limit - */ - - if ((info->fix.line_length * var->yres_virtual) > info->fix.smem_len) { - pr_debug("%s: Memory Limit requested yres_virtual = %u\n", - __func__, var->yres_virtual); - return -ENOMEM; - } - - - return 0; -} - -int bfin_lq035q1_fb_cursor(struct fb_info *info, struct fb_cursor *cursor) -{ - if (nocursor) - return 0; - else - return -EINVAL; /* just to force soft_cursor() call */ -} - -static int bfin_lq035q1_fb_setcolreg(u_int regno, u_int red, u_int green, - u_int blue, u_int transp, - struct fb_info *info) -{ - if (regno >= BFIN_LCD_NBR_PALETTE_ENTRIES) - return -EINVAL; - - if (info->var.grayscale) { - /* grayscale = 0.30*R + 0.59*G + 0.11*B */ - red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8; - } - - if (info->fix.visual == FB_VISUAL_TRUECOLOR) { - - u32 value; - /* Place color in the pseudopalette */ - if (regno > 16) - return -EINVAL; - - red >>= (16 - info->var.red.length); - green >>= (16 - info->var.green.length); - blue >>= (16 - info->var.blue.length); - - value = (red << info->var.red.offset) | - (green << info->var.green.offset) | - (blue << info->var.blue.offset); - value &= 0xFFFFFF; - - ((u32 *) (info->pseudo_palette))[regno] = value; - - } - - return 0; -} - -static struct fb_ops bfin_lq035q1_fb_ops = { - .owner = THIS_MODULE, - .fb_open = bfin_lq035q1_fb_open, - .fb_release = bfin_lq035q1_fb_release, - .fb_check_var = bfin_lq035q1_fb_check_var, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_cursor = bfin_lq035q1_fb_cursor, - .fb_setcolreg = bfin_lq035q1_fb_setcolreg, -}; - -static irqreturn_t bfin_lq035q1_irq_error(int irq, void *dev_id) -{ - /*struct bfin_lq035q1fb_info *info = (struct bfin_lq035q1fb_info *)dev_id;*/ - - u16 status = bfin_read_PPI_STATUS(); - bfin_write_PPI_STATUS(-1); - - if (status) { - bfin_lq035q1_disable_ppi(); - disable_dma(CH_PPI); - - /* start dma */ - enable_dma(CH_PPI); - bfin_lq035q1_enable_ppi(); - bfin_write_PPI_STATUS(-1); - } - - return IRQ_HANDLED; -} - -static int __devinit bfin_lq035q1_probe(struct platform_device *pdev) -{ - struct bfin_lq035q1fb_info *info; - struct fb_info *fbinfo; - int ret; - - ret = request_dma(CH_PPI, DRIVER_NAME"_CH_PPI"); - if (ret < 0) { - dev_err(&pdev->dev, "PPI DMA unavailable\n"); - goto out1; - } - - fbinfo = framebuffer_alloc(sizeof(*info), &pdev->dev); - if (!fbinfo) { - ret = -ENOMEM; - goto out2; - } - - info = fbinfo->par; - info->fb = fbinfo; - info->dev = &pdev->dev; - - info->disp_info = pdev->dev.platform_data; - - platform_set_drvdata(pdev, fbinfo); - - strcpy(fbinfo->fix.id, DRIVER_NAME); - - fbinfo->fix.type = FB_TYPE_PACKED_PIXELS; - fbinfo->fix.type_aux = 0; - fbinfo->fix.xpanstep = 0; - fbinfo->fix.ypanstep = 0; - fbinfo->fix.ywrapstep = 0; - fbinfo->fix.accel = FB_ACCEL_NONE; - fbinfo->fix.visual = FB_VISUAL_TRUECOLOR; - - fbinfo->var.nonstd = 0; - fbinfo->var.activate = FB_ACTIVATE_NOW; - fbinfo->var.height = -1; - fbinfo->var.width = -1; - fbinfo->var.accel_flags = 0; - fbinfo->var.vmode = FB_VMODE_NONINTERLACED; - - fbinfo->var.xres = LCD_X_RES; - fbinfo->var.xres_virtual = LCD_X_RES; - fbinfo->var.yres = LCD_Y_RES; - fbinfo->var.yres_virtual = LCD_Y_RES; - fbinfo->var.bits_per_pixel = LCD_BPP; - - if (info->disp_info->mode & LQ035_BGR) { -#if (LCD_BPP == 24) - fbinfo->var.red.offset = 0; - fbinfo->var.green.offset = 8; - fbinfo->var.blue.offset = 16; -#else - fbinfo->var.red.offset = 0; - fbinfo->var.green.offset = 5; - fbinfo->var.blue.offset = 11; -#endif - } else { -#if (LCD_BPP == 24) - fbinfo->var.red.offset = 16; - fbinfo->var.green.offset = 8; - fbinfo->var.blue.offset = 0; -#else - fbinfo->var.red.offset = 11; - fbinfo->var.green.offset = 5; - fbinfo->var.blue.offset = 0; -#endif - } - - fbinfo->var.transp.offset = 0; - -#if (LCD_BPP == 24) - fbinfo->var.red.length = 8; - fbinfo->var.green.length = 8; - fbinfo->var.blue.length = 8; -#else - fbinfo->var.red.length = 5; - fbinfo->var.green.length = 6; - fbinfo->var.blue.length = 5; -#endif - - fbinfo->var.transp.length = 0; - - fbinfo->fix.smem_len = LCD_X_RES * LCD_Y_RES * LCD_BPP / 8 - + ACTIVE_VIDEO_MEM_OFFSET; - - fbinfo->fix.line_length = fbinfo->var.xres_virtual * - fbinfo->var.bits_per_pixel / 8; - - - fbinfo->fbops = &bfin_lq035q1_fb_ops; - fbinfo->flags = FBINFO_FLAG_DEFAULT; - - info->fb_buffer = - dma_alloc_coherent(NULL, fbinfo->fix.smem_len, &info->dma_handle, - GFP_KERNEL); - - if (NULL == info->fb_buffer) { - dev_err(&pdev->dev, "couldn't allocate dma buffer\n"); - ret = -ENOMEM; - goto out3; - } - - fbinfo->screen_base = (void *)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; - fbinfo->fix.smem_start = (int)info->fb_buffer + ACTIVE_VIDEO_MEM_OFFSET; - - fbinfo->fbops = &bfin_lq035q1_fb_ops; - - fbinfo->pseudo_palette = &info->pseudo_pal; - - ret = fb_alloc_cmap(&fbinfo->cmap, BFIN_LCD_NBR_PALETTE_ENTRIES, 0); - if (ret < 0) { - dev_err(&pdev->dev, "failed to allocate colormap (%d entries)\n", - BFIN_LCD_NBR_PALETTE_ENTRIES); - goto out4; - } - - ret = bfin_lq035q1_request_ports(pdev); - if (ret) { - dev_err(&pdev->dev, "couldn't request gpio port\n"); - goto out6; - } - - info->irq = platform_get_irq(pdev, 0); - if (info->irq < 0) { - ret = -EINVAL; - goto out7; - } - - ret = request_irq(info->irq, bfin_lq035q1_irq_error, IRQF_DISABLED, - DRIVER_NAME" PPI ERROR", info); - if (ret < 0) { - dev_err(&pdev->dev, "unable to request PPI ERROR IRQ\n"); - goto out7; - } - - info->spidrv.driver.name = DRIVER_NAME"-spi"; - info->spidrv.probe = lq035q1_spidev_probe; - info->spidrv.remove = __devexit_p(lq035q1_spidev_remove); - info->spidrv.shutdown = lq035q1_spidev_shutdown; - info->spidrv.suspend = lq035q1_spidev_suspend; - info->spidrv.resume = lq035q1_spidev_resume; - - ret = spi_register_driver(&info->spidrv); - if (ret < 0) { - dev_err(&pdev->dev, "couldn't register SPI Interface\n"); - goto out8; - } - - if (info->disp_info->use_bl) { - ret = gpio_request(info->disp_info->gpio_bl, "LQ035 Backlight"); - - if (ret) { - dev_err(&pdev->dev, "failed to request GPIO %d\n", - info->disp_info->gpio_bl); - goto out9; - } - gpio_direction_output(info->disp_info->gpio_bl, 0); - } - - ret = register_framebuffer(fbinfo); - if (ret < 0) { - dev_err(&pdev->dev, "unable to register framebuffer\n"); - goto out10; - } - - dev_info(&pdev->dev, "%dx%d %d-bit RGB FrameBuffer initialized\n", - LCD_X_RES, LCD_Y_RES, LCD_BPP); - - return 0; - - out10: - if (info->disp_info->use_bl) - gpio_free(info->disp_info->gpio_bl); - out9: - spi_unregister_driver(&info->spidrv); - out8: - free_irq(info->irq, info); - out7: - bfin_lq035q1_free_ports(); - out6: - fb_dealloc_cmap(&fbinfo->cmap); - out4: - dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, - info->dma_handle); - out3: - framebuffer_release(fbinfo); - out2: - free_dma(CH_PPI); - out1: - platform_set_drvdata(pdev, NULL); - - return ret; -} - -static int __devexit bfin_lq035q1_remove(struct platform_device *pdev) -{ - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct bfin_lq035q1fb_info *info = fbinfo->par; - - if (info->disp_info->use_bl) - gpio_free(info->disp_info->gpio_bl); - - spi_unregister_driver(&info->spidrv); - - unregister_framebuffer(fbinfo); - - free_dma(CH_PPI); - free_irq(info->irq, info); - - if (info->fb_buffer != NULL) - dma_free_coherent(NULL, fbinfo->fix.smem_len, info->fb_buffer, - info->dma_handle); - - fb_dealloc_cmap(&fbinfo->cmap); - - bfin_lq035q1_free_ports(); - - platform_set_drvdata(pdev, NULL); - framebuffer_release(fbinfo); - - dev_info(&pdev->dev, "unregistered LCD driver\n"); - - return 0; -} - -#ifdef CONFIG_PM -static int bfin_lq035q1_suspend(struct device *dev) -{ - struct fb_info *fbinfo = dev_get_drvdata(dev); - struct bfin_lq035q1fb_info *info = fbinfo->par; - - if (info->lq035_open_cnt) { - lq035q1_backlight(info, 0); - bfin_lq035q1_disable_ppi(); - SSYNC(); - disable_dma(CH_PPI); - bfin_lq035q1_stop_timers(); - bfin_write_PPI_STATUS(-1); - } - - return 0; -} - -static int bfin_lq035q1_resume(struct device *dev) -{ - struct fb_info *fbinfo = dev_get_drvdata(dev); - struct bfin_lq035q1fb_info *info = fbinfo->par; - - if (info->lq035_open_cnt) { - bfin_lq035q1_disable_ppi(); - SSYNC(); - - bfin_lq035q1_config_dma(info); - bfin_lq035q1_config_ppi(info); - bfin_lq035q1_init_timers(); - - /* start dma */ - enable_dma(CH_PPI); - bfin_lq035q1_enable_ppi(); - bfin_lq035q1_start_timers(); - lq035q1_backlight(info, 1); - } - - return 0; -} - -static struct dev_pm_ops bfin_lq035q1_dev_pm_ops = { - .suspend = bfin_lq035q1_suspend, - .resume = bfin_lq035q1_resume, -}; -#endif - -static struct platform_driver bfin_lq035q1_driver = { - .probe = bfin_lq035q1_probe, - .remove = __devexit_p(bfin_lq035q1_remove), - .driver = { - .name = DRIVER_NAME, -#ifdef CONFIG_PM - .pm = &bfin_lq035q1_dev_pm_ops, -#endif - }, -}; - -static int __init bfin_lq035q1_driver_init(void) -{ - return platform_driver_register(&bfin_lq035q1_driver); -} -module_init(bfin_lq035q1_driver_init); - -static void __exit bfin_lq035q1_driver_cleanup(void) -{ - platform_driver_unregister(&bfin_lq035q1_driver); -} -module_exit(bfin_lq035q1_driver_cleanup); - -MODULE_DESCRIPTION("Blackfin TFT LCD Driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/video/bfin-t350mcqb-fb.c b/trunk/drivers/video/bfin-t350mcqb-fb.c index 2549c53b26a0..5cc36cfbf07b 100644 --- a/trunk/drivers/video/bfin-t350mcqb-fb.c +++ b/trunk/drivers/video/bfin-t350mcqb-fb.c @@ -487,8 +487,8 @@ static int __devinit bfin_t350mcqb_probe(struct platform_device *pdev) fbinfo->var.nonstd = 0; fbinfo->var.activate = FB_ACTIVATE_NOW; - fbinfo->var.height = 53; - fbinfo->var.width = 70; + fbinfo->var.height = -1; + fbinfo->var.width = -1; fbinfo->var.accel_flags = 0; fbinfo->var.vmode = FB_VMODE_NONINTERLACED; @@ -634,35 +634,17 @@ static int __devexit bfin_t350mcqb_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int bfin_t350mcqb_suspend(struct platform_device *pdev, pm_message_t state) { - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct bfin_t350mcqbfb_info *fbi = fbinfo->par; - - if (fbi->lq043_open_cnt) { - bfin_t350mcqb_disable_ppi(); - disable_dma(CH_PPI); - bfin_t350mcqb_stop_timers(); - bfin_write_PPI_STATUS(-1); - } - + bfin_t350mcqb_disable_ppi(); + disable_dma(CH_PPI); + bfin_write_PPI_STATUS(0xFFFF); return 0; } static int bfin_t350mcqb_resume(struct platform_device *pdev) { - struct fb_info *fbinfo = platform_get_drvdata(pdev); - struct bfin_t350mcqbfb_info *fbi = fbinfo->par; - - if (fbi->lq043_open_cnt) { - bfin_t350mcqb_config_dma(fbi); - bfin_t350mcqb_config_ppi(fbi); - bfin_t350mcqb_init_timers(); - - /* start dma */ - enable_dma(CH_PPI); - bfin_t350mcqb_enable_ppi(); - bfin_t350mcqb_start_timers(); - } + enable_dma(CH_PPI); + bfin_t350mcqb_enable_ppi(); return 0; } diff --git a/trunk/drivers/video/clps711xfb.c b/trunk/drivers/video/clps711xfb.c index 99b354b8e257..16f5db471ab5 100644 --- a/trunk/drivers/video/clps711xfb.c +++ b/trunk/drivers/video/clps711xfb.c @@ -19,10 +19,8 @@ * * Framebuffer driver for the CLPS7111 and EP7212 processors. */ -#include #include #include -#include #include #include #include @@ -40,6 +38,14 @@ struct fb_info *cfb; #define CMAP_MAX_SIZE 16 +/* The /proc entry for the backlight. */ +static struct proc_dir_entry *clps7111fb_backlight_proc_entry = NULL; + +static int clps7111fb_proc_backlight_read(char *page, char **start, off_t off, + int count, int *eof, void *data); +static int clps7111fb_proc_backlight_write(struct file *file, + const char *buffer, unsigned long count, void *data); + /* * LCD AC Prescale. This comes from the LCD panel manufacturers specifications. * This determines how many clocks + 1 of CL1 before the M signal toggles. @@ -215,23 +221,26 @@ static struct fb_ops clps7111fb_ops = { .fb_imageblit = cfb_imageblit, }; -static int backlight_proc_show(struct seq_file *m, void *v) +static int +clps7111fb_proc_backlight_read(char *page, char **start, off_t off, + int count, int *eof, void *data) { + /* We need at least two characters, one for the digit, and one for + * the terminating NULL. */ + if (count < 2) + return -EINVAL; + if (machine_is_edb7211()) { - seq_printf(m, "%d\n", + return sprintf(page, "%d\n", (clps_readb(PDDR) & EDB_PD3_LCDBL) ? 1 : 0); } return 0; } -static int backlight_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, backlight_proc_show, NULL); -} - -static ssize_t backlight_proc_write(struct file *file, const char *buffer, - size_t count, loff_t *pos) +static int +clps7111fb_proc_backlight_write(struct file *file, const char *buffer, + unsigned long count, void *data) { unsigned char char_value; int value; @@ -262,15 +271,6 @@ static ssize_t backlight_proc_write(struct file *file, const char *buffer, return count; } -static const struct file_operations backlight_proc_fops = { - .owner = THIS_MODULE, - .open = backlight_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = backlight_proc_write, -}; - static void __init clps711x_guess_lcd_params(struct fb_info *info) { unsigned int lcdcon, syscon, size; @@ -379,11 +379,19 @@ int __init clps711xfb_init(void) fb_alloc_cmap(&cfb->cmap, CMAP_MAX_SIZE, 0); - if (!proc_create("backlight", 0444, NULL, &backlight_proc_fops)) { + /* Register the /proc entries. */ + clps7111fb_backlight_proc_entry = create_proc_entry("backlight", 0444, + NULL); + if (clps7111fb_backlight_proc_entry == NULL) { printk("Couldn't create the /proc entry for the backlight.\n"); return -EINVAL; } + clps7111fb_backlight_proc_entry->read_proc = + &clps7111fb_proc_backlight_read; + clps7111fb_backlight_proc_entry->write_proc = + &clps7111fb_proc_backlight_write; + /* * Power up the LCD */ diff --git a/trunk/drivers/video/da8xx-fb.c b/trunk/drivers/video/da8xx-fb.c index 369a5b3ac649..ea1fd3f47511 100644 --- a/trunk/drivers/video/da8xx-fb.c +++ b/trunk/drivers/video/da8xx-fb.c @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include